Fixes from clang / scan-build
[freeradius.git] / src / lib / token.c
index ebe1dac..47fb90a 100644 (file)
@@ -4,22 +4,32 @@
  *
  * Version:    $Id$
  *
+ *   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
+ *
+ * Copyright 2000,2006  The FreeRADIUS server project
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include "token.h"
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
 
-static const char rcsid[] = "$Id$";
+#include <freeradius-devel/libradius.h>
+#include <freeradius-devel/token.h>
 
-typedef struct {
-       const char *str;
-       int token;
-} TOKEN;
+#include <ctype.h>
 
-static const TOKEN tokens[] = {
+static const FR_NAME_NUMBER tokens[] = {
        { "=~", T_OP_REG_EQ,    }, /* order is important! */
        { "!~", T_OP_REG_NE,    },
        { "{",  T_LCBRACE,      },
@@ -30,6 +40,8 @@ static const TOKEN tokens[] = {
        { "+=", T_OP_ADD,       },
        { "-=", T_OP_SUB,       },
        { ":=", T_OP_SET,       },
+       { "=*", T_OP_CMP_TRUE,  },
+       { "!*", T_OP_CMP_FALSE, },
        { "==", T_OP_CMP_EQ,    },
        { "=",  T_OP_EQ,        },
        { "!=", T_OP_NE,        },
@@ -57,20 +69,21 @@ static const TOKEN tokens[] = {
  *     At end-of-line, buf[0] is set to '\0'.
  *     Returns 0 or special token value.
  */
-static int getthing(char **ptr, char *buf, int buflen, int tok,
-                   const TOKEN *tokenlist)
+static FR_TOKEN getthing(const char **ptr, char *buf, int buflen, int tok,
+                        const FR_NAME_NUMBER *tokenlist)
 {
-       char    *s, *p;
-       int     quote;
-       int     escape;
-       int     x;
-       const TOKEN     *t;
+       char *s;
+       const char *p;
+       int     quote, end = 0;
+       unsigned int    x;
+       const FR_NAME_NUMBER*t;
+       FR_TOKEN rcode;
 
        buf[0] = 0;
 
        /* Skip whitespace */
        p = *ptr;
-       while (*p && isspace(*p))
+       while (*p && isspace((int) *p))
                p++;
 
        if (*p == 0) {
@@ -81,29 +94,32 @@ static int getthing(char **ptr, char *buf, int buflen, int tok,
        /*
         *      Might be a 1 or 2 character token.
         */
-       if (tok) for (t = tokenlist; t->str; t++) {
-               if (TOKEN_MATCH(p, t->str)) {
-                       strcpy(buf, t->str);
-                       p += strlen(t->str);
-                       while (isspace(*p))
+       if (tok) for (t = tokenlist; t->name; t++) {
+               if (TOKEN_MATCH(p, t->name)) {
+                       strcpy(buf, t->name);
+                       p += strlen(t->name);
+                       while (isspace((int) *p))
                                p++;
                        *ptr = p;
-                       return t->token;
+                       return (FR_TOKEN) t->number;
                }
        }
 
        /* Read word. */
        quote = 0;
-       if (*p == '"') {
-               quote = 1;
+       if ((*p == '"') ||
+           (*p == '\'') ||
+           (*p == '`')) {
+               quote = *p;
+               end = 0;
                p++;
        }
        s = buf;
-       escape = 0;
 
-       while (*p && buflen-- > 0) {
-               if (escape) {
-                       escape = 0;
+       while (*p && buflen-- > 1) {
+               if (quote && (*p == '\\')) {
+                       p++;
+
                        switch(*p) {
                                case 'r':
                                        *s++ = '\r';
@@ -114,8 +130,9 @@ static int getthing(char **ptr, char *buf, int buflen, int tok,
                                case 't':
                                        *s++ = '\t';
                                        break;
-                               case '"':
-                                       *s++ = '"';
+                               case '\0':
+                                       *s++ = '\\';
+                                       p--; /* force EOS */
                                        break;
                                default:
                                        if (*p >= '0' && *p <= '9' &&
@@ -129,23 +146,19 @@ static int getthing(char **ptr, char *buf, int buflen, int tok,
                        p++;
                        continue;
                }
-               if (*p == '\\') {
-                       p++;
-                       escape = 1;
-                       continue;
-               }
-               if (quote && *p == '"') {
+               if (quote && (*p == quote)) {
+                       end = 1;
                        p++;
                        break;
                }
                if (!quote) {
-                       if (isspace(*p))
+                       if (isspace((int) *p))
                                break;
                        if (tok) {
-                               for (t = tokenlist; t->str; t++)
-                                       if (TOKEN_MATCH(p, t->str))
+                               for (t = tokenlist; t->name; t++)
+                                       if (TOKEN_MATCH(p, t->name))
                                                break;
-                               if (t->str != NULL)
+                               if (t->name != NULL)
                                        break;
                        }
                }
@@ -153,28 +166,122 @@ static int getthing(char **ptr, char *buf, int buflen, int tok,
        }
        *s++ = 0;
 
+       if (quote && !end) {
+               fr_strerror_printf("Unterminated string");
+               return T_OP_INVALID;
+       }
+
        /* Skip whitespace again. */
-       while (*p && isspace(*p))
+       while (*p && isspace((int) *p))
                p++;
        *ptr = p;
 
-       /* we got SOME form out output string, even if it is empty */
-       return 0;
+       /* we got SOME form of output string, even if it is empty */
+       switch (quote) {
+       default:
+         rcode = T_BARE_WORD;
+         break;
+
+       case '\'':
+         rcode = T_SINGLE_QUOTED_STRING;
+         break;
+
+       case '"':
+         rcode = T_DOUBLE_QUOTED_STRING;
+         break;
+
+       case '`':
+         rcode = T_BACK_QUOTED_STRING;
+         break;
+       }
+
+       return rcode;
 }
 
 /*
  *     Read a "word" - this means we don't honor
  *     tokens as delimiters.
  */
-int getword(char **ptr, char *buf, int buflen)
+int getword(const char **ptr, char *buf, int buflen)
 {
        return getthing(ptr, buf, buflen, 0, tokens) == T_EOL ? 0 : 1;
 }
 
 /*
+ *     Read a bare "word" - this means we don't honor
+ *     tokens as delimiters.
+ */
+int getbareword(const char **ptr, char *buf, int buflen)
+{
+       FR_TOKEN token;
+
+       token = getthing(ptr, buf, buflen, 0, NULL);
+       if (token != T_BARE_WORD) {
+               return 0;
+       }
+
+       return 1;
+}
+
+/*
  *     Read the next word, use tokens as delimiters.
  */
-int gettoken(char **ptr, char *buf, int buflen)
+FR_TOKEN gettoken(const char **ptr, char *buf, int buflen)
 {
        return getthing(ptr, buf, buflen, 1, tokens);
 }
+
+/*
+ *     Expect a string.
+ */
+FR_TOKEN getstring(const char **ptr, char *buf, int buflen)
+{
+       const char *p;
+
+       if (!ptr || !*ptr || !buf) return T_OP_INVALID;
+       
+       p = *ptr;
+
+       while (p && (isspace((int)*p))) p++;
+
+       *ptr = p;
+
+       if ((*p == '"') || (*p == '\'') || (*p == '`')) {
+               return gettoken(ptr, buf, buflen);
+       }
+
+       return getthing(ptr, buf, buflen, 0, tokens);
+}
+
+/*
+ *     Convert a string to an integer
+ */
+int fr_str2int(const FR_NAME_NUMBER *table, const char *name, int def)
+{
+       const FR_NAME_NUMBER *this;
+
+       for (this = table; this->name != NULL; this++) {
+               if (strcasecmp(this->name, name) == 0) {
+                       return this->number;
+               }
+       }
+
+       return def;
+}
+
+/*
+ *     Convert an integer to a string.
+ */
+const char *fr_int2str(const FR_NAME_NUMBER *table, int number,
+                        const char *def)
+{
+       const FR_NAME_NUMBER *this;
+
+       for (this = table; this->name != NULL; this++) {
+               if (this->number == number) {
+                       return this->name;
+               }
+       }
+
+       return def;
+}