Bayonne 3 - API
 All Classes Namespaces Files Functions Variables Typedefs Macros
runtime/script.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 using namespace BAYONNE_NAMESPACE;
27 using namespace UCOMMON_NAMESPACE;
28 
29 static Script::keyword_t *keywords = NULL;
30 
31 size_t Script::paging = 0; // default page size used...
32 unsigned Script::sizing = 64; // default symbol size is 64...
33 unsigned Script::indexing = 77; // hash size of symbol index
34 unsigned Script::stacking = 20; // max stack depth 20...
35 unsigned Script::stepping = 7; // automatic stepping...
36 unsigned Script::decimals = 2; // two decimal places...us default
37 
38 static bool ideq(const char *id1, const char *id2)
39 {
40  unsigned count = 0;
41 
42  if(!id1)
43  id1 = "";
44 
45  if(!id2)
46  id2 = "";
47 
48  while(id1[count] && id1[count] != ':') {
49  if(id2[count] != id1[count])
50  return false;
51  ++count;
52  }
53  if(id2[count] && id2[count] != ':')
54  return false;
55 
56  return true;
57 }
58 static bool iskeyword(const char *str)
59 {
60  if(!str || !*str)
61  return false;
62 
63  if(*str == '_')
64  ++str;
65 
66  while(*str) {
67  if(!isalpha(*str) && *str != '.')
68  return false;
69  ++str;
70  }
71  return true;
72 }
73 
74 static bool isend(const char *str)
75 {
76  if(!str || !*str)
77  return true;
78 
79  if(!strncmp("%%", str, 2))
80  return true;
81 
82  if(!strncmp("//", str, 2))
83  return true;
84 
85  return false;
86 }
87 
88 static bool preparse(char **tokens)
89 {
90  if(!tokens || !*tokens)
91  return true;
92 
93  while(*tokens && isspace(**tokens))
94  ++*tokens;
95 
96  char *str = *tokens;
97  if(isend(str)) {
98  *str = 0;
99  return true;
100  }
101 
102  switch(*str) {
103  case '=':
104  if(isspace(str[1]) || (str[1] == '=' && isspace(str[2]))) {
105  --*tokens;
106  **tokens = '?';
107  return true;
108  }
109  return false;
110 #ifdef HAVE_REGEX_H
111  case '~':
112  if(isspace(str[1])) {
113  --*tokens;
114  **tokens = '?';
115  return true;
116  }
117  return false;
118 #endif
119  case '>':
120  if(eq(str, ">>%", 3)) {
121  --*tokens;
122  --str;
123  str[0] = '$';
124  str[3] = ':';
125  return true;
126  }
127  if(isspace(str[1]) || (str[1] == '=' && isspace(str[2]))) {
128  --*tokens;
129  **tokens = '?';
130  return true;
131  }
132  return false;
133  case '$':
134  if(isspace(str[1])) {
135  --*tokens;
136  **tokens = '?';
137  return true;
138  }
139  break;
140  case '?':
141  if(isspace(str[1])) {
142  --*tokens;
143  **tokens = '?';
144  return true;
145  }
146  return false;
147  case '<':
148  if(eq(str, "<<%", 3)) {
149  --*tokens;
150  --str;
151  str[0] = '$';
152  str[3] = ':';
153  return true;
154  }
155  if(isspace(str[1]) || (str[1] == '=' && isspace(str[2])) || (str[1] == '>' && isspace(str[2]))) {
156  --*tokens;
157  **tokens = '?';
158  return true;
159  }
160  return false;
161  case '!':
162  if(str[1] == '=' && isspace(str[2])) {
163  --*tokens;
164  **tokens = '?';
165  return true;
166  }
167  else if(str[1] == '?' && isspace(str[2])) {
168  --*tokens;
169  **tokens = '?';
170  return true;
171  }
172  else if(str[1] == '$' && isspace(str[2])) {
173  --*tokens;
174  **tokens = '?';
175  return true;
176  }
177  else if(str[1] == '~' && isspace(str[2])) {
178  --*tokens;
179  **tokens = '?';
180  return true;
181  }
182  if(isalnum(str[1]))
183  break;
184  return false;
185  case '&':
186  if(str[1] == '&' && isspace(str[2])) {
187  --*tokens;
188  **tokens = '?';
189  return true;
190  }
191  else if(isalnum(str[1])) {
192  *str = '%';
193  break;
194  }
195  return false;
196  case '|':
197  if(str[1] == '|' && isspace(str[2])) {
198  --*tokens;
199  **tokens = '?';
200  return true;
201  }
202  return false;
203  case '/':
204  case '*':
205  if(isspace(str[1]))
206  break;
207  if(str[1] == '=' && isspace(str[2]))
208  break;
209  return false;
210  case ':':
211  if(str[1] == '=' && isspace(str[2]))
212  return true;
213  case ',':
214  case '`':
215  case '(':
216  case '[':
217  case ')':
218  case ']':
219  case ';':
220  case '_':
221  return false;
222  case '+':
223  if(eq(str, "++%", 3)) {
224  --*tokens;
225  --str;
226  str[0] = '$';
227  str[3] = ':';
228  return true;
229  }
230  if(isdigit(str[1]) || str[1] == '.') {
231  ++*tokens;
232  return true;
233  }
234  if(isspace(str[1]))
235  break;
236  if(str[1] == '=' && isspace(str[2]))
237  break;
238  return false;
239  case '.':
240  if(isdigit(str[1]))
241  break;
242  return false;
243  case '-':
244  if(eq(str, "--%", 3)) {
245  --*tokens;
246  --str;
247  str[0] = '$';
248  str[3] = ':';
249  return true;
250  }
251  if(isalnum(str[1]) || str[1] == '.')
252  return true;
253  if(isspace(str[1]))
254  break;
255  if(str[1] == '=' && isspace(str[2]))
256  break;
257  return false;
258  case '\'':
259  case '\"':
260  case '{':
261  --str;
262  --*tokens;
263  str[0] = str[1];
264  str[1] = '&';
265  return true;
266  }
267 
268  while(*str && (isalnum(*str) || *str == ':' || *str == '.'))
269  ++str;
270 
271  // we flip xxx=... into =xxx objects...
272 
273  if(*str == '=') {
274  --*tokens;
275  **tokens = '=';
276  *str = ' ';
277  }
278 
279  return true;
280 }
281 
282 Script::error::error(Script *img, unsigned line, const char *msg) :
283 OrderedObject(&img->errlist)
284 {
285  errmsg = img->dup(msg);
286  errline = line;
287 }
288 
289 Script::Script() :
290 CountedObject(), memalloc()
291 {
292  errors = 0;
293  loop = 0;
294  lines = 0;
295  first = NULL;
296  global = NULL;
297  headers = NULL;
298  stack = NULL;
299  scripts = (LinkedObject **)alloc(sizeof(LinkedObject **) * Script::indexing);
300  memset(scripts, 0, sizeof(LinkedObject **) * Script::indexing);
301 }
302 
303 Script::~Script()
304 {
305  if(stack)
306  delete[] stack;
307  shared = NULL;
308 }
309 
310 void Script::errlog(unsigned line, const char *fmt, ...)
311 {
312  char text[65];
313  va_list args;
314 
315  va_start(args, fmt);
316  vsnprintf(text, sizeof(text), fmt, args);
317 
318  ++errors;
319  caddr_t mp = (caddr_t)alloc(sizeof(Script::error));
320  new(mp) Script::error(this, line, text);
321  va_end(args);
322 }
323 
324 void Script::assign(Script::keyword_t *keyword)
325 {
326  while(keyword && keyword->name) {
327  keyword->next = keywords;
328  keywords = keyword;
329  ++keyword;
330  }
331 }
332 
333 Script::keyword_t *Script::find(const char *cmd)
334 {
335  keyword_t *keyword = keywords;
336 
337  while(keyword != NULL) {
338  if(eq(cmd, keyword->name))
339  break;
340  keyword = keyword->next;
341  }
342  return keyword;
343 }
344 
345 void Script::init(void)
346 {
347  static keyword_t keywords[] = {
348  {"pause", (method_t)&methods::scrPause, (check_t)&checks::chkNop},
349  {"nop", (method_t)&methods::scrNop, (check_t)&checks::chkNop},
350  {"exit", (method_t)&methods::scrExit, (check_t)&checks::chkExit},
351  {"return", (method_t)&methods::scrReturn, (check_t)&checks::chkExit},
352  {"restart", (method_t)&methods::scrRestart, (check_t)&checks::chkExit},
353  {"goto", (method_t)&methods::scrGoto, (check_t)&checks::chkGoto},
354  {"gosub", (method_t)&methods::scrGosub, (check_t)&checks::chkGosub},
355  {"var", (method_t)&methods::scrVar, (check_t)&checks::chkVar},
356  {"const", (method_t)&methods::scrConst, (check_t)&checks::chkConst},
357  {"error", (method_t)&methods::scrError, (check_t)&checks::chkError},
358  {"clear", (method_t)&methods::scrClear, (check_t)&checks::chkClear},
359  {"push", (method_t)&methods::scrPush, (check_t)&checks::chkPush},
360  {"set", (method_t)&methods::scrSet, (check_t)&checks::chkSet},
361  {"add", (method_t)&methods::scrAdd, (check_t)&checks::chkSet},
362  {"pack", (method_t)&methods::scrPack, (check_t)&checks::chkPack},
363  {"expand", (method_t)&methods::scrExpand, (check_t)&checks::chkExpand},
364  {"do", (method_t)&methods::scrDo, (check_t)&checks::chkDo},
365  {"until", (method_t)&methods::scrUntil, (check_t)&checks::chkUntil},
366  {"break", (method_t)&methods::scrBreak, (check_t)&checks::chkBreak},
367  {"continue", (method_t)&methods::scrContinue, (check_t)&checks::chkContinue},
368  {"previous", (method_t)&methods::scrPrevious, (check_t)&checks::chkPrevious},
369  {"repeat", (method_t)&methods::scrRepeat, (check_t)&checks::chkPrevious},
370  {"index", (method_t)&methods::scrIndex, (check_t)&checks::chkIndex},
371  {"loop", (method_t)&methods::scrLoop, (check_t)&checks::chkLoop},
372  {"while", (method_t)&methods::scrWhile, (check_t)&checks::chkWhile},
373  {"for", (method_t)&methods::scrForeach, (check_t)&checks::chkForeach},
374  {"foreach", (method_t)&methods::scrForeach, (check_t)&checks::chkForeach},
375  {"case", (method_t)&methods::scrCase, (check_t)&checks::chkCase},
376  {"otherwise", (method_t)&methods::scrOtherwise, (check_t)&checks::chkOtherwise},
377  {"endcase", (method_t)&methods::scrEndcase, (check_t)&checks::chkEndcase},
378  {"if", (method_t)&methods::scrIf, (check_t)&checks::chkIf},
379  {"elif", (method_t)&methods::scrElif, (check_t)&checks::chkElif},
380  {"else", (method_t)&methods::scrElse, (check_t)&checks::chkElse},
381  {"endif", (method_t)&methods::scrEndif, (check_t)&checks::chkEndif},
382  {"expr", (method_t)&methods::scrExpr, (check_t)&checks::chkExpr},
383  {"strict", (method_t)NULL, (check_t)&checks::chkStrict},
384  {"apply", (method_t)NULL, (check_t)&checks::chkApply},
385  {"_ifthen", (method_t)&methods::scrWhen, (check_t)&checks::chkWhen},
386  {"_define", (method_t)&methods::scrDefine, (check_t)&checks::chkDefine},
387  {"_invoke", (method_t)&methods::scrInvoke, (check_t)&checks::chkInvoke},
388  {"_ref", (method_t)&methods::scrRef, (check_t)&checks::chkRef},
389  {NULL}
390  };
391 
392  static bool initial = false;
393 
394  if(!initial) {
395  initial = true;
396  assign(keywords);
397  }
398 }
399 
400 Script::header *Script::find(Script *img, const char *id)
401 {
402  unsigned path = NamedObject::keyindex(id, Script::indexing);
403  linked_pointer<header> hp = img->scripts[path];
404 
405  while(is(hp)) {
406  if(eq(hp->name, id))
407  break;
408 
409  hp.next();
410  }
411  return *hp;
412 }
413 
414 Script *Script::merge(const char *fn, Script *root)
415 {
416  Script *img = compile(fn, root);
417  if(!root || !img)
418  return img;
419 
420  return merge(img, root);
421 }
422 
423 Script *Script::merge(Script *img, Script *root)
424 {
425  assert(img != NULL && root != NULL);
426 
427  for(unsigned index = 0; index < Script::indexing; ++index) {
428  header *prior = NULL;
429  linked_pointer<header> hp = img->scripts[index];
430  while(is(hp)) {
431  prior = *hp;
432  hp.next();
433  }
434  if(prior)
435  prior->link(static_cast<header *>(root->scripts[index]));
436  else
437  img->scripts[index] = root->scripts[index];
438  }
439 
440  return img;
441 }
442 
443 Script *Script::compile(const char *fn, Script *cfg)
444 {
445  return Script::append(NULL, fn, cfg);
446 }
447 
448 Script *Script::append(Script *merge, const char *fn, Script *cfg)
449 {
450 // linked_pointer<script::strict> sp;
451 
452  char **argv = new char *[256];
453  stringbuf<512> buffer;
454  Script *img;
455  charfile cf(fn, "r");
456  header *scr = NULL;
457  const char *name = "_init_";
458  Script::event *current;
459  Script::event *prior;
460  char *tokens;
461  const char *token = NULL;
462  char *arg;
463  unsigned lnum = 0;
464  line_t *line, *last;
465  bool section = false;
466  unsigned argc;
467  const char *err, *op;
468  char *assigned;
469  unsigned path;
470  bool indented, formed;
471  Script::header *invoke;
472  bool define = false;
473  bool when = false;
474  bool label = false;
475  unsigned pos;
476  const char *cp;
477  bool requires = false;
478  char *ep;
479  unsigned len;
480 
481  if(!is(cf)) {
482  if(merge)
483  return merge;
484  return NULL;
485  }
486 
487  if(merge)
488  img = merge;
489  else
490  img = new Script();
491 
492  if(!img->stack)
493  img->stack = new line_t*[Script::stacking];
494 
495  img->shared = cfg;
496  img->filename = strrchr(fn, '/');
497  if(!img->filename)
498  img->filename = strrchr(fn, '\\');
499  if(!img->filename)
500  img->filename = strrchr(fn, ':');
501  if(img->filename)
502  ++img->filename;
503  else
504  img->filename = fn;
505 
506 initial:
507  current = NULL;
508  prior = NULL;
509  last = NULL;
510 
511  scr = (header *)img->alloc(sizeof(header));
512  memset(scr, 0, sizeof(header));
513  scr->name = img->dup(name);
514  scr->events = NULL;
515  scr->first = NULL;
516  scr->resmask = 0;
517  scr->scoped = NULL;
518  keyword_t *keyword;
519  img->loop = 0;
520  char *temp;
521 
522  // we drop additional initializers during append
523  if(!eq(name, "_init_") || !merge) {
524  path = NamedObject::keyindex(name, Script::indexing);
525  scr->enlist(&img->scripts[path]);
526  }
527 
528  if(!img->first)
529  img->first = scr;
530 
531  while(when || label || define || cf.readline(buffer)) {
532  if(define) {
533  indented = true;
534  goto parse;
535  }
536 
537  if(when) {
538  indented = true;
539  when = false;
540  goto parse;
541  }
542 
543  if(label) {
544  label = false;
545  indented = true;
546  token = String::token(NULL, &tokens, " \t", "{}\'\'\"\"");
547  if(!token)
548  continue;
549  goto parse;
550  }
551 
552  img->lines = ++lnum;
553  img->thencheck = false;
554 
555  indented = false;
556  tokens = buffer.c_mem();
557  if(isspace(*tokens)) {
558  while(isspace(*tokens))
559  ++tokens;
560  indented = true;
561  if(!preparse(&tokens)) {
562  img->errlog(lnum, "malformed line");
563  continue;
564  }
565  }
566 
567  String::trim(buffer, " \t\r\n");
568 
569  // if empty line or comment, continue...
570  if(isend(*buffer))
571  continue;
572 
573  tokens = NULL;
574  token = String::token(buffer.c_mem(), &tokens, " \t", "{}\'\'\"\"");
575 
576  if(eq(token, "endreq") || eq(token, "endrequires")) {
577  if(indented) {
578  img->errlog(lnum, "endreq cannot be indented");
579  continue;
580  }
581  requires = false;
582  continue;
583  }
584  else if(eq(token, "requires")) {
585  if(indented) {
586  img->errlog(lnum, "requires cannot be indented");
587  continue;
588  }
589  requires = true;
590  while(NULL != (token = String::token(NULL, &tokens, " \t", "{}\'\'\"\""))) {
591  bool rev = false;
592  if(*token == '!') {
593  rev = true;
594  ++token;
595  }
596  keyword = find(token);
597  invoke = find(img, token);
598  if(!invoke && is(img->shared))
599  invoke = find(*(img->shared), token);
600  if(!rev && (keyword || invoke)) {
601  requires = false;
602  break;
603  }
604  if(rev && !keyword && !invoke) {
605  requires = false;
606  break;
607  }
608  }
609  continue;
610  }
611 
612  if(requires)
613  continue;
614 
615  if(*token == '^' || *token == '-') {
616  current = (event *)img->alloc(sizeof(Script::event));
617  if(!prior)
618  prior = current;
619 
620  last = NULL;
621  memset(current, 0, sizeof(event));
622  if(*token == '^')
623  current->enlist(&scr->events);
624  else
625  current->enlist(&scr->methods);
626  current->name = (char *)img->dup(++token);
627  current->first = NULL;
628  continue;
629  }
630 
631  if(*token == '@') {
632  section = true;
633  name = token;
634  label = true;
635  goto closure;
636  }
637 
638  if(eq(token, "template")) {
639  if(section) {
640  img->errlog(lnum, "templates must be before named sections");
641  continue;
642  }
643  if(indented) {
644  img->errlog(lnum, "templates cannot be indented");
645  continue;
646  }
647  token = String::token(NULL, &tokens, " \t", "{}\'\'\"\"");
648  if(!token)
649  img->errlog(lnum, "template must be named");
650  name = token;
651  goto closure;
652  }
653 
654  if(eq(token, "define")) {
655  if(section) {
656  img->errlog(lnum, "defines must be before named sections");
657  continue;
658  }
659  if(indented) {
660  img->errlog(lnum, "define cannot be indented");
661  continue;
662  }
663  token = String::token(NULL, &tokens, " \t", "{}\'\'\"\"");
664  keyword = find(token);
665  if(keyword) {
666  img->errlog(lnum, "cannot redefine existing command");
667  continue;
668  }
669  define = true;
670  name = token;
671  goto closure;
672  }
673  if(!indented) {
674  img->errlog(lnum, "unindented statement");
675  continue;
676  }
677 
678 parse:
679  assigned = NULL;
680  op = NULL;
681  if(*token == '%') {
682  assigned = img->dup(token);
683  op = String::token(NULL, &tokens, " \t", "{}\'\'\"\"");
684  if(op && (eq(op, ":=") || eq(op, "+=") || eq(op, "-=") || eq(op, "*=") || eq(op, "/=") || eq(op, "%=") || eq(op, "#=")))
685  token = "expr";
686  else if(op && (eq(op, "=") || eq(op, "==") || eq(op, "$="))) {
687  op = NULL;
688  token = "set";
689  }
690  else if(op && (eq(op, ".") || eq(op, ".="))) {
691  op = NULL;
692  token = "add";
693  }
694  else if(op && (eq(op, ",") || eq(op, ",="))) {
695  op = NULL;
696  token = "pack";
697  }
698  else {
699  img->errlog(lnum, "invalid assignment");
700  continue;
701  }
702  }
703  else if(*token == '$') {
704  assigned = img->dup(token);
705  token = "_ref";
706  }
707  invoke = NULL;
708  if(!iskeyword(token)) {
709  img->errlog(lnum, "invalid keyword");
710  continue;
711  }
712 
713  if(define) {
714  define = false;
715  keyword = find("_define");
716  if(!keyword) {
717  img->errlog(lnum, "define unsupported");
718  continue;
719  }
720  }
721  else {
722  keyword = find(token);
723  if(!keyword && NULL != (invoke = find(img, token)))
724  keyword = find("_invoke");
725  if(!keyword && is(img->shared) && NULL != (invoke = find(*(img->shared), token)))
726  keyword = find("_invoke");
727 
728  if(!keyword) {
729  img->errlog(lnum, "unknown keyword \"%s\"", token);
730  continue;
731  }
732  }
733 
734  // protects in backparse
735  token = img->dup(token);
736 
737  line = (line_t *)img->alloc(sizeof(line_t));
738  memset(line, 0, sizeof(line_t));
739  line->next = NULL;
740  line->lnum = lnum;
741  line->mask = 0;
742  if(invoke)
743  line->sub = invoke;
744  else
745  line->cmd = token;
746  line->loop = img->loop;
747  line->method = keyword->method;
748 
749  formed = true;
750  argc = 0;
751  arg = NULL;
752 
753  if(assigned)
754  argv[argc++] = assigned;
755 
756  if(op)
757  argv[argc++] = img->dup(op);
758 
759  while(argc < 249 && formed) {
760  if(!arg) {
761  formed = preparse(&tokens);
762  if(!formed)
763  break;
764  arg = (char *)String::token(NULL, &tokens, " \t", "{}\'\'\"\"");
765  }
766  if(!arg)
767  break;
768 
769  if(eq(token, "if")) {
770  if(eq(arg, "if")) {
771  formed = false;
772  break;
773  }
774  if(eq(arg, "then")) {
775  keyword = find("_ifthen");
776  line->method = keyword->method;
777  token = String::token(NULL, &tokens, " \t", "{}\'\'\"\"");
778  if(!token || !keyword || img->thencheck)
779  formed = false;
780  else
781  img->thencheck = when = true;
782  break;
783  }
784  }
785 
786  ep = strchr(arg, '<');
787  if(*arg == '%' && ep) {
788  len = strlen(arg) + 10;
789  *(ep++) = 0;
790  temp = (char *)img->alloc(len);
791  String::set(temp, len, "$map/");
792  String::add(temp, len, ep);
793  ep = strchr(temp, '>');
794  if(ep)
795  *ep = ':';
796  String::add(temp, len, ++arg);
797  argv[argc++] = temp;
798  arg = NULL;
799  continue;
800  }
801 
802  ep = strchr(arg, '[');
803  if(*arg == '%' && ep) {
804  len = strlen(arg) + 10;
805  *(ep++) = 0;
806  temp = (char *)img->alloc(len);
807  if(atoi(ep))
808  String::set(temp, len, "$offset/");
809  else
810  String::set(temp, len, "$find/");
811  String::add(temp, len, ep);
812  ep = strchr(temp, ']');
813  if(ep)
814  *ep = ':';
815  String::add(temp, len, ++arg);
816  argv[argc++] = temp;
817  arg = NULL;
818  continue;
819  }
820 
821  ep = strchr(arg, '(');
822  if(*arg == '%' && ep) {
823  len = strlen(arg) + 10;
824  *(ep++) = 0;
825  temp = (char *)img->alloc(len);
826  String::set(temp, len, "$index/");
827  String::add(temp, len, ep);
828  ep = strchr(temp, ')');
829  if(ep)
830  *ep = ':';
831  String::add(temp, len, ++arg);
832  argv[argc++] = temp;
833  arg = NULL;
834  continue;
835  }
836 
837  argv[argc++] = img->dup(arg);
838  arg = NULL;
839  }
840 
841  if(!formed) {
842  img->errlog(lnum, "malformed statement or argument");
843  continue;
844  }
845 
846  line->argc = argc;
847  argv[argc++] = NULL;
848  line->argv = (char **)img->alloc(sizeof(char *) * argc);
849  memcpy(line->argv, argv, sizeof(char *) * argc);
850 
851  err = (*(keyword->check))(img, scr, line);
852  if(err) {
853  img->errlog(lnum, "%s", err);
854  continue;
855  }
856 
857  pos = 0;
858  while(img->isStrict() && pos < line->argc) {
859  cp = line->argv[pos++];
860  if(!Script::strict::find(img, scr, cp))
861  img->errlog(lnum, "undefined symbol reference %s\n", cp);
862  }
863 
864  // if compile-time only line, then no runtime method, so we skip...
865 
866  if(line->method == (method_t)NULL)
867  continue;
868 
869  // after error checking...we may add starting line...
870 
871  if(last)
872  last->next = line;
873  else {
874  if(current) {
875  linked_pointer<event> ep = prior;
876  while(is(ep) && *ep != current) {
877  ep->first = line;
878  ep.next();
879  }
880  current->first = line;
881  }
882  else
883  scr->first = line;
884  }
885  last = line;
886  }
887 
888 closure:
889  while(img->loop) {
890  line = img->stack[--img->loop];
891  img->errlog(line->lnum, "%s never completed loop", line->cmd);
892  }
893 
894  keyword = find("_close");
895  if(keyword) {
896  err = (*(keyword->check))(img, scr, scr->first);
897  if(err)
898  img->errlog(lnum, "%s", err);
899  }
900 
901 // sp = scr->scoped;
902 // while(is(sp)) {
903 // sp->put(stdout, scr->name);
904 // sp.next();
905 // }
906 
907  if(!cf.eof())
908  goto initial;
909 
910  delete[] argv;
911  delete[] img->stack;
912  img->stack = NULL;
913 // sp = img->global;
914 // while(is(sp)) {
915 // sp->put(stdout, "*");
916 // sp.next();
917 // }
918 
919  return img;
920 }
921 
922 bool Script::isEvent(header *scr, const char *id)
923 {
924  linked_pointer<event> ep = scr->events;
925 
926  while(is(ep)) {
927  if(eq(ep->name, id))
928  return true;
929  ep.next();
930  }
931  return false;
932 }
933 
934 bool Script::push(line_t *line)
935 {
936  if(loop < stacking) {
937  stack[loop++] = line;
938  return true;
939  }
940  return false;
941 }
942 
943 Script::method_t Script::pull(void)
944 {
945  if(!loop)
946  return NULL;
947 
948  return stack[--loop]->method;
949 }
950 
951 Script::method_t Script::looping(void)
952 {
953  if(!loop)
954  return NULL;
955 
956  return stack[loop - 1]->method;
957 }
958 
959 void Script::strict::createVar(Script* image, Script::header *scr, const char *id)
960 {
961  assert(id && *id);
962  assert(scr != NULL);
963  assert(image != NULL);
964 
965  linked_pointer<Script::strict> sp;
966  Script::strict *sym;
967 
968  if(*id == '%' || *id == '=' || *id == '$')
969  ++id;
970 
971  if(!image->global)
972  return;
973 
974  if(*(scr->name) != '@') {
975  sp = scr->scoped;
976  while(is(sp)) {
977  if(ideq(sp->id, id))
978  return;
979  sp.next();
980  }
981  sym = (Script::strict *)image->zalloc(sizeof(Script::strict));
982  sym->enlist(&scr->scoped);
983  sym->id = id;
984  return;
985  }
986  sp = image->global;
987  while(is(sp)) {
988  if(ideq(sp->id, id))
989  return;
990  sp.next();
991  }
992  sym = (Script::strict *)image->zalloc(sizeof(Script::strict));
993  sym->enlist(&image->global);
994  sym->id = id;
995 }
996 
997 void Script::strict::createSym(Script* image, Script::header *scr, const char *id)
998 {
999  assert(id && *id);
1000  assert(scr != NULL);
1001  assert(image != NULL);
1002 
1003  linked_pointer<Script::strict> sp;
1004  Script::strict *sym;
1005 
1006  if(*id == '%' || *id == '=' || *id == '$')
1007  ++id;
1008 
1009  if(scr && !image->global)
1010  return;
1011 
1012  if(*(scr->name) != '@') {
1013  sp = scr->scoped;
1014  while(is(sp)) {
1015  if(ideq(sp->id, id))
1016  return;
1017  sp.next();
1018  }
1019  }
1020  sp = image->global;
1021  while(is(sp)) {
1022  if(ideq(sp->id, id))
1023  return;
1024  sp.next();
1025  }
1026  sym = (Script::strict *)image->zalloc(sizeof(Script::strict));
1027  sym->enlist(&image->global);
1028  sym->id = id;
1029 }
1030 
1031 void Script::strict::createAny(Script* image, Script::header *scr, const char *id)
1032 {
1033  assert(id && *id);
1034  assert(scr != NULL);
1035  assert(image != NULL);
1036 
1037  linked_pointer<Script::strict> sp;
1038  Script::strict *sym;
1039 
1040  if(*id == '%' || *id == '=' || *id == '$')
1041  ++id;
1042 
1043  if(scr && !image->global)
1044  return;
1045 
1046  if(*(scr->name) != '@') {
1047  sp = scr->scoped;
1048  while(is(sp)) {
1049  if(ideq(sp->id, id))
1050  return;
1051  sp.next();
1052  }
1053  }
1054  sp = image->global;
1055  while(is(sp)) {
1056  if(ideq(sp->id, id))
1057  return;
1058  sp.next();
1059  }
1060  sym = (Script::strict *)image->zalloc(sizeof(Script::strict));
1061  if(*(scr->name) != '@')
1062  sym->enlist(&scr->scoped);
1063  else
1064  sym->enlist(&image->global);
1065  sym->id = id;
1066 }
1067 
1068 void Script::strict::createGlobal(Script *image, const char *id)
1069 {
1070  assert(id && *id);
1071  assert(image != NULL);
1072 
1073  linked_pointer<Script::strict> sp;
1074  Script::strict *sym;
1075 
1076  if(*id == '%' || *id == '=' || *id == '$')
1077  ++id;
1078 
1079  sp = image->global;
1080  while(is(sp)) {
1081  if(ideq(sp->id, id))
1082  return;
1083  sp.next();
1084  }
1085  sym = (Script::strict *)image->zalloc(sizeof(Script::strict));
1086  sym->enlist(&image->global);
1087  sym->id = id;
1088 }
1089 
1090 bool Script::strict::find(Script* image, Script::header *scr, const char *id)
1091 {
1092  assert(id && *id);
1093  assert(scr != NULL);
1094  assert(image != NULL);
1095 
1096  char buf[64];
1097  const char *cp;
1098  char *ep;
1099  linked_pointer<Script::strict> sp;
1100 
1101  if(!image->global)
1102  return true;
1103 
1104  if(*id != '%' && *id != '$')
1105  return true;
1106 
1107  if(eq(id, "$map/", 5)) {
1108  buf[0] = '%';
1109  String::set(buf + 1, sizeof(buf) - 1, id + 5);
1110  ep = strchr(buf, ':');
1111  if(ep)
1112  *ep = 0;
1113 
1114  if(!find(image, scr, buf))
1115  return false;
1116  }
1117 
1118  if(*id == '$') {
1119  cp = strchr(id, ':');
1120  if(cp)
1121  id = ++cp;
1122  else
1123  ++id;
1124  }
1125  else
1126  ++id;
1127 
1128  if(*(scr->name) != '@') {
1129  sp = scr->scoped;
1130  while(is(sp)) {
1131  if(ideq(sp->id, id))
1132  return true;
1133  sp.next();
1134  }
1135  }
1136 
1137  sp = image->global;
1138  while(is(sp)) {
1139  if(ideq(sp->id, id))
1140  return true;
1141  sp.next();
1142  }
1143  return false;
1144 }
1145 
1146 void Script::strict::put(FILE *fp, const char *header)
1147 {
1148  assert(fp != NULL);
1149  assert(id != NULL);
1150 
1151  const char *pid = id;
1152  if(header) {
1153  fputs(header, fp);
1154  fputc(':', fp);
1155  }
1156  while(*pid && *pid != ':')
1157  fputc(*(pid++), fp);
1158  fputc('\n', fp);
1159 }
1160 
1161 unsigned Script::count(const char *data)
1162 {
1163  unsigned count = 0;
1164  char quote = 0;
1165  unsigned paren = 0;
1166 
1167  if(!data || !*data)
1168  return 0;
1169 
1170  ++count;
1171  while(*data) {
1172  if(*data == ',' && !quote && !paren)
1173  ++count;
1174  else if(*data == quote && !paren)
1175  quote = 0;
1176  else if(*data == '\"' && !paren)
1177  quote = *data;
1178  else if(*data == '(' && !quote)
1179  ++paren;
1180  else if(*data == ')' && !quote)
1181  --paren;
1182  ++data;
1183  }
1184  return count;
1185 }
1186 
1187 void Script::copy(const char *list, char *item, unsigned size)
1188 {
1189  assert(size > 0);
1190  assert(item != NULL);
1191 
1192  bool lead = false;
1193  char quote = 0;
1194  char prev = 0;
1195  unsigned paren = 0;
1196  bool leadparen = false;
1197 
1198  if(!list || !*list || *list == ',') {
1199  *item = 0;
1200  return;
1201  }
1202 
1203  while(isspace(*list))
1204  ++list;
1205 
1206  if(*list == '(') {
1207  leadparen = true;
1208  ++paren;
1209  ++list;
1210  }
1211  else {
1212  if(*list == '\"' || *list == '\'') {
1213  quote = *(list++);
1214  lead = true;
1215  }
1216  }
1217 
1218  while(--size && *list) {
1219  if(paren == 1 && leadparen && *list == ')' && !quote)
1220  break;
1221  if(*list == '(')
1222  ++paren;
1223  else if(*list == ')')
1224  --paren;
1225  if(*list == ',' && !quote && !paren)
1226  break;
1227  if(*list == quote && lead)
1228  break;
1229  if(*list == quote) {
1230  *(item++) = quote;
1231  break;
1232  }
1233  if(!quote && *list == '\"' && prev == '=' && !paren)
1234  quote = *list;
1235  prev = *item;
1236  *(item++) = *(list++);
1237  }
1238  *item = 0;
1239 }
1240 
1241 unsigned Script::offset(const char *list, unsigned index)
1242 {
1243  const char *cp = get(list, index);
1244  return cp - list;
1245 }
1246 
1247 const char *Script::get(const char *list, unsigned index)
1248 {
1249  char quote = 0;
1250  unsigned paren = 0;
1251 
1252  if(!list || !*list)
1253  return NULL;
1254 
1255  if(!index)
1256  return list;
1257 
1258  while(*list && index) {
1259  if(*list == ',' && !quote && !paren) {
1260  --index;
1261  if(!index)
1262  return ++list;
1263  } else if(*list == quote)
1264  quote = 0;
1265  else if(*list == '(' && !quote)
1266  ++paren;
1267  else if(*list == ')' && !quote)
1268  --paren;
1269  else if(*list == '\"' && !paren)
1270  quote = *list;
1271  ++list;
1272  }
1273  return NULL;
1274 }
1275 
1276 char *Script::get(char *list, unsigned index)
1277 {
1278  char quote = 0;
1279  unsigned paren = 0;
1280 
1281  if(!list || !*list)
1282  return NULL;
1283 
1284  if(!index)
1285  return list;
1286 
1287  while(*list && index) {
1288  if(*list == ',' && !quote && !paren) {
1289  --index;
1290  if(!index)
1291  return ++list;
1292  } else if(*list == quote)
1293  quote = 0;
1294  else if(*list == '(' && !quote)
1295  ++paren;
1296  else if(*list == ')' && !quote)
1297  --paren;
1298  else if(*list == '\"' && !paren)
1299  quote = *list;
1300  ++list;
1301  }
1302  return NULL;
1303 }
1304 
#define BAYONNE_NAMESPACE
Definition: bayonne.h:25
GNU Bayonne library namespace.