updated rcsid[] strings
[freeradius.git] / src / lib / token.c
1 /*
2  * token.c      Read the next token from a string.
3  *              Yes it's pretty primitive but effective.
4  *
5  * Version:     $Id$
6  *
7  */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include "token.h"
14
15 static const char rcsid[] = "$Id$";
16
17 typedef struct {
18         char *str;
19         int token;
20 } TOKEN;
21
22 static TOKEN tokens[] = {
23         { "=~", T_OP_REG_EQ,    }, /* order is important! */
24         { "!~", T_OP_REG_NE,    },
25         { "{",  T_LCBRACE,      },
26         { "}",  T_RCBRACE,      },
27         { "(",  T_LBRACE,       },
28         { ")",  T_RBRACE,       },
29         { ",",  T_COMMA,        },
30         { "+=", T_OP_ADD,       },
31         { "-=", T_OP_SUB,       },
32         { ":=", T_OP_SET,       },
33         { "=",  T_OP_EQ,        },
34         { "!=", T_OP_NE,        },
35         { ">=", T_OP_GE,        },
36         { ">",  T_OP_GT,        },
37         { "<=", T_OP_LE,        },
38         { "<",  T_OP_LT,        },
39         { NULL, 0,              },
40 };
41
42 /*
43  *      This works only as long as special tokens
44  *      are max. 2 characters, but it's fast.
45  */
46 #define TOKEN_MATCH(bptr, tptr) \
47         ( (tptr)[0] == (bptr)[0] && \
48          ((tptr)[1] == (bptr)[1] || (tptr)[1] == 0))
49
50 /*
51  *      Read a word from a buffer and advance pointer.
52  *      This function knows about escapes and quotes.
53  *
54  *      At end-of-line, buf[0] is set to '\0'.
55  *      Returns 0 or special token value.
56  */
57 static int getthing(char **ptr, char *buf, int buflen, int tok)
58 {
59         char    *s, *p;
60         int     quote;
61         int     escape;
62         int     x;
63         TOKEN   *t;
64
65         buf[0] = 0;
66
67         /* Skip whitespace */
68         p = *ptr;
69         while (*p && isspace(*p))
70                 p++;
71
72         if (*p == 0) {
73                 *ptr = p;
74                 return T_EOL;
75         }
76
77         /*
78          *      Might be a 1 or 2 character token.
79          */
80         if (tok) for (t = tokens; t->str; t++) {
81                 if (TOKEN_MATCH(p, t->str)) {
82                         strcpy(buf, t->str);
83                         p += strlen(t->str);
84                         while (isspace(*p))
85                                 p++;
86                         *ptr = p;
87                         return t->token;
88                 }
89         }
90
91         /* Read word. */
92         quote = 0;
93         if (*p == '"') {
94                 quote = 1;
95                 p++;
96         }
97         s = buf;
98         escape = 0;
99
100         while (*p && buflen-- > 0) {
101                 if (escape) {
102                         escape = 0;
103                         switch(*p) {
104                                 case 'r':
105                                         *s++ = '\r';
106                                         break;
107                                 case 'n':
108                                         *s++ = '\n';
109                                         break;
110                                 case 't':
111                                         *s++ = '\t';
112                                         break;
113                                 default:
114                                         if (*p >= '0' && *p <= '9' &&
115                                             sscanf(p, "%3o", &x) == 1) {
116                                                 *s++ = x;
117                                                 p += 2;
118                                         } else
119                                                 *s++ = *p;
120                                         break;
121                         }
122                         p++;
123                         continue;
124                 }
125                 if (*p == '\\') {
126                         p++;
127                         escape = 1;
128                         continue;
129                 }
130                 if (quote && *p == '"') {
131                         p++;
132                         break;
133                 }
134                 if (!quote) {
135                         if (isspace(*p))
136                                 break;
137                         if (tok) {
138                                 for (t = tokens; t->str; t++)
139                                         if (TOKEN_MATCH(p, t->str))
140                                                 break;
141                                 if (t->str != NULL)
142                                         break;
143                         }
144                 }
145                 *s++ = *p++;
146         }
147         *s++ = 0;
148
149         /* Skip whitespace again. */
150         while (*p && isspace(*p))
151                 p++;
152         *ptr = p;
153
154         return (buf[0]) ? 0 : T_EOL;
155 }
156
157 /*
158  *      Read a "word" - this means we don't honor
159  *      tokens as delimiters.
160  */
161 int getword(char **ptr, char *buf, int buflen)
162 {
163         return getthing(ptr, buf, buflen, 0) == T_EOL ? 0 : 1;
164 }
165
166 /*
167  *      Read the next word, use tokens as delimiters.
168  */
169 int gettoken(char **ptr, char *buf, int buflen)
170 {
171         return getthing(ptr, buf, buflen, 1);
172 }
173