validate: range and base arguments for numeric types, new types hexstring, regexp...
[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",
334 "1", "on", "true", "yes"
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 }