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