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