All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
token.c
Go to the documentation of this file.
1 /*
2  * token.c Read the next token from a string.
3  * Yes it's pretty primitive but effective.
4  *
5  * Version: $Id: 94c47c118f47941e15b4415e193def00ee2658de $
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * Copyright 2000,2006 The FreeRADIUS server project
22  */
23 
24 RCSID("$Id: 94c47c118f47941e15b4415e193def00ee2658de $")
25 
26 #include <freeradius-devel/libradius.h>
27 
28 #include <ctype.h>
29 
31  { "=~", T_OP_REG_EQ, }, /* order is important! */
32  { "!~", T_OP_REG_NE, },
33  { "{", T_LCBRACE, },
34  { "}", T_RCBRACE, },
35  { "(", T_LBRACE, },
36  { ")", T_RBRACE, },
37  { ",", T_COMMA, },
38  { "++", T_OP_INCRM, },
39  { "+=", T_OP_ADD, },
40  { "-=", T_OP_SUB, },
41  { ":=", T_OP_SET, },
42  { "=*", T_OP_CMP_TRUE, },
43  { "!*", T_OP_CMP_FALSE, },
44  { "==", T_OP_CMP_EQ, },
45  { "=", T_OP_EQ, },
46  { "!=", T_OP_NE, },
47  { ">=", T_OP_GE, },
48  { ">", T_OP_GT, },
49  { "<=", T_OP_LE, },
50  { "<", T_OP_LT, },
51  { "#", T_HASH, },
52  { ";", T_SEMICOLON, },
53  { NULL, 0, },
54 };
55 
56 
57 /*
58  * This is a hack, and has to be kept in sync with tokens.h
59  */
60 char const *fr_tokens[] = {
61  "?", /* T_INVALID */
62  "EOL", /* T_EOL */
63  "{",
64  "}",
65  "(",
66  ")",
67  ",",
68  ";",
69  "++",
70  "+=",
71  "-=",
72  ":=",
73  "=",
74  "!=",
75  ">=",
76  ">",
77  "<=",
78  "<",
79  "=~",
80  "!~",
81  "=*",
82  "!*",
83  "==",
84  "#",
85  "<BARE-WORD>",
86  "<\"STRING\">",
87  "<'STRING'>",
88  "<`STRING`>"
89 };
90 
91 
92 /** Convert tokens back to a quoting character
93  *
94  * None string types convert to '?' to screw ups can be identified easily
95  */
96 const char fr_token_quote[] = {
97  '?', /* invalid token */
98  '?', /* end of line */
99  '?', /* { */
100  '?', /* } */
101  '?', /* ( */
102  '?', /* ) 5 */
103  '?', /* , */
104  '?', /* ; */
105 
106  '?', /* ++ */
107  '?', /* += */
108  '?', /* -= 10 */
109  '?', /* := */
110  '?', /* = */
111  '?', /* != */
112  '?', /* >= */
113  '?', /* > 15 */
114  '?', /* <= */
115  '?', /* < */
116  '?', /* =~ */
117  '?', /* !~ */
118  '?', /* =* 20 */
119  '?', /* !* */
120  '?', /* == */
121  '?', /* # */
122  '\0', /* bare word */
123  '"', /* "foo" 25 */
124  '\'', /* 'foo' */
125  '`', /* `foo` */
126  '?'
127 };
128 
129 const bool fr_assignment_op[] = {
130  false, /* invalid token */
131  false, /* end of line */
132  false, /* { */
133  false, /* } */
134  false, /* ( */
135  false, /* ) 5 */
136  false, /* , */
137  false, /* ; */
138 
139  true, /* ++ */
140  true, /* += */
141  true, /* -= 10 */
142  true, /* := */
143  true, /* = */
144  false, /* != */
145  false, /* >= */
146  false, /* > 15 */
147  false, /* <= */
148  false, /* < */
149  false, /* =~ */
150  false, /* !~ */
151  false, /* =* 20 */
152  false, /* !* */
153  false, /* == */
154  false, /* # */
155  false, /* bare word */
156  false, /* "foo" 25 */
157  false, /* 'foo' */
158  false, /* `foo` */
159  false
160 };
161 
162 const bool fr_equality_op[] = {
163  false, /* invalid token */
164  false, /* end of line */
165  false, /* { */
166  false, /* } */
167  false, /* ( */
168  false, /* ) 5 */
169  false, /* , */
170  false, /* ; */
171 
172  false, /* ++ */
173  false, /* += */
174  false, /* -= 10 */
175  false, /* := */
176  false, /* = */
177  true, /* != */
178  true, /* >= */
179  true, /* > 15 */
180  true, /* <= */
181  true, /* < */
182  true, /* =~ */
183  true, /* !~ */
184  true, /* =* 20 */
185  true, /* !* */
186  true, /* == */
187  false, /* # */
188  false, /* bare word */
189  false, /* "foo" 25 */
190  false, /* 'foo' */
191  false, /* `foo` */
192  false
193 };
194 
195 const bool fr_str_tok[] = {
196  false, /* invalid token */
197  false, /* end of line */
198  false, /* { */
199  false, /* } */
200  false, /* ( */
201  false, /* ) 5 */
202  false, /* , */
203  false, /* ; */
204 
205  false, /* ++ */
206  false, /* += */
207  false, /* -= 10 */
208  false, /* := */
209  false, /* = */
210  false, /* != */
211  false, /* >= */
212  false, /* > 15 */
213  false, /* <= */
214  false, /* < */
215  false, /* =~ */
216  false, /* !~ */
217  false, /* =* 20 */
218  false, /* !* */
219  false, /* == */
220  false, /* # */
221  true, /* bare word */
222  true, /* "foo" 25 */
223  true, /* 'foo' */
224  true, /* `foo` */
225  false
226 };
227 
228 /*
229  * This works only as long as special tokens
230  * are max. 2 characters, but it's fast.
231  */
232 #define TOKEN_MATCH(bptr, tptr) \
233  ( (tptr)[0] == (bptr)[0] && \
234  ((tptr)[1] == (bptr)[1] || (tptr)[1] == 0))
235 
236 /*
237  * Read a word from a buffer and advance pointer.
238  * This function knows about escapes and quotes.
239  *
240  * At end-of-line, buf[0] is set to '\0'.
241  * Returns 0 or special token value.
242  */
243 static FR_TOKEN getthing(char const **ptr, char *buf, int buflen, bool tok,
244  FR_NAME_NUMBER const *tokenlist, bool unescape)
245 {
246  char *s;
247  char const *p;
248  char quote;
249  bool end = false;
250  unsigned int x;
251  FR_NAME_NUMBER const *t;
252  FR_TOKEN rcode;
253 
254  buf[0] = '\0';
255 
256  /* Skip whitespace */
257  p = *ptr;
258  while (*p && isspace((int) *p))
259  p++;
260 
261  if (*p == 0) {
262  *ptr = p;
263  return T_EOL;
264  }
265 
266  /*
267  * Might be a 1 or 2 character token.
268  */
269  if (tok) for (t = tokenlist; t->name; t++) {
270  if (TOKEN_MATCH(p, t->name)) {
271  strcpy(buf, t->name);
272  p += strlen(t->name);
273  while (isspace((int) *p))
274  p++;
275  *ptr = p;
276  return (FR_TOKEN) t->number;
277  }
278  }
279 
280  /* Read word. */
281  quote = '\0';
282  if ((*p == '"') ||
283  (*p == '\'') ||
284  (*p == '`')) {
285  quote = *p;
286  end = false;
287  p++;
288  }
289  s = buf;
290 
291  while (*p && buflen-- > 1) {
292  if (unescape && quote && (*p == '\\')) {
293  p++;
294 
295  switch (*p) {
296  case 'r':
297  *s++ = '\r';
298  break;
299  case 'n':
300  *s++ = '\n';
301  break;
302  case 't':
303  *s++ = '\t';
304  break;
305  case '\0':
306  *s++ = '\\';
307  p--; /* force EOS */
308  break;
309  default:
310  if (*p >= '0' && *p <= '9' &&
311  sscanf(p, "%3o", &x) == 1) {
312  *s++ = x;
313  p += 2;
314  } else
315  *s++ = *p;
316  break;
317  }
318  p++;
319  continue;
320  }
321 
322  /*
323  * Deal with quotes and escapes, but don't mash
324  * escaped characters into their non-escaped
325  * equivalent.
326  */
327  if (!unescape && quote && (*p == '\\')) {
328  if (!p[1]) continue; /* force end of string */
329 
330  if (p[1] == quote) { /* convert '\'' --> ' */
331  p++;
332  } else {
333  *(s++) = *(p++);
334  }
335  *(s++) = *(p++);
336  continue;
337  }
338 
339  if (quote && (*p == quote)) {
340  end = true;
341  p++;
342  break;
343  }
344  if (!quote) {
345  if (isspace((int) *p))
346  break;
347  if (tok) {
348  for (t = tokenlist; t->name; t++)
349  if (TOKEN_MATCH(p, t->name))
350  break;
351  if (t->name != NULL)
352  break;
353  }
354  if (*p == ',') break; /* hack */
355  }
356  *s++ = *p++;
357  }
358  *s++ = 0;
359 
360  if (quote && !end) {
361  fr_strerror_printf("Unterminated string");
362  return T_INVALID;
363  }
364 
365  /* Skip whitespace again. */
366  while (*p && isspace((int) *p))
367  p++;
368  *ptr = p;
369 
370  /* we got SOME form of output string, even if it is empty */
371  switch (quote) {
372  default:
373  rcode = T_BARE_WORD;
374  break;
375 
376  case '\'':
377  rcode = T_SINGLE_QUOTED_STRING;
378  break;
379 
380  case '"':
381  rcode = T_DOUBLE_QUOTED_STRING;
382  break;
383 
384  case '`':
385  rcode = T_BACK_QUOTED_STRING;
386  break;
387  }
388 
389  return rcode;
390 }
391 
392 /*
393  * Read a "word" - this means we don't honor
394  * tokens as delimiters.
395  */
396 int getword(char const **ptr, char *buf, int buflen, bool unescape)
397 {
398  return getthing(ptr, buf, buflen, false, fr_tokens_table, unescape) == T_EOL ? 0 : 1;
399 }
400 
401 
402 /*
403  * Read the next word, use tokens as delimiters.
404  */
405 FR_TOKEN gettoken(char const **ptr, char *buf, int buflen, bool unescape)
406 {
407  return getthing(ptr, buf, buflen, true, fr_tokens_table, unescape);
408 }
409 
410 /*
411  * Expect an operator.
412  */
413 FR_TOKEN getop(char const **ptr)
414 {
415  char op[3];
416  FR_TOKEN rcode;
417 
418  rcode = getthing(ptr, op, sizeof(op), true, fr_tokens_table, false);
419  if (!fr_assignment_op[rcode] && !fr_equality_op[rcode]) {
420  fr_strerror_printf("Expected operator");
421  return T_INVALID;
422  }
423  return rcode;
424 }
425 
426 /*
427  * Expect a string.
428  */
429 FR_TOKEN getstring(char const **ptr, char *buf, int buflen, bool unescape)
430 {
431  char const *p;
432 
433  if (!ptr || !*ptr || !buf) return T_INVALID;
434 
435  p = *ptr;
436 
437  while (*p && (isspace((int)*p))) p++;
438 
439  *ptr = p;
440 
441  if ((*p == '"') || (*p == '\'') || (*p == '`')) {
442  return gettoken(ptr, buf, buflen, unescape);
443  }
444 
445  return getthing(ptr, buf, buflen, 0, fr_tokens_table, unescape);
446 }
447 
448 /*
449  * Convert a string to an integer
450  */
451 int fr_str2int(FR_NAME_NUMBER const *table, char const *name, int def)
452 {
453  FR_NAME_NUMBER const *this;
454 
455  if (!name) {
456  return def;
457  }
458 
459  for (this = table; this->name != NULL; this++) {
460  if (strcasecmp(this->name, name) == 0) {
461  return this->number;
462  }
463  }
464 
465  return def;
466 }
467 
468 /*
469  * Convert a string matching part of name to an integer.
470  */
471 int fr_substr2int(FR_NAME_NUMBER const *table, char const *name, int def, int len)
472 {
473  FR_NAME_NUMBER const *this;
474  size_t max;
475 
476  if (!name) {
477  return def;
478  }
479 
480  for (this = table; this->name != NULL; this++) {
481  size_t tlen;
482 
483  tlen = strlen(this->name);
484 
485  /*
486  * Don't match "request" to user input "req".
487  */
488  if ((len > 0) && (len < (int) tlen)) continue;
489 
490  /*
491  * Match up to the length of the table entry if len is < 0.
492  */
493  max = (len < 0) ? tlen : (unsigned)len;
494 
495  if (strncasecmp(this->name, name, max) == 0) {
496  return this->number;
497  }
498  }
499 
500  return def;
501 }
502 
503 /*
504  * Convert an integer to a string.
505  */
506 char const *fr_int2str(FR_NAME_NUMBER const *table, int number,
507  char const *def)
508 {
509  FR_NAME_NUMBER const *this;
510 
511  for (this = table; this->name != NULL; this++) {
512  if (this->number == number) {
513  return this->name;
514  }
515  }
516 
517  return def;
518 }
519 
520 char const *fr_token_name(int token)
521 {
522  return fr_int2str(fr_tokens_table, token, "???");
523 }
const bool fr_str_tok[]
Definition: token.c:195
char const * fr_token_name(int token)
Definition: token.c:520
Definition: token.h:47
int getword(char const **ptr, char *buf, int buflen, bool unescape)
Definition: token.c:396
Definition: token.h:34
static char const * name
static FR_TOKEN getthing(char const **ptr, char *buf, int buflen, bool tok, FR_NAME_NUMBER const *tokenlist, bool unescape)
Definition: token.c:243
Definition: token.h:39
Definition: token.h:38
Definition: token.h:46
int number
Definition: token.h:70
Definition: token.h:37
int fr_substr2int(FR_NAME_NUMBER const *table, char const *name, int def, int len)
Definition: token.c:471
Definition: token.h:50
char const * name
Definition: token.h:69
FR_TOKEN gettoken(char const **ptr, char *buf, int buflen, bool unescape)
Definition: token.c:405
Definition: token.h:43
#define TOKEN_MATCH(bptr, tptr)
Definition: token.c:232
Definition: token.h:49
Definition: token.h:44
Definition: token.h:45
int strcasecmp(char *s1, char *s2)
Definition: missing.c:73
Definition: token.h:57
FR_TOKEN getop(char const **ptr)
Definition: token.c:413
Definition: token.h:48
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
Definition: token.c:506
int strncasecmp(char *s1, char *s2, int n)
Definition: missing.c:43
uint8_t token[4]
Definition: eap_pwd.h:625
void fr_strerror_printf(char const *,...) CC_HINT(format(printf
int fr_str2int(FR_NAME_NUMBER const *table, char const *name, int def)
Definition: token.c:451
const FR_NAME_NUMBER fr_tokens_table[]
Definition: token.c:30
const char fr_token_quote[]
Convert tokens back to a quoting character.
Definition: token.c:96
FR_TOKEN getstring(char const **ptr, char *buf, int buflen, bool unescape)
Definition: token.c:429
enum fr_token FR_TOKEN
const bool fr_assignment_op[]
Definition: token.c:129
#define RCSID(id)
Definition: build.h:135
Definition: token.h:51
const bool fr_equality_op[]
Definition: token.c:162
char const * fr_tokens[]
Definition: token.c:60