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