]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
move fr_skip* to their own C file and header
authorAlan T. DeKok <aland@freeradius.org>
Thu, 15 May 2025 13:42:45 +0000 (09:42 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 15 May 2025 15:29:18 +0000 (11:29 -0400)
as they are (and will be) used in many places

21 files changed:
src/bin/unit_test_attribute.c
src/lib/server/cf_file.c
src/lib/server/command.c
src/lib/server/util.c
src/lib/tls/session.c
src/lib/util/libfreeradius-util.mk
src/lib/util/misc.h
src/lib/util/pair_tokenize.c
src/lib/util/skip.c [new file with mode: 0644]
src/lib/util/skip.h [new file with mode: 0644]
src/lib/util/time.c
src/lib/util/token.c
src/lib/util/token.h
src/lib/util/trie.c
src/listen/control/radmin.c
src/listen/cron/proto_cron_crontab.c
src/modules/rlm_isc_dhcp/rlm_isc_dhcp.c
src/modules/rlm_rest/rest.c
src/modules/rlm_sql/rlm_sql.c
src/modules/rlm_unix/rlm_unix.c
src/modules/rlm_winbind/rlm_winbind.c

index d3493bff53f35d10ec60c5722408223df9f14b0a..067f7640c64d086d9fa16ced4a0ddf2f11f8e11c 100644 (file)
@@ -50,7 +50,7 @@ typedef struct request_s request_t;
 #include <freeradius-devel/util/dns.h>
 #include <freeradius-devel/util/file.h>
 #include <freeradius-devel/util/log.h>
-#include <freeradius-devel/util/misc.h>
+#include <freeradius-devel/util/skip.h>
 #include <freeradius-devel/util/pair_legacy.h>
 #include <freeradius-devel/util/sha1.h>
 #include <freeradius-devel/util/syserror.h>
index b3cc08f67fd5d7a5cb3a1fed4d43a43ac5d0df78..c0de76b7af4737b611c66e3749aa188156177042 100644 (file)
@@ -40,6 +40,7 @@ RCSID("$Id$")
 #include <freeradius-devel/util/file.h>
 #include <freeradius-devel/util/misc.h>
 #include <freeradius-devel/util/perm.h>
+#include <freeradius-devel/util/skip.h>
 #include <freeradius-devel/util/md5.h>
 
 
@@ -174,8 +175,6 @@ static inline CC_HINT(always_inline) int cf_tmpl_rules_verify(CONF_SECTION *cs,
 
 #define RULES_VERIFY(_cs, _rules) if (cf_tmpl_rules_verify(_cs, _rules) < 0) return NULL
 
-static ssize_t fr_skip_xlat(char const *start, char const *end);
-
 /*
  *     Expand the variables in an input string.
  *
@@ -1228,140 +1227,6 @@ static int process_template(cf_stack_t *stack)
 static int cf_file_fill(cf_stack_t *stack);
 
 
-/**  Skip an xlat expression.
- *
- *  This is a simple "peek ahead" parser which tries to not be wrong.  It may accept
- *  some things which will later parse as invalid (e.g. unknown attributes, etc.)
- *  But it also rejects all malformed expressions.
- *
- *  It's used as a quick hack because the full parser isn't always available.
- *
- *  @param[in] start   start of the expression, MUST point to the "%{" or "%("
- *  @param[in] end     end of the string (or NULL for zero-terminated strings)
- *  @return
- *     >0 length of the string which was parsed
- *     <=0 on error
- */
-static ssize_t fr_skip_xlat(char const *start, char const *end)
-{
-       int     depth = 1;              /* caller skips '{' */
-       ssize_t slen;
-       char    quote, end_quote;
-       char const *p = start;
-
-       /*
-        *      At least %{1}
-        */
-       if (end && ((start + 4) > end)) {
-               fr_strerror_const("Invalid expansion");
-               return 0;
-       }
-
-       if ((*p != '%') && (*p != '$')) {
-               fr_strerror_const("Unexpected character in expansion");
-               return -(p - start);
-       }
-
-       p++;
-       if ((*p != '{') && (*p != '(')) {
-               char const *q = p;
-
-               /*
-                *      New xlat syntax: %foo(...)
-                */
-               while (isalnum((int) *q) || (*q == '.') || (*q == '_') || (*q == '-')) {
-                       q++;
-               }
-               if (*q == '(') {
-                       p = q;
-                       goto do_quote;
-               }
-
-               fr_strerror_const("Invalid character after '%'");
-               return -(p - start);
-       }
-
-do_quote:
-       quote = *(p++);
-       if (quote == '{') {
-               end_quote = '}';
-       } else {
-               end_quote = ')';
-       }
-
-       while ((end && (p < end)) || (*p >= ' ')) {
-               if (*p == quote) {
-                       p++;
-                       depth++;
-                       continue;
-               }
-
-               if (*p == end_quote) {
-                       p++;
-                       depth--;
-                       if (!depth) return p - start;
-
-                       continue;
-               }
-
-               /*
-                *      Nested expansion.
-                */
-               if ((p[0] == '$') || (p[0] == '%')) {
-                       if (end && (p + 2) >= end) break;
-
-                       if ((p[1] == '{') || ((p[0] == '$') && (p[1] == '('))) {
-                               slen = fr_skip_xlat(p, end);
-
-                       check:
-                               if (slen <= 0) return -(p - start) + slen;
-
-                               p += slen;
-                               continue;
-                       }
-
-                       /*
-                        *      Bare $ or %, just leave it alone.
-                        */
-                       p++;
-                       continue;
-               }
-
-               /*
-                *      A quoted string.
-                */
-               if ((*p == '"') || (*p == '\'') || (*p == '`')) {
-                       slen = fr_skip_string(p, end);
-                       goto check;
-               }
-
-               /*
-                *      @todo - bare '(' is a condition or nested
-                *      expression.  The brackets need to balance
-                *      here, too.
-                */
-
-               if (*p != '\\') {
-                       p++;
-                       continue;
-               }
-
-               if (end && ((p + 2) >= end)) break;
-
-               /*
-                *      Escapes here are only one-character escapes.
-                */
-               if (p[1] < ' ') break;
-               p += 2;
-       }
-
-       /*
-        *      Unexpected end of xlat
-        */
-       fr_strerror_const("Unexpected end of expansion");
-       return -(p - start);
-}
-
 static const bool terminal_end_section[UINT8_MAX + 1] = {
        ['{'] = true,
 };
@@ -1378,171 +1243,6 @@ static const bool terminal_end_line[UINT8_MAX + 1] = {
        ['}'] = true,
 };
 
-/**  Skip a conditional expression.
- *
- *  This is a simple "peek ahead" parser which tries to not be wrong.  It may accept
- *  some things which will later parse as invalid (e.g. unknown attributes, etc.)
- *  But it also rejects all malformed expressions.
- *
- *  It's used as a quick hack because the full parser isn't always available.
- *
- *  @param[in] start   start of the condition.
- *  @param[in] end     end of the string (or NULL for zero-terminated strings)
- *  @param[in] terminal        terminal character(s)
- *  @param[out] eol    did the parse error happen at eol?
- *  @return
- *     >0 length of the string which was parsed.  *eol is false.
- *     <=0 on error, *eol may be set.
- */
-static ssize_t fr_skip_condition(char const *start, char const *end, bool const terminal[static UINT8_MAX + 1], bool *eol)
-{
-       char const *p = start;
-       bool was_regex = false;
-       int depth = 0;
-       ssize_t slen;
-
-       if (eol) *eol = false;
-
-       /*
-        *      Keep parsing the condition until we hit EOS or EOL.
-        */
-       while ((end && (p < end)) || *p) {
-               if (isspace((uint8_t) *p)) {
-                       p++;
-                       continue;
-               }
-
-               /*
-                *      In the configuration files, conditions end with ") {" or just "{"
-                */
-               if ((depth == 0) && terminal[(uint8_t) *p]) {
-                       return p - start;
-               }
-
-               /*
-                *      "recurse" to get more conditions.
-                */
-               if (*p == '(') {
-                       p++;
-                       depth++;
-                       was_regex = false;
-                       continue;
-               }
-
-               if (*p == ')') {
-                       if (!depth) {
-                               fr_strerror_const("Too many ')'");
-                               return -(p - start);
-                       }
-
-                       p++;
-                       depth--;
-                       was_regex = false;
-                       continue;
-               }
-
-               /*
-                *      Parse xlats.  They cannot span EOL.
-                */
-               if ((*p == '$') || (*p == '%')) {
-                       if (end && ((p + 2) >= end)) {
-                               fr_strerror_const("Expansions cannot extend across end of line");
-                               return -(p - start);
-                       }
-
-                       if ((p[1] == '{') || ((p[0] == '$') && (p[1] == '('))) {
-                               slen = fr_skip_xlat(p, end);
-
-                       check:
-                               if (slen <= 0) return -(p - start) + slen;
-
-                               p += slen;
-                               continue;
-                       }
-
-                       /*
-                        *      Bare $ or %, just leave it alone.
-                        */
-                       p++;
-                       was_regex = false;
-                       continue;
-               }
-
-               /*
-                *      Parse quoted strings.  They cannot span EOL.
-                */
-               if ((*p == '"') || (*p == '\'') || (*p == '`') || (was_regex && (*p == '/'))) {
-                       was_regex = false;
-
-                       slen = fr_skip_string((char const *) p, end);
-                       goto check;
-               }
-
-               /*
-                *      192.168/16 is a netmask.  So we only
-                *      allow regex after a regex operator.
-                *
-                *      This isn't perfect, but is good enough
-                *      for most purposes.
-                */
-               if ((p[0] == '=') || (p[0] == '!')) {
-                       if (end && ((p + 2) >= end)) {
-                               fr_strerror_const("Operators cannot extend across end of line");
-                               return -(p - start);
-                       }
-
-                       if (p[1] == '~') {
-                               was_regex = true;
-                               p += 2;
-                               continue;
-                       }
-
-                       /*
-                        *      Some other '==' or '!=', just leave it alone.
-                        */
-                       p++;
-                       was_regex = false;
-                       continue;
-               }
-
-               /*
-                *      Any control characters (other than \t) cause an error.
-                */
-               if (*p < ' ') break;
-
-               was_regex = false;
-
-               /*
-                *      Normal characters just get skipped.
-                */
-               if (*p != '\\') {
-                       p++;
-                       continue;
-               }
-
-               /*
-                *      Backslashes at EOL are ignored.
-                */
-               if (end && ((p + 2) >= end)) break;
-
-               /*
-                *      Escapes here are only one-character escapes.
-                */
-               if (p[1] < ' ') break;
-               p += 2;
-       }
-
-       /*
-        *      We've fallen off of the end of a string.  It may be OK?
-        */
-       if (eol) *eol = (depth > 0);
-
-       if (terminal[(uint8_t) *p]) return p - start;
-
-       fr_strerror_const("Unexpected end of condition");
-       return -(p - start);
-}
-
 static CONF_ITEM *process_if(cf_stack_t *stack)
 {
        ssize_t         slen = 0;
index 66b9b26cf82fd2b61cb2d4d7da715937d96243e2..b6a0c541f011f3d71a27a4eeb28f3b0fedac71b3 100644 (file)
@@ -29,7 +29,7 @@ RCSID("$Id$")
 #include <freeradius-devel/server/log.h>
 #include <freeradius-devel/util/debug.h>
 
-#include <freeradius-devel/util/misc.h>
+#include <freeradius-devel/util/skip.h>
 
 /*
  *     Registration hooks for radmin.
index 7f5c2d4a90910e9bc2e5593729b491d3676283c3..82a1aa7c13634532bd6d9bd7ddbd38ebae63b3c8 100644 (file)
@@ -25,6 +25,7 @@ RCSID("$Id$")
 #include <freeradius-devel/server/base.h>
 
 #include <freeradius-devel/util/base16.h>
+#include <freeradius-devel/util/skip.h>
 #include <freeradius-devel/util/perm.h>
 
 
index 99fa5eb5c15af310282b1da10d4d4a711fa76b13..f6233b420ee62997bd5ef63f5d297f421a8b936a 100644 (file)
@@ -32,7 +32,7 @@
 
 #include <freeradius-devel/util/debug.h>
 #include <freeradius-devel/util/base16.h>
-#include <freeradius-devel/util/misc.h>
+#include <freeradius-devel/util/skip.h>
 #include <freeradius-devel/util/pair_legacy.h>
 
 #include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
index 86a88bf95d90add1a8d2d0ee2fd7b6e6507f201d..f9e21d14e95f2dc73c8d1edcff5cf7c534975f91 100644 (file)
@@ -80,6 +80,7 @@ SOURCES               := \
                   sem.c \
                   sha1.c \
                   size.c \
+                  skip.c \
                   snprintf.c \
                   socket.c \
                   stats.c \
index de2598cee5289dbb7bcd58e116874b44501bdc30..e7bacbc081e45f4e103299e3c620422378cd1108 100644 (file)
@@ -52,25 +52,6 @@ void         fr_talloc_verify_cb(const void *ptr, int depth,
 #  define VERIFY_ALL_TALLOC
 #endif
 
-/** Skip whitespace ('\\t', '\\n', '\\v', '\\f', '\\r', ' ')
- *
- * @param[in,out] _p   string to skip over.
- */
-#define fr_skip_whitespace(_p) while(isspace((uint8_t)*(_p))) _p++
-
-/** Skip whitespace, stopping at end ('\\t', '\\n', '\\v', '\\f', '\\r', ' ')
- *
- * @param[in,out] _p   string to skip over.
- * @param[in] _e       pointer to end of string.
- */
-#define fr_bskip_whitespace(_p, _e) while((_p < _e) && isspace((uint8_t)*(_p))) _p++
-
-/** Skip everything that's not whitespace ('\\t', '\\n', '\\v', '\\f', '\\r', ' ')
- *
- * @param[in,out] _p   string to skip over.
- */
-#define fr_skip_not_whitespace(_p) while(*_p && !isspace((uint8_t)*(_p))) _p++
-
 /** Zero out any whitespace with nul bytes
  *
  * @param[in,out] _p   string to process
index 981bd93372c412207126323dfcc1727b51919575..b59f06805fb1b864e9934ef95e55ff7b641d2ae3 100644 (file)
@@ -22,7 +22,7 @@
  */
 RCSID("$Id$")
 
-#include <freeradius-devel/util/misc.h>
+#include <freeradius-devel/util/skip.h>
 #include <freeradius-devel/util/pair.h>
 #include <freeradius-devel/util/proto.h>
 #include <freeradius-devel/util/regex.h>
diff --git a/src/lib/util/skip.c b/src/lib/util/skip.c
new file mode 100644 (file)
index 0000000..81d7129
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ *   This library is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU Lesser General Public
+ *   License as published by the Free Software Foundation; either
+ *   version 2.1 of the License, or (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ *   Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** Preparse input by skipping known tokens
+ *
+ * @file src/lib/util/skip.c
+ *
+ * @copyright 2025 Network RADIUS SAS (legal@networkradius.com)
+ */
+RCSID("$Id$")
+
+#include <freeradius-devel/util/misc.h>
+#include <freeradius-devel/util/skip.h>
+#include <freeradius-devel/util/strerror.h>
+
+/**  Skip a quoted string.
+ *
+ *  @param[in] start   start of the string, pointing to the quotation character
+ *  @param[in] end     end of the string (or NULL for zero-terminated strings)
+ *  @return
+ *     >0 length of the string which was parsed
+ *     <=0 on error
+ */
+ssize_t fr_skip_string(char const *start, char const *end)
+{
+       char const *p = start;
+       char quote;
+
+       quote = *(p++);
+
+       while ((end && (p < end)) || *p) {
+               /*
+                *      Stop at the quotation character
+                */
+               if (*p == quote) {
+                       p++;
+                       return p - start;
+               }
+
+               /*
+                *      Not an escape character: it's OK.
+                */
+               if (*p != '\\') {
+                       p++;
+                       continue;
+               }
+
+               if (end && ((p + 2) >= end)) {
+               fail:
+                       fr_strerror_const("Unexpected escape at end of string");
+                       return -(p - start);
+               }
+
+               /*
+                *      Escape at EOL is not allowed.
+                */
+               if (p[1] < ' ') goto fail;
+
+               /*
+                *      \r or \n, etc.
+                */
+               if (!isdigit((uint8_t) p[1])) {
+                       p += 2;
+                       continue;
+               }
+
+               /*
+                *      Double-quoted strings use \000
+                *      Regexes use \0
+                */
+               if (quote == '/') {
+                       p++;
+                       continue;
+               }
+
+               if (end && ((p + 4) >= end)) goto fail;
+
+               /*
+                *      Allow for \1f in single quoted strings
+                */
+               if ((quote == '\'') && isxdigit((uint8_t) p[1]) && isxdigit((uint8_t) p[2])) {
+                       p += 3;
+                       continue;
+               }
+
+               if (!isdigit((uint8_t) p[2]) || !isdigit((uint8_t) p[3])) {
+                       fr_strerror_const("Invalid octal escape");
+                       return -(p - start);
+               }
+
+               p += 4;
+       }
+
+       /*
+        *      Unexpected end of string.
+        */
+       fr_strerror_const("Unexpected end of string");
+       return -(p - start);
+}
+
+/**  Skip an xlat expression.
+ *
+ *  This is a simple "peek ahead" parser which tries to not be wrong.  It may accept
+ *  some things which will later parse as invalid (e.g. unknown attributes, etc.)
+ *  But it also rejects all malformed expressions.
+ *
+ *  It's used as a quick hack because the full parser isn't always available.
+ *
+ *  @param[in] start   start of the expression, MUST point to the "%{" or "%("
+ *  @param[in] end     end of the string (or NULL for zero-terminated strings)
+ *  @return
+ *     >0 length of the string which was parsed
+ *     <=0 on error
+ */
+ssize_t fr_skip_xlat(char const *start, char const *end)
+{
+       int     depth = 1;              /* caller skips '{' */
+       ssize_t slen;
+       char    quote, end_quote;
+       char const *p = start;
+
+       /*
+        *      At least %{1}
+        */
+       if (end && ((start + 4) > end)) {
+               fr_strerror_const("Invalid expansion");
+               return 0;
+       }
+
+       if ((*p != '%') && (*p != '$')) {
+               fr_strerror_const("Unexpected character in expansion");
+               return -(p - start);
+       }
+
+       p++;
+       if ((*p != '{') && (*p != '(')) {
+               char const *q = p;
+
+               /*
+                *      New xlat syntax: %foo(...)
+                */
+               while (isalnum((int) *q) || (*q == '.') || (*q == '_') || (*q == '-')) {
+                       q++;
+               }
+               if (*q == '(') {
+                       p = q;
+                       goto do_quote;
+               }
+
+               fr_strerror_const("Invalid character after '%'");
+               return -(p - start);
+       }
+
+do_quote:
+       quote = *(p++);
+       if (quote == '{') {
+               end_quote = '}';
+       } else {
+               end_quote = ')';
+       }
+
+       while ((end && (p < end)) || (*p >= ' ')) {
+               if (*p == quote) {
+                       p++;
+                       depth++;
+                       continue;
+               }
+
+               if (*p == end_quote) {
+                       p++;
+                       depth--;
+                       if (!depth) return p - start;
+
+                       continue;
+               }
+
+               /*
+                *      Nested expansion.
+                */
+               if ((p[0] == '$') || (p[0] == '%')) {
+                       if (end && (p + 2) >= end) break;
+
+                       if ((p[1] == '{') || ((p[0] == '$') && (p[1] == '('))) {
+                               slen = fr_skip_xlat(p, end);
+
+                       check:
+                               if (slen <= 0) return -(p - start) + slen;
+
+                               p += slen;
+                               continue;
+                       }
+
+                       /*
+                        *      Bare $ or %, just leave it alone.
+                        */
+                       p++;
+                       continue;
+               }
+
+               /*
+                *      A quoted string.
+                */
+               if ((*p == '"') || (*p == '\'') || (*p == '`')) {
+                       slen = fr_skip_string(p, end);
+                       goto check;
+               }
+
+               /*
+                *      @todo - bare '(' is a condition or nested
+                *      expression.  The brackets need to balance
+                *      here, too.
+                */
+
+               if (*p != '\\') {
+                       p++;
+                       continue;
+               }
+
+               if (end && ((p + 2) >= end)) break;
+
+               /*
+                *      Escapes here are only one-character escapes.
+                */
+               if (p[1] < ' ') break;
+               p += 2;
+       }
+
+       /*
+        *      Unexpected end of xlat
+        */
+       fr_strerror_const("Unexpected end of expansion");
+       return -(p - start);
+}
+
+/**  Skip a conditional expression.
+ *
+ *  This is a simple "peek ahead" parser which tries to not be wrong.  It may accept
+ *  some things which will later parse as invalid (e.g. unknown attributes, etc.)
+ *  But it also rejects all malformed expressions.
+ *
+ *  It's used as a quick hack because the full parser isn't always available.
+ *
+ *  @param[in] start   start of the condition.
+ *  @param[in] end     end of the string (or NULL for zero-terminated strings)
+ *  @param[in] terminal        terminal character(s)
+ *  @param[out] eol    did the parse error happen at eol?
+ *  @return
+ *     >0 length of the string which was parsed.  *eol is false.
+ *     <=0 on error, *eol may be set.
+ */
+ssize_t fr_skip_condition(char const *start, char const *end, bool const terminal[static UINT8_MAX + 1], bool *eol)
+{
+       char const *p = start;
+       bool was_regex = false;
+       int depth = 0;
+       ssize_t slen;
+
+       if (eol) *eol = false;
+
+       /*
+        *      Keep parsing the condition until we hit EOS or EOL.
+        */
+       while ((end && (p < end)) || *p) {
+               if (isspace((uint8_t) *p)) {
+                       p++;
+                       continue;
+               }
+
+               /*
+                *      In the configuration files, conditions end with ") {" or just "{"
+                */
+               if ((depth == 0) && terminal[(uint8_t) *p]) {
+                       return p - start;
+               }
+
+               /*
+                *      "recurse" to get more conditions.
+                */
+               if (*p == '(') {
+                       p++;
+                       depth++;
+                       was_regex = false;
+                       continue;
+               }
+
+               if (*p == ')') {
+                       if (!depth) {
+                               fr_strerror_const("Too many ')'");
+                               return -(p - start);
+                       }
+
+                       p++;
+                       depth--;
+                       was_regex = false;
+                       continue;
+               }
+
+               /*
+                *      Parse xlats.  They cannot span EOL.
+                */
+               if ((*p == '$') || (*p == '%')) {
+                       if (end && ((p + 2) >= end)) {
+                               fr_strerror_const("Expansions cannot extend across end of line");
+                               return -(p - start);
+                       }
+
+                       if ((p[1] == '{') || ((p[0] == '$') && (p[1] == '('))) {
+                               slen = fr_skip_xlat(p, end);
+
+                       check:
+                               if (slen <= 0) return -(p - start) + slen;
+
+                               p += slen;
+                               continue;
+                       }
+
+                       /*
+                        *      Bare $ or %, just leave it alone.
+                        */
+                       p++;
+                       was_regex = false;
+                       continue;
+               }
+
+               /*
+                *      Parse quoted strings.  They cannot span EOL.
+                */
+               if ((*p == '"') || (*p == '\'') || (*p == '`') || (was_regex && (*p == '/'))) {
+                       was_regex = false;
+
+                       slen = fr_skip_string((char const *) p, end);
+                       goto check;
+               }
+
+               /*
+                *      192.168/16 is a netmask.  So we only
+                *      allow regex after a regex operator.
+                *
+                *      This isn't perfect, but is good enough
+                *      for most purposes.
+                */
+               if ((p[0] == '=') || (p[0] == '!')) {
+                       if (end && ((p + 2) >= end)) {
+                               fr_strerror_const("Operators cannot extend across end of line");
+                               return -(p - start);
+                       }
+
+                       if (p[1] == '~') {
+                               was_regex = true;
+                               p += 2;
+                               continue;
+                       }
+
+                       /*
+                        *      Some other '==' or '!=', just leave it alone.
+                        */
+                       p++;
+                       was_regex = false;
+                       continue;
+               }
+
+               /*
+                *      Any control characters (other than \t) cause an error.
+                */
+               if (*p < ' ') break;
+
+               was_regex = false;
+
+               /*
+                *      Normal characters just get skipped.
+                */
+               if (*p != '\\') {
+                       p++;
+                       continue;
+               }
+
+               /*
+                *      Backslashes at EOL are ignored.
+                */
+               if (end && ((p + 2) >= end)) break;
+
+               /*
+                *      Escapes here are only one-character escapes.
+                */
+               if (p[1] < ' ') break;
+               p += 2;
+       }
+
+       /*
+        *      We've fallen off of the end of a string.  It may be OK?
+        */
+       if (eol) *eol = (depth > 0);
+
+       if (terminal[(uint8_t) *p]) return p - start;
+
+       fr_strerror_const("Unexpected end of condition");
+       return -(p - start);
+}
+
diff --git a/src/lib/util/skip.h b/src/lib/util/skip.h
new file mode 100644 (file)
index 0000000..454b2be
--- /dev/null
@@ -0,0 +1,60 @@
+#pragma once
+/*
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/** Preparse input by skipping known tokens
+ *
+ * @file src/lib/util/skip.h
+ *
+ * @copyright 2001,2006 The FreeRADIUS server project
+ */
+RCSIDH(skip_h, "$Id$")
+
+#include <sys/types.h>
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Skip whitespace ('\\t', '\\n', '\\v', '\\f', '\\r', ' ')
+ *
+ * @param[in,out] _p   string to skip over.
+ */
+#define fr_skip_whitespace(_p) while(isspace((uint8_t)*(_p))) _p++
+
+/** Skip whitespace, stopping at end ('\\t', '\\n', '\\v', '\\f', '\\r', ' ')
+ *
+ * @param[in,out] _p   string to skip over.
+ * @param[in] _e       pointer to end of string.
+ */
+#define fr_bskip_whitespace(_p, _e) while((_p < _e) && isspace((uint8_t)*(_p))) _p++
+
+/** Skip everything that's not whitespace ('\\t', '\\n', '\\v', '\\f', '\\r', ' ')
+ *
+ * @param[in,out] _p   string to skip over.
+ */
+#define fr_skip_not_whitespace(_p) while(*_p && !isspace((uint8_t)*(_p))) _p++
+
+ssize_t                fr_skip_string(char const *start, char const *end) CC_HINT(nonnull(1));
+
+ssize_t                fr_skip_xlat(char const *start, char const *end) CC_HINT(nonnull(1));
+
+ssize_t                fr_skip_condition(char const *start, char const *end, bool const terminal[static UINT8_MAX + 1],
+                                 bool *eol) CC_HINT(nonnull(1,3));
+#ifdef __cplusplus
+}
+#endif
index 207a9af603fff4cf461f31e4357cb3dc8bd7e679..a965af202b4766b99523aa2d2cc47834494cbf57 100644 (file)
@@ -27,7 +27,7 @@ RCSID("$Id$")
 
 #include <freeradius-devel/autoconf.h>
 #include <freeradius-devel/util/time.h>
-#include <freeradius-devel/util/misc.h>
+#include <freeradius-devel/util/skip.h>
 
 int64_t const fr_time_multiplier_by_res[] = {
        [FR_TIME_RES_NSEC]      = 1,
index 469c678c20313da398a0f9eb503cfce966d24d3f..dcfd4eb71cf26ad86774962a0c41610c8854faf3 100644 (file)
@@ -24,7 +24,9 @@
  */
 RCSID("$Id$")
 
-#include <freeradius-devel/util/misc.h>
+#include <stdio.h>
+
+#include <freeradius-devel/util/skip.h>
 #include <freeradius-devel/util/strerror.h>
 #include <freeradius-devel/util/token.h>
 
@@ -511,90 +513,3 @@ char const *fr_token_name(int token)
 {
        return fr_table_str_by_value(fr_tokens_table, token, "<INVALID>");
 }
-
-
-/**  Skip a quoted string.
- *
- *  @param[in] start   start of the string, pointing to the quotation character
- *  @param[in] end     end of the string (or NULL for zero-terminated strings)
- *  @return
- *     >0 length of the string which was parsed
- *     <=0 on error
- */
-ssize_t fr_skip_string(char const *start, char const *end)
-{
-       char const *p = start;
-       char quote;
-
-       quote = *(p++);
-
-       while ((end && (p < end)) || *p) {
-               /*
-                *      Stop at the quotation character
-                */
-               if (*p == quote) {
-                       p++;
-                       return p - start;
-               }
-
-               /*
-                *      Not an escape character: it's OK.
-                */
-               if (*p != '\\') {
-                       p++;
-                       continue;
-               }
-
-               if (end && ((p + 2) >= end)) {
-               fail:
-                       fr_strerror_const("Unexpected escape at end of string");
-                       return -(p - start);
-               }
-
-               /*
-                *      Escape at EOL is not allowed.
-                */
-               if (p[1] < ' ') goto fail;
-
-               /*
-                *      \r or \n, etc.
-                */
-               if (!isdigit((uint8_t) p[1])) {
-                       p += 2;
-                       continue;
-               }
-
-               /*
-                *      Double-quoted strings use \000
-                *      Regexes use \0
-                */
-               if (quote == '/') {
-                       p++;
-                       continue;
-               }
-
-               if (end && ((p + 4) >= end)) goto fail;
-
-               /*
-                *      Allow for \1f in single quoted strings
-                */
-               if ((quote == '\'') && isxdigit((uint8_t) p[1]) && isxdigit((uint8_t) p[2])) {
-                       p += 3;
-                       continue;
-               }
-
-               if (!isdigit((uint8_t) p[2]) || !isdigit((uint8_t) p[3])) {
-                       fr_strerror_const("Invalid octal escape");
-                       return -(p - start);
-               }
-
-               p += 4;
-       }
-
-       /*
-        *      Unexpected end of string.
-        */
-       fr_strerror_const("Unexpected end of string");
-       return -(p - start);
-}
-
index 05f6062a44f27d95d5295660810461ddd784e7da..398084ec490524946e4acb293a284f894bc0019a 100644 (file)
@@ -153,7 +153,6 @@ fr_token_t  gettoken(char const **ptr, char *buf, int buflen, bool unescape);
 fr_token_t     getop(char const **ptr);
 fr_token_t     getstring(char const **ptr, char *buf, int buflen, bool unescape);
 char const     *fr_token_name(int);
-ssize_t                fr_skip_string(char const *start, char const *end);
 
 #ifdef __cplusplus
 }
index c8fe1cef472fddb6b5bb3e4e5f08f9765c22cd43..70e4c6f3c48183805fdefafead65cf7141d78dc2 100644 (file)
@@ -23,6 +23,7 @@
 RCSID("$Id$")
 
 #include <freeradius-devel/util/dict.h>
+#include <freeradius-devel/util/skip.h>
 #include <freeradius-devel/util/syserror.h>
 #include <freeradius-devel/util/trie.h>
 
index f5aa08a6b5d642c8cb5e80983f31e851e0cf8b26..1428871c9b2f77511ee413a11045012fb7e74223 100644 (file)
@@ -74,6 +74,7 @@ DIAG_ON(strict-prototypes)
 
 #include <freeradius-devel/util/conf.h>
 #include <freeradius-devel/util/md5.h>
+#include <freeradius-devel/util/skip.h>
 #include <freeradius-devel/util/socket.h>
 #include <freeradius-devel/util/atexit.h>
 
index d3a0eb8f0c6d3f417cb45b138708e620501111bf..7c1355e824ebe53b00a42dee0f00d589b7428739 100644 (file)
@@ -27,6 +27,7 @@
 #include <freeradius-devel/io/application.h>
 #include <freeradius-devel/io/listen.h>
 #include <freeradius-devel/io/schedule.h>
+#include <freeradius-devel/util/skip.h>
 
 #include "lib/server/cf_util.h"
 #include "proto_cron.h"
index 8d0ab69643b604a582dffd44ada77a45e45619d0..e13ed06df1353f32fe989a1a6c78ae994cf2df5c 100644 (file)
@@ -28,6 +28,7 @@ RCSID("$Id$")
 #include <freeradius-devel/server/module_rlm.h>
 #include <freeradius-devel/dhcpv4/dhcpv4.h>
 #include <freeradius-devel/util/debug.h>
+#include <freeradius-devel/util/skip.h>
 
 #include <freeradius-devel/server/map_proc.h>
 
index 0ae119dac46f3eddc39e1401132cde404ecac45c..33ddb2fc78305e6b36bc7764652ae8534b2073d2 100644 (file)
@@ -35,6 +35,7 @@ RCSID("$Id$")
 #include <freeradius-devel/server/pool.h>
 #include <freeradius-devel/server/tmpl.h>
 #include <freeradius-devel/unlang/call.h>
+#include <freeradius-devel/util/skip.h>
 #include <freeradius-devel/util/value.h>
 
 #include <talloc.h>
index a236eadfd98920d4d98fbfeef187338497f2c56b..d8b9e9c0fbb300eeaf1096d3e81afe5a9becfeb5 100644 (file)
@@ -36,6 +36,7 @@ RCSID("$Id$")
 #include <freeradius-devel/server/pairmove.h>
 #include <freeradius-devel/util/debug.h>
 #include <freeradius-devel/util/dict.h>
+#include <freeradius-devel/util/skip.h>
 #include <freeradius-devel/util/table.h>
 #include <freeradius-devel/unlang/function.h>
 #include <freeradius-devel/unlang/xlat_func.h>
index d1cc1b6c0b534884d13c5976fef7ddd0d7fe27f3..4ccdca7b06aefd46654db1322bf39323506d20a9 100644 (file)
@@ -31,6 +31,7 @@ USES_APPLE_DEPRECATED_API
 #include <freeradius-devel/radius/radius.h>
 #include <freeradius-devel/server/base.h>
 #include <freeradius-devel/server/module_rlm.h>
+#include <freeradius-devel/util/skip.h>
 #include <freeradius-devel/util/perm.h>
 #include <freeradius-devel/unlang/xlat_func.h>
 
index 434f3966da0a275399993318efb1e001d0ea1ccd..1a2041472da920f135e3a2f36ce8b655d1e2d768 100644 (file)
@@ -33,6 +33,7 @@ RCSID("$Id$")
 #include <freeradius-devel/util/debug.h>
 #include <freeradius-devel/unlang/xlat.h>
 #include <freeradius-devel/util/dcursor.h>
+#include <freeradius-devel/util/skip.h>
 #include <freeradius-devel/util/value.h>
 
 #include "rlm_winbind.h"