Bayonne 3 - API
 All Classes Namespaces Files Functions Variables Typedefs Macros
interp.cpp
Go to the documentation of this file.
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>
23 #include <bayonne.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 
36 using namespace BAYONNE_NAMESPACE;
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
Definition: bayonne.h:25
GNU Bayonne library namespace.
int main(int argc, char **argv)
#define NUM_FORMAT
Definition: interp.cpp:33