1 // Copyright (C) 1995-1999 David Sugar, Tycho Softworks.
2 // Copyright (C) 1999-2005 Open Source Telecom Corp.
3 // Copyright (C) 2005-2011 David Sugar, Tycho Softworks.
4 //
5 // This file is part of GNU Bayonne.
6 //
7 // GNU Bayonne is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // GNU Bayonne is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with GNU Bayonne. If not, see <http://www.gnu.org/licenses/>.
19
20 #include <config.h>
21 #include <ucommon/ucommon.h>
22 #include <ucommon/export.h>
24 #include <ctype.h>
25
26 #ifdef HAVE_REGEX_H
27 #include <regex.h>
28 #endif
29
30 #ifdef __MINGW32__
31 #define NUM_FORMAT "%lld"
32 #else
33 #define NUM_FORMAT "%ld"
34 #endif
35
37 using namespace UCOMMON_NAMESPACE;
38
39 Script::interp::interp() :
40 memalloc(Script::paging)
41 {
42 }
43
44 Script::interp::~interp()
45 {
46 detach();
47 }
48
49 void Script::interp::initialize(void)
50 {
51 unsigned tempcount = sizeof(temps) / sizeof(char *);
52 unsigned pos = 0;;
53
54 frame = 0;
55 tempindex = 0;
56
57 purge();
58
59 image = NULL;
60 stack = (Script::stack_t *)alloc(sizeof(Script::stack_t) * Script::stacking);
61 syms = (LinkedObject **)alloc(sizeof(LinkedObject *) * Script::indexing);
62 memset(syms, 0, sizeof(Script::symbol *) * Script::indexing);
63 while(pos < tempcount)
64 temps[pos++] = (char *)alloc(Script::sizing + 1);
65
66 errmsg = NULL;
67 Script::symbol *err = createSymbol("error:64");
68 if(err)
69 errmsg = err->data;
70 }
71
72 bool Script::interp::error(const char *msg)
73 {
74 #ifndef _MSWINDOWS_
75 if(getppid() > 1)
76 fprintf(stderr, "*** %s(%d): %s\n", image->filename, stack[frame].line->lnum, msg);
77 #endif
78
79 if(errmsg)
80 String::set(errmsg, 65, msg);
81
82 if(!eq(stack[frame].scr->name, "_init_")) {
83 if(scriptEvent("error"))
84 return false;
85 }
86
87 skip();
88 return true;
89 }
90
91 char *Script::interp::getTemp(void)
92 {
93 unsigned tempcount = sizeof(temps) / sizeof(char *);
94
95 char *ptr = temps[tempindex++];
96 if(tempindex >= tempcount)
97 tempindex = 0;
98 return ptr;
99 }
100
101 const char *Script::interp::getFormat(Script::symbol *sym, const char *id, char *tp)
102 {
103 #ifdef __MINGW32__
104 long long val;
105 #else
106 long val;
107 #endif
108
109 static char null[1] = {0};
110
111 unsigned dcount = 0, pos;
112 char *cp;
113 char *ep;
114 char idbuf[32];
115 unsigned len;
116 char quote = 0;
117 Script::symbol *index = NULL;
118 unsigned paren = 0;
119
120 cp = sym->data;
121 while(isspace(*cp))
122 ++cp;
123
124 if(eq(id, "len:", 4))
125 snprintf(tp, Script::sizing + 1, "%u", (unsigned)strlen(sym->data));
126 else if(eq(id, "key:", 4)) {
127 String::set(tp, Script::sizing + 1, cp);
128 ep = strchr(tp, '=');
129 if(ep)
130 *ep = 0;
131 else
132 String::set(tp, 2, "-");
133 }
134 else if(eq(id, "tail:", 5)) {
135 dcount = Script::count(sym->data);
136 if(dcount)
137 String::set(tp, Script::sizing + 1, Script::get(cp, --dcount));
138 else
139 tp[0] = 0;
140 }
141 else if(eq(id, "head:", 5)) {
142 String::set(tp, Script::sizing + 1, sym->data);
143 if(Script::count(tp) > 1) {
144 dcount = Script::offset(tp, 1);
145 if(dcount)
146 tp[--dcount] = 0;
147 }
148 }
149 else if(eq(id, "pull:", 5) || eq(id, "<<:", 3)) {
150 String::set(tp, Script::sizing + 1, sym->data);
151 if(Script::count(tp) > 1) {
152 dcount = Script::offset(tp, 1);
153 if(dcount) {
154 memcpy(sym->data, sym->data + dcount, strlen(sym->data + dcount) + 1);
155 tp[--dcount] = 0;
156 }
157 }
158 }
159 else if(eq(id, "pop:", 4) || eq(id, ">>:", 3)) {
160 dcount = Script::count(sym->data);
161 if(dcount) {
162 String::set(tp, Script::sizing + 1, Script::get(sym->data, --dcount));
163 if(dcount) {
164 dcount = Script::offset(sym->data, dcount);
165 sym->data[--dcount] = 0;
166 }
167 else
168 sym->data[0] = 0;
169 }
170 else
171 tp[0] = 0;
172 }
173 else if(eq(id, "val:", 4) && (*cp == '\'' || *cp == '\"' || *cp == '(')) {
174 String::set(tp, Script::sizing + 1, cp + 1);
175 if(*cp == '(')
176 ep = strrchr(tp, ')');
177 else
178 ep = strchr(tp, *cp);
179 if(ep)
180 *ep = 0;
181 }
182 else if(eq(id, "val:", 4) && strchr(sym->data, '=')) {
183 cp = strchr(sym->data, '=') + 1;
184 if(*cp == '\"' || *cp == '\'') {
185 String::set(tp, Script::sizing + 1, cp + 1);
186 ep = strchr(tp, *cp);
187 if(ep)
188 *ep = 0;
189 }
190 else {
191 String::set(tp, Script::sizing + 1, cp);
192 ep = strchr(tp, ',');
193 if(ep)
194 *ep = 0;
195 }
196 }
197 else if(eq(id, "unquote:", 8) && sym->size) {
198 cp = sym->data;
199 while(isspace(*cp))
200 ++cp;
201 if(*cp == '(') {
202 ++cp;
203 ep = strrchr(cp, ')');
204 if(ep)
205 *ep = 0;
206 }
207 else if(*cp == '\"' || *cp == '\'') {
208 ep = strchr(cp + 1, *cp);
209 if(ep)
210 *ep = 0;
211 ++cp;
212 }
213 String::set(sym->data, sym->size + 1, cp);
214 return sym->data;
215 }
216 else if(eq(id, "upper:", 6) && sym->size) {
217 String::upper(sym->data);
218 return sym->data;
219 }
220 else if(eq(id, "lower:", 6) && sym->size) {
221 String::lower(sym->data);
222 return sym->data;
223 }
224 else if((eq(id, "inc:", 4) || eq(id, "++:", 3)) && sym->size) {
225 val = atol(cp);
226 snprintf(sym->data, sym->size + 1,
NUM_FORMAT, ++val);
227 return sym->data;
228 }
229 else if(eq(id, "count:", 6))
230 snprintf(tp, Script::sizing + 1, "%u", Script::count(sym->data));
231 else if(eq(id, "index/", 6)) {
232 id += 6;
233 pos = atoi(id);
234 if(pos)
235 --pos;
236 else
237 return "";
238 if(pos < strlen(sym->data))
239 cp = sym->data + pos;
240 else
241 cp = null;
242 Script::copy(cp, tp, Script::sizing);
243 }
244 else if(eq(id, "offset/", 7)) {
245 id += 7;
246 pos = atoi(id);
247 if(pos)
248 --pos;
249 else
250 return "";
251 offset:
252 cp = Script::get(sym->data, pos);
253 Script::copy(cp, tp, Script::sizing);
254 }
255 else if((eq(id, "dec:", 4) || eq(id, "--:", 3)) && sym->size) {
256 val = atoi(cp);
257 snprintf(sym->data, sym->size + 1,
NUM_FORMAT, --val);
258 return sym->data;
259 }
260 else if(eq(id, "size:", 5))
261 snprintf(tp, Script::sizing + 1, "%d", sym->size);
262 else if(eq(id, "val:", 4) || eq(id, "int:", 4)) {
263 val = atol(cp);
264 snprintf(tp, Script::sizing + 1,
NUM_FORMAT, val);
265 }
266 else if(eq(id, "num:", 4)) {
267 val = atol(cp);
268 snprintf(tp, Script::sizing + 1,
NUM_FORMAT, val);
269 if(Script::decimals)
270 String::add(tp, Script::sizing + 1, ".");
271 pos = strlen(tp);
272 cp = strchr(sym->data, '.');
273 if(cp)
274 ++cp;
275 else
276 cp = null;
277 while(dcount++ < Script::decimals && pos < Script::sizing) {
278 if(*cp && isdigit(*cp))
279 tp[pos++] = *(cp++);
280 else
281 tp[pos++] = '0';
282 }
283 tp[pos] = 0;
284 }
285 else if(eq(id, "map/", 4)) {
286 idbuf[0] = '%';
287 String::set(idbuf, sizeof(idbuf), id + 4);
288 ep = strchr(idbuf, ':');
289 if(ep)
290 *ep = 0;
291 index = find(idbuf);
292 if(!index || !index->data[0])
293 return "";
294 pos = atoi(sym->data);
295 if(pos)
296 goto offset;
297 snprintf(idbuf, sizeof(idbuf), ",%s", sym->data);
298 paren = 0;
299 goto search;
300 }
301 else if(eq(id, "find/", 5)) {
302 id += 5;
303 paren = 0;
304 dcount = 1;
305 idbuf[0] = ',';
306 while(dcount < 30 && *id && *id != ':')
307 idbuf[dcount++] = *(id++);
308 idbuf[dcount++] = '=';
309 idbuf[dcount] = 0;
310 search:
311 cp = sym->data;
312 len = strlen(idbuf);
313 if(!strncmp(cp, idbuf + 1, len - 1))
314 cp = sym->data + len - 1;
315 else if(NULL != (cp = strstr(sym->data, idbuf)))
316 cp = cp + len;
317 else
318 cp = null;
319 dcount = 0;
320 if(*cp == '\"') {
321 quote = *cp;
322 ++cp;
323 }
324 else if(*cp == '(') {
325 paren = 1;
326 ++cp;
327 }
328 else
329 quote=',';
330 while(dcount < Script::sizing && *cp && *cp != quote) {
331 if(*cp == '(' && paren)
332 ++paren;
333 if(*cp == ')' && paren) {
334 if(paren-- == 1)
335 break;
336 }
337 if(*cp == '=' && quote == ',' && cp[1] == '\"') {
338 tp[dcount++] = *(cp++);
339 quote = *(cp++);
340 }
341 else
342 tp[dcount++] = *(cp++);
343 }
344 tp[dcount] = 0;
345 }
346 else if(eq(id, "bool:", 5)) {
347 if(atoi(sym->data) > 0 || tolower(sym->data[0]) == 't' || tolower(sym->data[0] == 'y'))
348 snprintf(tp, Script::sizing + 1, "true");
349 else
350 snprintf(tp, Script::sizing + 1, "false");
351 }
352 return tp;
353 }
354
355 const char *Script::interp::getContent(const char *cp)
356 {
357 Script::symbol *sym;
358 const char *id;
359 char *tp;
360
361 if(!cp)
362 return NULL;
363
364 switch(*cp) {
365 case '$':
366 tp = getTemp();
367 id = strchr(cp, ':');
368 if(id) {
369 sym = find(++id);
370 if(!sym)
371 return "";
372 *tp = 0;
373 return getFormat(sym, ++cp, tp);
374 }
375 case '%':
376 if(eq(cp, "%index"))
377 return getIndex();
378 sym = find(++cp);
379 if(sym)
380 return sym->data;
381 else
382 return "";
383 case '&':
384 case '=':
385 case '+':
386 if(cp[1] && cp[1] != '=')
387 return ++cp;
388 }
389 return cp;
390 }
391
392 const char *Script::interp::getKeyword(const char *id)
393 {
394 line_t *line = stack[frame].line;
395 unsigned index = 0;
396 const char *cp;
397
398 while(index < line->argc) {
399 cp = line->argv[index++];
400 if(*cp == '=') {
401 if(eq(id, ++cp))
402 return getContent(line->argv[index]);
403 ++index;
404 }
405 }
406 return NULL;
407 }
408
409 const char *Script::interp::getIndex(void)
410 {
411 method_t method;
412
413 unsigned pos = frame;
414 while(pos) {
415 method = stack[--pos].line->method;
416 if(method == (method_t)&Script::methods::scrForeach) {
417 char *temp = getTemp();
418 snprintf(temp, Script::sizing, "%d", stack[pos].index);
419 return temp;
420 }
421 }
422 return "0";
423 }
424
425 Script::method_t Script::interp::getLooping(void)
426 {
427 if(!frame)
428 return (method_t)NULL;
429
430 return stack[frame - 1].line->method;
431 }
432
433 const char *Script::interp::getContent(void)
434 {
435 const char *cp;
436 line_t *line = stack[frame].line;
437 while(stack[frame].index < line->argc) {
438 cp = line->argv[stack[frame].index++];
439 switch(*cp) {
440 case '=':
441 ++stack[frame].index;
442 break;
443 default:
444 return cp;
445 }
446 }
447 return NULL;
448 }
449
450 const char *Script::interp::getValue(void)
451 {
452 const char *cp;
453 line_t *line = stack[frame].line;
454 while(stack[frame].index < line->argc) {
455 cp = line->argv[stack[frame].index++];
456 switch(*cp) {
457 case '=':
458 ++stack[frame].index;
459 break;
460 default:
461 return getContent(cp);
462 }
463 }
464 return NULL;
465 }
466
467 bool Script::interp::setConst(const char *id, const char *value)
468 {
469 unsigned path;
470 linked_pointer<Script::symbol> sp;
471 Script::symbol *var = NULL;
472
473 if(*id == '=' || *id == '%')
474 ++id;
475
476 if(!isalnum(*id))
477 return false;
478
479 path = NamedObject::keyindex(id, Script::indexing);
480 sp = syms[path];
481
482 while(is(sp)) {
483 if(eq(sp->name, id) && sp->scope == stack[frame].scope)
484 return false;
485 sp.next();
486 }
487
488 var = (Script::symbol *)alloc(sizeof(Script::symbol));
489
490 var->name = dup(id);
491 var->scope = stack[frame].scope;
492 var->size = 0;
493 var->data = dup(value);
494 var->enlist(&syms[path]);
495 return true;
496 }
497
498 Script::symbol *Script::interp::createSymbol(const char *id)
499 {
500 unsigned path;
501 linked_pointer<Script::symbol> sp;
502 Script::symbol *var = NULL, *local = NULL;
503 unsigned size = Script::sizing;
504 char *cp;
505
506 if(*id == '=' || *id == '%')
507 ++id;
508
509 if(!isalnum(*id))
510 return NULL;
511
512 if(strchr(id, ':')) {
513 char *temp = getTemp();
514
515 String::set(temp, Script::sizing + 1, id);
516 cp = strchr(temp, ':');
517 if(cp) {
518 *(cp++) = 0;
519 id = temp;
520 size = atoi(cp);
521 }
522 }
523
524 path = NamedObject::keyindex(id, Script::indexing);
525 sp = syms[path];
526
527 if(!size)
528 size = Script::sizing;
529
530 while(is(sp)) {
531 if(eq(sp->name, id) && sp->scope == NULL)
532 var = *sp;
533 if(eq(sp->name, id) && sp->scope == stack[frame].scope)
534 local = *sp;
535 sp.next();
536 }
537
538 if(local)
539 var = local;
540
541 if(!var) {
542 var = (Script::symbol *)alloc(sizeof(Script::symbol));
543
544 var->name = dup(id);
545
546 var->scope = NULL;
547 var->size = size;
548 var->data = (char *)alloc(size + 1);
549 var->enlist(&syms[path]);
550 var->data[0] = 0;
551 }
552 return var;
553 }
554
555 unsigned Script::interp::getTypesize(const char *type_id)
556 {
557 if(!type_id)
558 return 0;
559
560 if(eq(type_id, "int"))
561 return 10;
562
563 if(eq(type_id, "num"))
564 return 20;
565
566 if(eq(type_id, "bool"))
567 return 1;
568
569 return 0;
570 }
571
572 const char *Script::interp::getTypeinit(const char *type_id)
573 {
574 if(!type_id)
575 return NULL;
576
577 if(eq(type_id, "int") || eq(type_id, "num"))
578 return "0";
579
580 if(eq(type_id, "bool"))
581 return "f";
582
583 return NULL;
584 }
585
586 void Script::interp::getParams(Script::header *scope, Script::line_t *line)
587 {
588 unsigned index = 0;
589 const char *cp;
590 const char *id;
591 unsigned param = 0;
592 char pbuf[8];
593 Script::symbol *sym;
594
595 while(index < line->argc) {
596 cp = line->argv[index++];
597 if(*cp == '=') {
598 id = ++cp;
599 cp = line->argv[index++];
600 }
601 else {
602 snprintf(pbuf, sizeof(pbuf), "%d", ++param);
603 id = pbuf;
604 }
605 if(eq(cp, "required") || eq(cp, "optional"))
606 setRef(scope, id, const_cast<char *>(""), 0);
607 else if(*cp == '%') {
608 sym = find(++cp);
609 if(sym) {
610 setRef(scope, id, sym->data, sym->size);
611 continue;
612 }
613 else
614 setRef(scope, id, const_cast<char *>(""), 0);
615
616 }
617 else {
618 cp = getContent(cp);
619 setRef(scope, id, const_cast<char *>(cp), 0);
620 }
621 }
622 }
623
624 void Script::interp::setRef(Script::header *scope, const char *id, char *value, unsigned size)
625 {
626 unsigned path;
627 linked_pointer<Script::symbol> sp;
628 Script::symbol *var = NULL;
629
630 if(*id == '=' || *id == '%')
631 ++id;
632
633 if(!isalnum(*id))
634 return;
635
636 path = NamedObject::keyindex(id, Script::indexing);
637 sp = syms[path];
638
639 while(is(sp)) {
640 if(eq(sp->name, id) && sp->scope == scope) {
641 var = *sp;
642 break;
643 }
644 sp.next();
645 }
646
647 if(!var) {
648 var = (Script::symbol *)alloc(sizeof(Script::symbol));
649
650 var->name = dup(id);
651
652 var->scope = scope;
653 var->enlist(&syms[path]);
654 }
655
656 var->size = size;
657 var->data = value;
658 }
659
660 Script::symbol *Script::interp::getVar(const char *id, const char *value)
661 {
662 unsigned path;
663 linked_pointer<Script::symbol> sp;
664 Script::symbol *var = NULL;
665 unsigned size = Script::sizing;
666 char *cp;
667
668 if(*id == '=' || *id == '%')
669 ++id;
670
671 if(!isalnum(*id))
672 return NULL;
673
674 if(strchr(id, ':')) {
675 char *temp = getTemp();
676
677 String::set(temp, Script::sizing + 1, id);
678 cp = strchr(temp, ':');
679 if(cp) {
680 *(cp++) = 0;
681 id = temp;
682 size = getTypesize(cp);
683 if(!value)
684 value = getTypeinit(cp);
685 if(!size)
686 size = atoi(cp);
687 }
688 }
689
690 path = NamedObject::keyindex(id, Script::indexing);
691 sp = syms[path];
692
693 if(!size)
694 size = Script::sizing;
695
696 while(is(sp)) {
697 if(eq(sp->name, id) && sp->scope == stack[frame].scope) {
698 var = *sp;
699 break;
700 }
701 sp.next();
702 }
703
704 if(!var) {
705 var = (Script::symbol *)alloc(sizeof(Script::symbol));
706
707 var->name = dup(id);
708
709 var->scope = stack[frame].scope;
710 var->size = size;
711 var->data = (char *)alloc(size + 1);
712 var->enlist(&syms[path]);
713 var->data[0] = 0;
714 }
715
716 // if const, we do not re-write...
717 if(!var->size)
718 return var;
719
720 // assign value, whether new or exists to reset...
721 if(value && *value)
722 String::set(var->data, var->size + 1, value);
723 else if(value)
724 var->data[0] = 0;
725 return var;
726 }
727
728 Script::symbol *Script::interp::find(const char *id)
729 {
730 unsigned path = NamedObject::keyindex(id, Script::indexing);
731 linked_pointer<Script::symbol> sp = syms[path];
732 Script::symbol *global = NULL, *local = NULL;
733
734 while(is(sp)) {
735 if(eq(sp->name, id)) {
736 if(sp->scope == NULL)
737 global = *sp;
738 else if(sp->scope == stack[frame].scope)
739 local = *sp;
740 }
741 sp.next();
742 }
743
744 if(local)
745 return local;
746
747 return global;
748 }
749
750 void Script::interp::detach(void)
751 {
752 image = NULL;
753 }
754
755 void Script::interp::startScript(Script::header *scr)
756 {
757 linked_pointer<Script::event> ep = scr->events;
758
759 while(is(ep)) {
760 if(eq(ep->name, "init")) {
761 push();
762 stack[frame].event = *ep;
763 stack[frame].line = ep->first;
764 return;
765 }
766 ep.next();
767 }
768 }
769
770 bool Script::interp::attach(Script *img, const char *entry)
771 {
772 Script::header *
main = NULL;
773 linked_pointer<Script::header> hp;
774 unsigned path = 0;
775 const char *cp;
776
777 image = img;
778
779 if(!img)
780 return false;
781
782 if(entry && *entry == '@')
783 main = Script::find(img, entry);
784 else while(entry && main == NULL && path < Script::indexing) {
785 hp = img->scripts[path++];
786 while(is(hp)) {
787 cp = hp->name;
788 if(*cp == '@' && match(cp, entry)) {
789 main = *hp;
790 break;
791 }
792 hp.next();
793 }
794 }
795
796 if(!main)
797 main = Script::find(img, "@main");
798
799 if(main) {
800 setStack(main);
801 push();
802 setStack(img->first);
803
804 while(frame && stack[frame].line)
805 (this->*(stack[frame].line->method))();
806
807 if(is(img->shared)) {
808 frame = 1;
809 setStack(img->shared->first);
810 while(frame && stack[frame].line)
811 (this->*(stack[frame].line->method))();
812 }
813
814 frame = 0;
815 startScript(main);
816 return true;
817 }
818 image = NULL;
819 return false;
820 }
821
822 void Script::interp::skip(void)
823 {
824 stack[frame].line = stack[frame].line->next;
825 }
826
827 bool Script::interp::match(const char *found, const char *name)
828 {
829 assert(found != NULL);
830 assert(name != NULL);
831
832 if(*found == '@')
833 ++found;
834
835 return !stricmp(found, name);
836 }
837
838 bool Script::interp::isInherited(const char *name)
839 {
840 return true;
841 }
842
843 Script::event *Script::interp::scriptMethod(const char *name)
844 {
845 linked_pointer<Script::event> mp = stack[frame].scr->methods;
846
847 while(is(mp)) {
848 if(match(mp->name, name))
849 return *mp;
850 mp.next();
851 }
852 return NULL;
853 }
854
855 bool Script::interp::scriptEvent(const char *name)
856 {
857 linked_pointer<Script::event> ep;
858 bool inherit = isInherited(name);
859 unsigned stackp = frame;
860
861 for(;;) {
862 ep = stack[stackp].scr->events;
863
864 while(is(ep)) {
865 if(match(ep->name, name))
866 break;
867
868 ep.next();
869 }
870
871 if(!is(ep) && !inherit)
872 return false;
873
874 if(is(ep)) {
875
876 if(stack[stackp].event == *ep)
877 return false;
878
879 frame = stackp;
880
881 pullScope();
882 setStack(stack[frame].scr, *ep);
883 return true;
884 }
885
886 while(stackp > stack[stackp].base && stack[stackp].line->loop)
887 --stackp;
888
889 if(stackp && stackp >= stack[stackp].base)
890 --stackp;
891 else
892 return false;
893 }
894 }
895
896 void Script::interp::setStack(Script::header *scr, Script::event *ev)
897 {
898 stack[frame].scr = scr;
899 stack[frame].event = ev;
900 stack[frame].index = 0;
901 stack[frame].resmask = scr->resmask;
902
903 if(ev)
904 stack[frame].line = ev->first;
905 else
906 stack[frame].line = scr->first;
907 }
908
909 void Script::interp::pullBase(void)
910 {
911 while(frame && stack[frame - 1].base == stack[frame].base)
912 --frame;
913 }
914
915 void Script::interp::pullScope(void)
916 {
917 while(frame && stack[frame - 1].scr == stack[frame].scr)
918 --frame;
919 }
920
921 void Script::interp::pullLoop(void)
922 {
923 skip();
924 if(frame) {
925 stack[frame - 1].line = stack[frame].line;
926 stack[frame - 1].index = 0;
927 --frame;
928 }
929 }
930
931 unsigned Script::interp::getResource(void)
932 {
933 if(!stack || !stack[frame].scr || (frame == 0 && !stack[frame].line))
934 return 0;
935
936 if(stack[frame].line)
937 return stack[frame].line->mask | stack[frame].resmask;
938
939 return stack[frame].resmask;
940 }
941
942 bool Script::interp::pop(void)
943 {
944 pullScope();
945 if(frame)
946 --frame;
947 else
948 return false;
949
950 return true;
951 }
952
953 void Script::interp::push(void)
954 {
955 if(frame >= Script::stacking) {
956 if(!scriptEvent("stack")) {
957 frame = 0;
958 stack[frame].line = NULL;
959 return;
960 }
961 }
962
963 stack[frame + 1] = stack[frame];
964 ++frame;
965 }
966
967 bool Script::interp::trylabel(const char *label)
968 {
969 if(*label != '@')
970 return false;
971
972 Script::header *scr = Script::find(*image, label);
973 if(!scr || !scr->first || stack[stack[frame].base].scr == scr)
974 return false;
975
976 frame = stack[frame].base;
977 setStack(scr, NULL);
978 return true;
979 }
980
981 bool Script::interp::tryexit(void)
982 {
983 if(stack[frame].event && eq("exit", stack[frame].event->name))
984 return false;
985
986 if(scriptEvent("exit"))
987 return true;
988
989 Script::header *ex = Script::find(image.get(), "@exit");
990 frame = 0;
991
992 if(!ex || stack[frame].scr == ex)
993 return false;
994
995 setStack(ex, NULL);
996 return true;
997 }
998
999 bool Script::interp::step(void)
1000 {
1001 unsigned scount = Script::stepping;
1002 line_t *line = stack[frame].line;
1003 bool rtn = true;
1004
1005 while(line && rtn && scount--) {
1006 rtn = (this->*(line->method))();
1007 line = stack[frame].line;
1008 }
1009
1010 if(line)
1011 return true;
1012
1013 while(stack[frame].line == NULL && frame)
1014 --frame;
1015
1016 if(!stack[frame].line && !tryexit())
1017 return false;
1018
1019 return true;
1020 }
1021
1022 bool Script::interp::getCondition(const char *test, const char *v)
1023 {
1024 unsigned points = 0;
1025 Script::symbol *sym;
1026
1027 if(eq(test, "defined")) {
1028 if(!v)
1029 return false;
1030 if(*v == '%') {
1031 sym = find(++v);
1032 if(!sym)
1033 return false;
1034 return true;
1035 }
1036 v = getContent(v);
1037 if(!*v)
1038 return false;
1039 return true;
1040 }
1041
1042 if(eq(test, "const")) {
1043 if(!v)
1044 return false;
1045
1046 if(*v == '%') {
1047 sym = find(++v);
1048 if(!sym)
1049 return false;
1050 if(sym->size)
1051 return false;
1052 return true;
1053 }
1054 else
1055 return false;
1056 }
1057
1058 if(eq(test, "modify")) {
1059 if(!v)
1060 return false;
1061
1062 if(*v == '%') {
1063 sym = find(++v);
1064 if(!sym)
1065 return false;
1066 if(sym->size)
1067 return true;
1068 return false;
1069 }
1070 else
1071 return false;
1072 }
1073
1074 v = getContent(v);
1075 if(eq(test, "empty")) {
1076 if(v && *v)
1077 return false;
1078 return true;
1079 }
1080
1081 if(eq(test, "integer")) {
1082 if(!v || !*v)
1083 return false;
1084
1085 if(*v == '-')
1086 ++v;
1087
1088 while(*v) {
1089 if(!isdigit(*v))
1090 return false;
1091 ++v;
1092 }
1093 return true;
1094 }
1095
1096 if(eq(test, "digits")) {
1097 if(!v || !*v)
1098 return false;
1099
1100 while(*v) {
1101 if(!isdigit(*v))
1102 return false;
1103 ++v;
1104 }
1105 return true;
1106 }
1107
1108 if(eq(test, "number")) {
1109 if(!v || !*v)
1110 return false;
1111
1112 if(*v == '-')
1113 ++v;
1114
1115 while(*v) {
1116 if(*v == '.') {
1117 if(points)
1118 return false;
1119 ++points;
1120 ++v;
1121 continue;
1122 }
1123 if(!isdigit(*v))
1124 return false;
1125 ++v;
1126 }
1127
1128 return true;
1129 }
1130
1131 return false;
1132 }
1133
1134 bool Script::interp::isConditional(unsigned index)
1135 {
1136 Script::line_t *line = stack[frame].line;
1137 const char *cp;
1138 bool rtn = false;
1139
1140 while(index < line->argc) {
1141 rtn = getExpression(index);
1142 cp = line->argv[index];
1143 if((*cp == '-' || *cp == '!') && isalpha(cp[1]))
1144 index += 2;
1145 else
1146 index += 3;
1147
1148 if(index >= line->argc)
1149 return rtn;
1150
1151 cp = line->argv[index++];
1152
1153 if(eq(cp, "?&&") || eq(cp, "and")) {
1154 if(!rtn)
1155 return false;
1156 rtn = false;
1157 continue;
1158 }
1159 if(eq(cp, "?||") || eq(cp, "or")) {
1160 if(rtn)
1161 return true;
1162 rtn = false;
1163 continue;
1164 }
1165 break;
1166 }
1167 return rtn;
1168 }
1169
1170 bool Script::interp::getExpression(unsigned index)
1171 {
1172 Script::line_t *line = stack[frame].line;
1173 const char *v1 = "", *v2 = "", *op;
1174 const char *d1, *d2;
1175 unsigned len;
1176 char dec1[9], dec2[9];
1177 long dv1, dv2;
1178 unsigned pos = 0, pcount;
1179
1180 #ifdef __MINGW32__
1181 long long dv;
1182 #else
1183 long dv;
1184 #endif
1185
1186 if(index < line->argc) {
1187 v1 = line->argv[index++];
1188 if((*v1 == '-' || *v1 == '!') && isalpha(v1[1])) {
1189 if(index < line->argc)
1190 v2 = line->argv[index++];
1191 else
1192 v2 = NULL;
1193 if(*v1 == '-')
1194 return getCondition(++v1, v2);
1195 else
1196 return !getCondition(++v1, v2);
1197 }
1198 v1 = getContent(v1);
1199 }
1200 else
1201 return false;
1202
1203 if(index <= line->argc) {
1204 op = line->argv[index++];
1205 if(*op == '?')
1206 ++op;
1207 }
1208 else if(v1 && *v1)
1209 return true;
1210 else
1211 return false;
1212
1213 if(index <= line->argc)
1214 v2 = getContent(line->argv[index++]);
1215
1216 d1 = strchr(v1, '.');
1217 d2 = strchr(v2, '.');
1218 dec1[0] = 0;
1219 dec2[0] = 0;
1220 if(d1) {
1221 dv = atol(++d1);
1222 snprintf(dec1,
sizeof(dec1),
NUM_FORMAT, dv);
1223 }
1224 if(d2) {
1225 dv = atol(++d2);
1226 snprintf(dec2,
sizeof(dec2),
NUM_FORMAT, dv);
1227 }
1228
1229 unsigned c1 = strlen(dec1);
1230 unsigned c2 = strlen(dec2);
1231 while(c1 < 8)
1232 dec1[c1++] = '0';
1233
1234 while(c2 < 8)
1235 dec2[c2++] = '0';
1236
1237 dec1[8] = dec2[8] = 0;
1238 if(eq(op, "="))
1239 return ((atol(v1) == atol(v2)) && !strcmp(dec1, dec2));
1240
1241 if(eq(op, "<>"))
1242 return ((atol(v1) != atol(v2)) || strcmp(dec1, dec2));
1243
1244 if(eq(op, "&&"))
1245 return (*v1 && *v2);
1246
1247 if(eq(op, "||"))
1248 return (*v1 || *v2);
1249
1250 if(eq(op, "gt")) {
1251 if(strcmp(v1, v2) > 0)
1252 return true;
1253 return false;
1254 }
1255
1256 if(eq(op, "lt")) {
1257 if(strcmp(v1, v2) < 0)
1258 return true;
1259 return false;
1260 }
1261
1262 if(eq(op, "ge")) {
1263 if(strcmp(v1, v2) >= 0)
1264 return true;
1265 return false;
1266 }
1267
1268 if(eq(op, "le")) {
1269 if(strcmp(v1, v2) <= 0)
1270 return true;
1271 return false;
1272 }
1273
1274 if(eq(op, "==") || eq(op, "eq"))
1275 return eq(v1, v2);
1276
1277 if(eq(op, "!=") || eq(op, "ne"))
1278 return !eq(v1, v2);
1279
1280 if(eq(op, "<")) {
1281 dv1 = atol(dec1);
1282 dv2 = atol(dec2);
1283 if(*v1 == '-') {
1284 dv1 = -dv1;
1285 dv2 = -dv2;
1286 }
1287 return (atol(v1) < atol(v2) || (atol(v1) == atol(v2) && dv1 < dv2));
1288 }
1289
1290 if(eq(op, "<=")) {
1291 dv1 = atol(dec1);
1292 dv2 = atol(dec2);
1293 if(*v1 == '-') {
1294 dv1 = -dv1;
1295 dv2 = -dv2;
1296 }
1297 return (atoi(v1) < atoi(v2) || (atol(v1) == atol(v2) && dv1 <= dv2));
1298 }
1299
1300 if(eq(op, ">")) {
1301 dv1 = atol(dec1);
1302 dv2 = atol(dec2);
1303 if(*v1 == '-') {
1304 dv1 = -dv1;
1305 dv2 = -dv2;
1306 }
1307 return (atol(v1) > atol(v2) || (atol(v1) == atol(v2) && dv1 > dv2));
1308 }
1309
1310 if(eq(op, ">=")) {
1311 dv1 = atol(dec1);
1312 dv2 = atol(dec2);
1313 if(*v1 == '-') {
1314 dv1 = -dv1;
1315 dv2 = -dv2;
1316 }
1317 return (atol(v1) > atol(v2) || (atol(v1) == atol(v2) && dv1 >= dv2));
1318 }
1319
1320 if(eq(op, "?") || eq(op, "in")) {
1321 pcount = Script::count(v2);
1322 if(!pcount)
1323 return false;
1324
1325 len = strlen(v1);
1326 while(pos < pcount) {
1327 op = Script::get(v2, pos++);
1328 if(op && eq(v1, op, len) && (op[len] == ',' || op[len] == 0 || op[len] == '='))
1329 return true;
1330 }
1331 return false;
1332 }
1333
1334 if(eq(op, "!?") || eq(op, "notin")) {
1335 pcount = Script::count(v2);
1336 if(!pcount)
1337 return true;
1338
1339 len = strlen(v1);
1340 while(pos < pcount) {
1341 op = Script::get(v2, pos++);
1342 if(op && eq(v1, op, len) && (op[len] == ',' || op[len] == 0 || op[len] == '='))
1343 return false;
1344 }
1345 return true;
1346 }
1347
1348 if(eq(op, "!$") || eq(op, "isnot"))
1349 return !match(v2, v1);
1350
1351 if(eq(op, "$") || eq(op, "is"))
1352 return match(v2, v1);
1353
1354 #ifdef HAVE_REGEX_H
1355 if(eq(op, "~") || eq(op, "!~")) {
1356 bool rtn = false;
1357 regex_t *regex = new regex_t;
1358 memset(regex, 0, sizeof(regex_t));
1359
1360 if(regcomp(regex, v2, REG_ICASE|REG_NOSUB|REG_NEWLINE)) {
1361 regfree(regex);
1362 delete regex;
1363 return false;
1364 }
1365
1366 if(regexec(regex, v1, 0, NULL, 0))
1367 rtn = false;
1368 else
1369 rtn = true;
1370
1371 regfree(regex);
1372 delete regex;
1373 if(*op == '!')
1374 return !rtn;
1375 return rtn;
1376 }
1377 #endif
1378 return false;
1379 }
#define BAYONNE_NAMESPACE
GNU Bayonne library namespace.
int main(int argc, char **argv)