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