*
* 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, },
{ "+=", 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, },
* 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) {
/*
* 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';
case 't':
*s++ = '\t';
break;
- case '"':
- *s++ = '"';
+ case '\0':
+ *s++ = '\\';
+ p--; /* force EOS */
break;
default:
if (*p >= '0' && *p <= '9' &&
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;
}
}
}
*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;
+}