• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/ubox/validate/validate.c

  1 /*
  2  * Copyright (C) 2013 Jo-Philipp Wich <jow@openwrt.org>
  3  *
  4  * This program is free software; you can redistribute it and/or modify
  5  * it under the terms of the GNU Lesser General Public License version 2.1
  6  * as published by the Free Software Foundation
  7  *
  8  * This program is distributed in the hope that it will be useful,
  9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11  * GNU General Public License for more details.
 12  */
 13 
 14 #include <stdio.h>
 15 #include <stdlib.h>
 16 #include <string.h>
 17 #include <stdbool.h>
 18 #include <ctype.h>
 19 
 20 #include <arpa/inet.h>
 21 #include <netinet/ether.h>
 22 #include <sys/stat.h>
 23 
 24 #include <sys/types.h>
 25 #include <regex.h>
 26 
 27 #include <uci.h>
 28 
 29 #include "libvalidate.h"
 30 
 31 enum dt_optype {
 32         OP_UNKNOWN,
 33         OP_NUMBER,
 34         OP_STRING,
 35         OP_FUNCTION
 36 };
 37 
 38 struct dt_fun;
 39 
 40 struct dt_op {
 41         enum dt_optype type;
 42         const char *next;
 43         int length;
 44         int nextop;
 45         union {
 46                 bool boolean;
 47                 double number;
 48                 const char *string;
 49                 struct dt_fun *function;
 50         } value;
 51 };
 52 
 53 struct dt_state {
 54         int pos;
 55         int depth;
 56         struct uci_context *ctx;
 57         const char *value;
 58         enum dt_type valtype;
 59         struct dt_op stack[32];
 60 };
 61 
 62 struct dt_fun {
 63         const char *name;
 64         enum dt_type valtype;
 65         bool (*call)(struct dt_state *s, int nargs);
 66 };
 67 
 68 static bool
 69 dt_test_number(double number, const char *value)
 70 {
 71         char *e;
 72         double n;
 73 
 74         n = strtod(value, &e);
 75 
 76         return (e > value && *e == 0 && n == number);
 77 }
 78 
 79 static bool
 80 dt_test_string(const char *s, const char *end, const char *value)
 81 {
 82         bool esc = false;
 83 
 84         while (*value)
 85         {
 86                 if (s > end)
 87                         return false;
 88 
 89                 if (!esc && *s == '\\')
 90                 {
 91                         s++;
 92 
 93                         if (s >= end)
 94                                 break;
 95 
 96                         esc = true;
 97                         continue;
 98                 }
 99 
100                 if (*s != *value)
101                         return false;
102 
103                 esc = false;
104                 value++;
105                 s++;
106         }
107 
108         return (*s == *value || (s >= end && *value == 0));
109 }
110 
111 static bool
112 dt_step(struct dt_state *s);
113 
114 static bool
115 dt_call(struct dt_state *s);
116 
117 #define dt_getint(n, v) \
118         ((n < nargs && s->stack[s->pos + n].type == OP_NUMBER) \
119                 ? (v = s->stack[s->pos + n].value.number, 1) : 0)
120 
121 static bool
122 dt_type_or(struct dt_state *s, int nargs)
123 {
124         while (nargs--)
125                 if (dt_step(s))
126                         return true;
127 
128         return false;
129 }
130 
131 static bool
132 dt_type_and(struct dt_state *s, int nargs)
133 {
134         while (nargs--)
135                 if (!dt_step(s))
136                         return false;
137 
138         return true;
139 }
140 
141 static bool
142 dt_type_not(struct dt_state *s, int nargs)
143 {
144         if (!nargs)
145                 return false;
146 
147         return !dt_step(s);
148 }
149 
150 static bool
151 dt_type_neg(struct dt_state *s, int nargs)
152 {
153         bool rv;
154         const char *value = s->value;
155 
156         if (!nargs)
157                 return false;
158 
159         if (*s->value == '!')
160                 while (isspace(*++s->value));
161 
162         rv = dt_step(s);
163         s->value = value;
164 
165         return rv;
166 }
167 
168 static bool
169 dt_type_list(struct dt_state *s, int nargs)
170 {
171         bool rv = true;
172         int pos = s->pos;
173         char *p, *str = strdup(s->value);
174         const char *value = s->value;
175 
176         if (!str || !nargs) {
177                 free(str);
178                 return false;
179         }
180 
181         for (p = strtok(str, " \t"); p; p = strtok(NULL, " \t"))
182         {
183                 s->value = p;
184 
185                 if (!dt_step(s))
186                 {
187                         rv = false;
188                         break;
189                 }
190 
191                 s->pos = pos;
192         }
193 
194         s->value = value;
195         free(str);
196 
197         return rv;
198 }
199 
200 static bool
201 dt_type_min(struct dt_state *s, int nargs)
202 {
203         int n;
204         int min = 0;
205         char *e;
206 
207         if (dt_getint(0, min))
208         {
209                 n = strtol(s->value, &e, 0);
210                 return (e > s->value && *e == 0 && n >= min);
211         }
212 
213         return false;
214 }
215 
216 static bool
217 dt_type_max(struct dt_state *s, int nargs)
218 {
219         int n;
220         int max = 0;
221         char *e;
222 
223         if (dt_getint(0, max))
224         {
225                 n = strtol(s->value, &e, 0);
226                 return (e > s->value && *e == 0 && n <= max);
227         }
228 
229         return false;
230 }
231 
232 static bool
233 dt_type_range(struct dt_state *s, int nargs)
234 {
235         int n;
236         int min = 0;
237         int max = 0;
238         char *e;
239 
240         if (dt_getint(0, min) && dt_getint(1, max))
241         {
242                 n = strtol(s->value, &e, 0);
243                 return (e > s->value && *e == 0 && n >= min && n <= max);
244         }
245 
246         return false;
247 }
248 
249 static bool
250 dt_type_minlen(struct dt_state *s, int nargs)
251 {
252         int min = 0;
253 
254         if (dt_getint(0, min))
255                 return (strlen(s->value) >= min);
256 
257         return false;
258 }
259 
260 static bool
261 dt_type_maxlen(struct dt_state *s, int nargs)
262 {
263         int max = 0;
264 
265         if (dt_getint(0, max))
266                 return (strlen(s->value) <= max);
267 
268         return false;
269 }
270 
271 static bool
272 dt_type_rangelen(struct dt_state *s, int nargs)
273 {
274         int min = 0;
275         int max = 0;
276         int len = strlen(s->value);
277 
278         if (dt_getint(0, min) && dt_getint(1, max))
279                 return (len >= min && len <= max);
280 
281         return false;
282 }
283 
284 static bool
285 dt_type_int(struct dt_state *s, int nargs)
286 {
287         char *e;
288         int base = 0;
289 
290         if (!isxdigit(*s->value) && *s->value != '-')
291                 return false;
292 
293         dt_getint(0, base);
294         strtol(s->value, &e, base);
295 
296         return (e > s->value && *e == 0);
297 }
298 
299 static bool
300 dt_type_uint(struct dt_state *s, int nargs)
301 {
302         char *e;
303         int base = 0;
304 
305         if (!isxdigit(*s->value))
306                 return false;
307 
308         dt_getint(0, base);
309         strtoul(s->value, &e, base);
310 
311         return (e > s->value && *e == 0);
312 }
313 
314 static bool
315 dt_type_float(struct dt_state *s, int nargs)
316 {
317         char *e;
318 
319         strtod(s->value, &e);
320 
321         return (e > s->value && *e == 0);
322 }
323 
324 static bool
325 dt_type_ufloat(struct dt_state *s, int nargs)
326 {
327         int n;
328         char *e;
329 
330         n = strtod(s->value, &e);
331 
332         return (e > s->value && *e == 0 && n >= 0.0);
333 }
334 
335 static bool
336 dt_type_bool(struct dt_state *s, int nargs)
337 {
338         int i;
339         const char *values[] = {
340                 "", "off", "false", "no", "disabled",
341                 "1", "on", "true", "yes", "enabled"
342         };
343 
344         for (i = 0; i < sizeof(values) / sizeof(values[0]); i++)
345                 if (!strcasecmp(values[i], s->value))
346                         return true;
347 
348         return false;
349 }
350 
351 static bool
352 dt_type_string(struct dt_state *s, int nargs)
353 {
354         int min = 0;
355         int max = 0;
356         int len = strlen(s->value);
357 
358         if (dt_getint(0, min) && (len < min))
359                 return false;
360 
361         if (dt_getint(1, max) && (len > max))
362                 return false;
363 
364         return true;
365 }
366 
367 static bool
368 dt_type_hexstring(struct dt_state *s, int nargs)
369 {
370         int min = 0;
371         int max = 0;
372         int len = strlen(s->value);
373         const char *p;
374 
375         if (len % 2)
376                 return false;
377 
378         if (dt_getint(0, min) && (len < min))
379                 return false;
380 
381         if (dt_getint(1, max) && (len > max))
382                 return false;
383 
384         for (p = s->value; *p; p++)
385                 if (!isxdigit(*p))
386                         return false;
387 
388         return true;
389 }
390 
391 static bool
392 dt_type_ip4addr(struct dt_state *s, int nargs)
393 {
394         struct in6_addr a;
395         return inet_pton(AF_INET, s->value, &a);
396 }
397 
398 static bool
399 dt_type_ip6addr(struct dt_state *s, int nargs)
400 {
401         struct in6_addr a;
402         return inet_pton(AF_INET6, s->value, &a);
403 }
404 
405 static bool
406 dt_type_ipaddr(struct dt_state *s, int nargs)
407 {
408         return (dt_type_ip4addr(s, 0) || dt_type_ip6addr(s, 0));
409 }
410 
411 static bool
412 dt_type_netmask4(struct dt_state *s, int nargs)
413 {
414         int i;
415         struct in_addr a;
416 
417         if (!inet_pton(AF_INET, s->value, &a))
418                 return false;
419 
420         if (a.s_addr == 0)
421                 return true;
422 
423         a.s_addr = ntohl(a.s_addr);
424 
425         for (i = 0; (i < 32) && !(a.s_addr & (1 << i)); i++);
426 
427         return ((uint32_t)(~((1 << i) - 1)) == a.s_addr);
428 }
429 
430 static bool
431 dt_type_netmask6(struct dt_state *s, int nargs)
432 {
433         int i;
434         struct in6_addr a;
435 
436         if (!inet_pton(AF_INET6, s->value, &a))
437                 return false;
438 
439         for (i = 0; (i < 16) && (a.s6_addr[i] == 0xFF); i++);
440 
441         if (i == 16)
442                 return true;
443 
444         if ((a.s6_addr[i] != 255) && (a.s6_addr[i] != 254) &&
445                 (a.s6_addr[i] != 252) && (a.s6_addr[i] != 248) &&
446                 (a.s6_addr[i] != 240) && (a.s6_addr[i] != 224) &&
447                 (a.s6_addr[i] != 192) && (a.s6_addr[i] != 128) &&
448                 (a.s6_addr[i] != 0))
449                 return false;
450 
451         for (; (i < 16) && (a.s6_addr[i] == 0); i++);
452 
453         return (i == 16);
454 }
455 
456 static bool
457 dt_type_cidr4(struct dt_state *s, int nargs)
458 {
459         int n;
460         struct in_addr a;
461         char *p, buf[sizeof("255.255.255.255/32\0")];
462 
463         if (strlen(s->value) >= sizeof(buf))
464                 return false;
465 
466         strcpy(buf, s->value);
467         p = strchr(buf, '/');
468 
469         if (p)
470         {
471                 *p++ = 0;
472 
473                 n = strtoul(p, &p, 10);
474 
475                 if ((*p != 0) || (n > 32))
476                         return false;
477         }
478 
479         return inet_pton(AF_INET, buf, &a);
480 }
481 
482 static bool
483 dt_type_cidr6(struct dt_state *s, int nargs)
484 {
485         int n;
486         struct in6_addr a;
487         char *p, buf[sizeof("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255/128\0")];
488 
489         if (strlen(s->value) >= sizeof(buf))
490                 return false;
491 
492         strcpy(buf, s->value);
493         p = strchr(buf, '/');
494 
495         if (p)
496         {
497                 *p++ = 0;
498 
499                 n = strtoul(p, &p, 10);
500 
501                 if ((*p != 0) || (n > 128))
502                         return false;
503         }
504 
505         return inet_pton(AF_INET6, buf, &a);
506 }
507 
508 static bool
509 dt_type_cidr(struct dt_state *s, int nargs)
510 {
511         return (dt_type_cidr4(s, 0) || dt_type_cidr6(s, 0));
512 }
513 
514 static bool
515 dt_type_ipmask4(struct dt_state *s, int nargs)
516 {
517         bool rv;
518         struct in_addr a;
519         const char *value;
520         char *p, buf[sizeof("255.255.255.255/255.255.255.255\0")];
521 
522         if (strlen(s->value) >= sizeof(buf))
523                 return false;
524 
525         strcpy(buf, s->value);
526         p = strchr(buf, '/');
527 
528         if (p)
529         {
530                 *p++ = 0;
531 
532                 value = s->value;
533                 s->value = p;
534                 rv = dt_type_netmask4(s, 0);
535                 s->value = value;
536 
537                 if (!rv)
538                         return false;
539         }
540 
541         return inet_pton(AF_INET, buf, &a);
542 }
543 
544 static bool
545 dt_type_ipmask6(struct dt_state *s, int nargs)
546 {
547         bool rv;
548         struct in6_addr a;
549         const char *value;
550         char *p, buf[sizeof("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255/"
551                             "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255\0")];
552 
553         if (strlen(s->value) >= sizeof(buf))
554                 return false;
555 
556         strcpy(buf, s->value);
557         p = strchr(buf, '/');
558 
559         if (p)
560         {
561                 *p++ = 0;
562 
563                 value = s->value;
564                 s->value = p;
565                 rv = dt_type_netmask6(s, 0);
566                 s->value = value;
567 
568                 if (!rv)
569                         return false;
570         }
571 
572         return inet_pton(AF_INET6, buf, &a);
573 }
574 
575 static bool
576 dt_type_ipmask(struct dt_state *s, int nargs)
577 {
578         return (dt_type_ipmask4(s, 0) || dt_type_ipmask6(s, 0));
579 }
580 
581 static bool
582 dt_type_port(struct dt_state *s, int nargs)
583 {
584         int n;
585         char *e;
586 
587         n = strtoul(s->value, &e, 10);
588 
589         return (e > s->value && *e == 0 && n <= 65535);
590 }
591 
592 static bool
593 dt_type_portrange(struct dt_state *s, int nargs)
594 {
595         int n, m;
596         char *e;
597 
598         n = strtoul(s->value, &e, 10);
599 
600         if (e == s->value || *e != '-') {
601                 // If parsing as portrange fails, try parsing as a single port
602                 return dt_type_port(s, nargs);
603         }
604 
605         m = strtoul(e + 1, &e, 10);
606 
607         return (*e == 0 && n <= 65535 && m <= 65535 && n <= m);
608 }
609 
610 static bool
611 dt_type_macaddr(struct dt_state *s, int nargs)
612 {
613         return !!ether_aton(s->value);
614 }
615 
616 static bool
617 dt_type_uciname(struct dt_state *s, int nargs)
618 {
619         const char *p;
620 
621         for (p = s->value;
622              *p && ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
623                     (*p >= '' && *p <= '9') || (*p == '_'));
624                  p++);
625 
626         return (*p == 0);
627 }
628 
629 static bool
630 dt_type_wpakey(struct dt_state *s, int nargs)
631 {
632         int len = strlen(s->value);
633         const char *p = s->value;
634 
635         if (len == 64)
636         {
637                 while (isxdigit(*p))
638                         p++;
639 
640                 return (*p == 0);
641         }
642 
643         return (len >= 8 && len <= 63);
644 }
645 
646 static bool
647 dt_type_wepkey(struct dt_state *s, int nargs)
648 {
649         int len = strlen(s->value);
650         const char *p = s->value;
651 
652         if (!strncmp(p, "s:", 2))
653         {
654                 len -= 2;
655                 p += 2;
656         }
657 
658         if (len == 10 || len == 26)
659         {
660                 while (isxdigit(*p))
661                         p++;
662 
663                 return (*p == 0);
664         }
665 
666         return (len == 5 || len == 13);
667 }
668 
669 static bool
670 dt_type_hostname(struct dt_state *s, int nargs)
671 {
672         const char *p, *last;
673 
674         for (p = last = s->value; *p; p++)
675         {
676                 if (*p == '.')
677                 {
678                         if ((p - last) == 0 || (p - last) > 63)
679                                 return false;
680 
681                         last = p + 1;
682                         continue;
683                 }
684                 else if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') ||
685                          (*p >= '' && *p <= '9') || (*p == '_') || (*p == '-'))
686                 {
687                         continue;
688                 }
689 
690                 return false;
691         }
692 
693         return ((p - last) > 0 && (p - last) <= 255);
694 }
695 
696 static bool
697 dt_type_host(struct dt_state *s, int nargs)
698 {
699         return (dt_type_hostname(s, 0) || dt_type_ipaddr(s, 0));
700 }
701 
702 static bool
703 dt_type_network(struct dt_state *s, int nargs)
704 {
705         return (dt_type_uciname(s, 0) || dt_type_host(s, 0));
706 }
707 
708 static bool
709 dt_type_phonedigit(struct dt_state *s, int nargs)
710 {
711         const char *p;
712 
713         for (p = s->value;
714              *p && ((*p >= '' && *p <= '9') || (*p == '*') || (*p == '#') ||
715                     (*p == '!') || (*p == '.'));
716                  p++);
717 
718         return (*p == 0);
719 }
720 
721 static bool
722 dt_type_directory(struct dt_state *s, int nargs)
723 {
724         struct stat st;
725         return (!stat(s->value, &st) && S_ISDIR(st.st_mode));
726 }
727 
728 
729 static bool
730 dt_type_device(struct dt_state *s, int nargs)
731 {
732         struct stat st;
733         return (!stat(s->value, &st) &&
734                 (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)));
735 }
736 
737 static bool
738 dt_type_file(struct dt_state *s, int nargs)
739 {
740         struct stat st;
741         return (!stat(s->value, &st) && S_ISREG(st.st_mode));
742 }
743 
744 static bool
745 dt_type_regex(struct dt_state *s, int nargs)
746 {
747         bool rv;
748         int relen;
749         regex_t pattern;
750         char *re = NULL;
751 
752         if (nargs < 1 || s->stack[s->pos].type != OP_STRING)
753                 return false;
754 
755         relen = s->stack[s->pos].length;
756         re = alloca(relen + 3);
757 
758         if (!re)
759                 return false;
760 
761         memset(re, 0, relen + 3);
762         memcpy(re + 1, s->stack[s->pos].value.string, relen);
763 
764         re[0] = '^';
765         re[relen + 1] = '$';
766 
767         if (regcomp(&pattern, re, REG_EXTENDED | REG_NOSUB))
768                 return false;
769 
770         rv = !regexec(&pattern, s->value, 0, NULL, 0);
771 
772         regfree(&pattern);
773 
774         return rv;
775 }
776 
777 static void *
778 dt_uci_lookup(struct dt_state *s, const char *pkg,
779               const char *sct, const char *opt, enum uci_type type)
780 {
781         struct uci_ptr ptr = {
782                 .package = pkg,
783                 .section = sct,
784                 .option  = opt
785         };
786 
787         if (!s->ctx || uci_lookup_ptr(s->ctx, &ptr, NULL, false) ||
788             !(ptr.flags & UCI_LOOKUP_COMPLETE))
789                 return NULL;
790 
791         if (ptr.last->type != type)
792                 return NULL;
793 
794         switch (type)
795         {
796         case UCI_TYPE_PACKAGE:
797                 return uci_to_package(ptr.last);
798 
799         case UCI_TYPE_SECTION:
800                 return uci_to_section(ptr.last);
801 
802         case UCI_TYPE_OPTION:
803                 return uci_to_option(ptr.last);
804 
805         default:
806                 return NULL;
807         }
808 }
809 
810 static bool
811 dt_uci_cmp(struct dt_state *s,
812            const char *pkg, const char *sct, const char *opt)
813 {
814         struct uci_element *e;
815         struct uci_option *o = dt_uci_lookup(s, pkg, sct, opt, UCI_TYPE_OPTION);
816 
817         if (!o)
818                 return false;
819 
820         switch (o->type)
821         {
822         case UCI_TYPE_STRING:
823                 if (!strcmp(s->value, o->v.string))
824                         return true;
825                 break;
826 
827         case UCI_TYPE_LIST:
828                 uci_foreach_element(&o->v.list, e)
829                         if (!strcmp(s->value, e->name))
830                                 return true;
831                 break;
832         }
833 
834         return false;
835 }
836 
837 static bool
838 dt_type_uci(struct dt_state *s, int nargs)
839 {
840         int i, len;
841         struct uci_element *e;
842         struct uci_package *p;
843         char *cso[3] = { };
844 
845         if (!s->ctx)
846                 return false;
847 
848         for (i = 0; i < nargs && i < 3; i++)
849         {
850                 if (s->stack[s->pos + i].type != OP_STRING)
851                         continue;
852 
853                 len = s->stack[s->pos + i].length;
854                 cso[i] = alloca(len + 1);
855 
856                 if (!cso[i])
857                         continue;
858 
859                 memset(cso[i], 0, len + 1);
860                 memcpy(cso[i], s->stack[s->pos + i].value.string, len);
861         }
862 
863         if (!cso[0] || !cso[1] || (*cso[1] != '@' && !cso[2]))
864                 return false;
865 
866         if (*cso[1] != '@')
867                 return dt_uci_cmp(s, cso[0], cso[1], cso[2]);
868 
869         p = dt_uci_lookup(s, cso[0], NULL, NULL, UCI_TYPE_PACKAGE);
870 
871         if (!p)
872                 return false;
873 
874         uci_foreach_element(&p->sections, e)
875         {
876                 if (strcmp(uci_to_section(e)->type, cso[1] + 1))
877                         continue;
878 
879                 if (!cso[2])
880                 {
881                         if (!strcmp(s->value, e->name))
882                                 return true;
883                 }
884                 else
885                 {
886                         if (dt_uci_cmp(s, cso[0], e->name, cso[2]))
887                                 return true;
888                 }
889         }
890 
891         return false;
892 }
893 
894 
895 static struct dt_fun dt_types[] = {
896         { "or",                 DT_INVALID,     dt_type_or              },
897         { "and",                DT_INVALID,     dt_type_and             },
898         { "not",                DT_INVALID,     dt_type_not             },
899         { "neg",                DT_INVALID,     dt_type_neg             },
900         { "list",               DT_INVALID,     dt_type_list            },
901         { "min",                DT_NUMBER,      dt_type_min             },
902         { "max",                DT_NUMBER,      dt_type_max             },
903         { "range",              DT_NUMBER,      dt_type_range           },
904         { "minlength",          DT_STRING,      dt_type_minlen          },
905         { "maxlength",          DT_STRING,      dt_type_maxlen          },
906         { "rangelength",        DT_STRING,      dt_type_rangelen        },
907         { "integer",            DT_NUMBER,      dt_type_int             },
908         { "uinteger",           DT_NUMBER,      dt_type_uint            },
909         { "float",              DT_NUMBER,      dt_type_float           },
910         { "ufloat",             DT_NUMBER,      dt_type_ufloat          },
911         { "bool",               DT_BOOL,        dt_type_bool            },
912         { "string",             DT_STRING,      dt_type_string          },
913         { "hexstring",          DT_STRING,      dt_type_hexstring       },
914         { "ip4addr",            DT_STRING,      dt_type_ip4addr         },
915         { "ip6addr",            DT_STRING,      dt_type_ip6addr         },
916         { "ipaddr",             DT_STRING,      dt_type_ipaddr          },
917         { "cidr4",              DT_STRING,      dt_type_cidr4           },
918         { "cidr6",              DT_STRING,      dt_type_cidr6           },
919         { "cidr",               DT_STRING,      dt_type_cidr            },
920         { "netmask4",           DT_STRING,      dt_type_netmask4        },
921         { "netmask6",           DT_STRING,      dt_type_netmask6        },
922         { "ipmask4",            DT_STRING,      dt_type_ipmask4         },
923         { "ipmask6",            DT_STRING,      dt_type_ipmask6         },
924         { "ipmask",             DT_STRING,      dt_type_ipmask          },
925         { "port",               DT_NUMBER,      dt_type_port            },
926         { "portrange",          DT_STRING,      dt_type_portrange       },
927         { "macaddr",            DT_STRING,      dt_type_macaddr         },
928         { "uciname",            DT_STRING,      dt_type_uciname         },
929         { "wpakey",             DT_STRING,      dt_type_wpakey          },
930         { "wepkey",             DT_STRING,      dt_type_wepkey          },
931         { "hostname",           DT_STRING,      dt_type_hostname        },
932         { "host",               DT_STRING,      dt_type_host            },
933         { "network",            DT_STRING,      dt_type_network         },
934         { "phonedigit",         DT_STRING,      dt_type_phonedigit      },
935         { "directory",          DT_STRING,      dt_type_directory       },
936         { "device",             DT_STRING,      dt_type_device          },
937         { "file",               DT_STRING,      dt_type_file            },
938         { "regex",              DT_STRING,      dt_type_regex           },
939         { "uci",                DT_STRING,      dt_type_uci             },
940 
941         { }
942 };
943 
944 static struct dt_fun *
945 dt_lookup_function(const char *s, const char *e)
946 {
947         struct dt_fun *fun = dt_types;
948 
949         while (fun->name)
950         {
951                 if (!strncmp(fun->name, s, e - s) && *(fun->name + (e - s)) == '\0')
952                         return fun;
953 
954                 fun++;
955         }
956 
957         return NULL;
958 }
959 
960 static bool
961 dt_parse_atom(struct dt_state *s, const char *label, const char *end)
962 {
963         char q, *e;
964         const char *p;
965         bool esc;
966         double dval;
967         struct dt_fun *func;
968         struct dt_op *op = &s->stack[s->depth];
969 
970         if ((s->depth + 1) >= (sizeof(s->stack) / sizeof(s->stack[0])))
971         {
972                 printf("Syntax error, expression too long\n");
973                 return false;
974         }
975 
976         while (isspace(*label))
977                 label++;
978 
979         /* test whether label is a float */
980         dval = strtod(label, &e);
981 
982         if (e > label)
983         {
984                 op->next = e;
985                 op->type = OP_NUMBER;
986                 op->value.number = dval;
987                 op->nextop = ++s->depth;
988 
989                 return true;
990         }
991         else if ((*label == '"') || (*label == '\''))
992         {
993                 for (p = label + 1, q = *label, esc = false; p <= end; p++)
994                 {
995                         if (esc)
996                         {
997                                 esc = false;
998                                 continue;
999                         }
1000                         else if (*p == '\\')
1001                         {
1002                                 esc = true;
1003                                 continue;
1004                         }
1005                         else if (*p == q)
1006                         {
1007                                 op->next = p + 1;
1008                                 op->type = OP_STRING;
1009                                 op->length = (p - label) - 1;
1010                                 op->value.string = label + 1;
1011                                 op->nextop = ++s->depth;
1012 
1013                                 return true;
1014                         }
1015                 }
1016 
1017                 printf("Syntax error, unterminated string\n");
1018                 return false;
1019         }
1020         else if (*label)
1021         {
1022                 for (p = label;
1023                      p <= end && ((*p >= 'A' && *p <= 'Z') ||
1024                                   (*p >= 'a' && *p <= 'z') ||
1025                                   (*p >= '' && *p <= '9') ||
1026                                   (*p == '_'));
1027                      p++);
1028 
1029                 func = dt_lookup_function(label, p);
1030 
1031                 if (!func)
1032                 {
1033                         printf("Syntax error, unrecognized function\n");
1034                         return false;
1035                 }
1036 
1037                 op->next = p;
1038                 op->type = OP_FUNCTION;
1039                 op->value.function = func;
1040                 op->nextop = ++s->depth;
1041 
1042                 return true;
1043         }
1044 
1045         printf("Syntax error, unexpected EOF\n");
1046         return false;
1047 }
1048 
1049 static bool
1050 dt_parse_list(struct dt_state *s, const char *code, const char *end);
1051 
1052 static bool
1053 dt_parse_expr(const char *code, const char *end, struct dt_state *s)
1054 {
1055         struct dt_op *tok;
1056 
1057         if (!dt_parse_atom(s, code, end))
1058                 return false;
1059 
1060         tok = &s->stack[s->depth - 1];
1061 
1062         while (isspace(*tok->next))
1063                 tok->next++;
1064 
1065         if (tok->type == OP_FUNCTION)
1066         {
1067                 if (*tok->next == '(')
1068                 {
1069                         end--;
1070 
1071                         while (isspace(*end) && end > tok->next + 1)
1072                                 end--;
1073 
1074                         return dt_parse_list(s, tok->next + 1, end);
1075                 }
1076                 else if (tok->next == end)
1077                 {
1078                         return dt_parse_list(s, tok->next, tok->next);
1079                 }
1080 
1081                 printf("Syntax error, expected '(' or EOF after function label\n");
1082                 return false;
1083         }
1084         else if (tok->next == end)
1085         {
1086                 return true;
1087         }
1088 
1089         printf("Syntax error, expected ',' after literal\n");
1090         return false;
1091 }
1092 
1093 static bool
1094 dt_parse_list(struct dt_state *s, const char *code, const char *end)
1095 {
1096         char c;
1097         bool esc;
1098         int nest;
1099         const char *p, *last;
1100         struct dt_op *fptr;
1101 
1102         if (!code)
1103                 return false;
1104 
1105         fptr = &s->stack[s->depth - 1];
1106 
1107         for (nest = 0, p = last = code, esc = false, c = *p;
1108              p <= end;
1109              p++, c = (p < end) ? *p : '\0')
1110         {
1111                 if (esc)
1112                 {
1113                         esc = false;
1114                         continue;
1115                 }
1116 
1117                 switch (c)
1118                 {
1119                 case '\\':
1120                         esc = true;
1121                         break;
1122 
1123                 case '(':
1124                         nest++;
1125                         break;
1126 
1127                 case ')':
1128                         nest--;
1129                         break;
1130 
1131                 case ',':
1132                 case '\0':
1133                         if (nest <= 0)
1134                         {
1135                                 if (p > last)
1136                                 {
1137                                         if (!dt_parse_expr(last, p, s))
1138                                                 return false;
1139 
1140                                         fptr->length++;
1141                                 }
1142 
1143                                 last = p + 1;
1144                         }
1145 
1146                         break;
1147                 }
1148         }
1149 
1150         fptr->nextop = s->depth;
1151         return true;
1152 }
1153 
1154 static bool
1155 dt_step(struct dt_state *s)
1156 {
1157         bool rv;
1158         struct dt_op *op = &s->stack[s->pos];
1159 
1160         switch (op->type)
1161         {
1162         case OP_NUMBER:
1163                 rv = dt_test_number(op->value.number, s->value);
1164                 if (rv)
1165                         s->valtype = DT_NUMBER;
1166                 break;
1167 
1168         case OP_STRING:
1169                 rv = dt_test_string(op->value.string, op->value.string + op->length, s->value);
1170                 if (rv)
1171                         s->valtype = DT_STRING;
1172                 break;
1173 
1174         case OP_FUNCTION:
1175                 rv = dt_call(s);
1176                 break;
1177 
1178         default:
1179                 rv = false;
1180                 break;
1181         }
1182 
1183         s->pos = op->nextop;
1184         return rv;
1185 }
1186 
1187 static bool
1188 dt_call(struct dt_state *s)
1189 {
1190         bool rv;
1191         struct dt_op *fptr = &s->stack[s->pos];
1192         struct dt_fun *func = fptr->value.function;
1193 
1194         s->pos++;
1195 
1196         rv = func->call(s, fptr->length);
1197 
1198         if (rv && func->valtype)
1199                 s->valtype = func->valtype;
1200 
1201         s->pos = fptr->nextop;
1202 
1203         return rv;
1204 }
1205 
1206 enum dt_type
1207 dt_parse(const char *code, const char *value)
1208 {
1209         enum dt_type rv = DT_INVALID;
1210 
1211         struct dt_state s = {
1212                 .depth = 1,
1213                 .stack = {
1214                         {
1215                                 .type = OP_FUNCTION,
1216                                 .value.function = &dt_types[0],
1217                                 .next = code
1218                         }
1219                 }
1220         };
1221 
1222         if (!value || !*value)
1223                 return false;
1224 
1225         if (!dt_parse_list(&s, code, code + strlen(code)))
1226                 return false;
1227 
1228         s.ctx = uci_alloc_context();
1229         s.value = value;
1230 
1231         if (dt_call(&s))
1232                 rv = s.valtype;
1233 
1234         if (s.ctx)
1235                 uci_free_context(s.ctx);
1236 
1237         return rv;
1238 }
1239 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt