1 // Copyright (C) 2008-2011 David Sugar, Tycho Softworks.
2 //
3 // This file is part of GNU Bayonne.
4 //
5 // GNU Bayonne is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // GNU Bayonne is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with GNU Bayonne. If not, see <http://www.gnu.org/licenses/>.
17
18 #include <config.h>
19 #include <ucommon/ucommon.h>
20 #include <ucommon/export.h>
22
24 using namespace UCOMMON_NAMESPACE;
25
26 bool Script::methods::scrDo(void)
27 {
28 push();
29 skip();
30 return true;
31 }
32
33 bool Script::methods::scrPrevious(void)
34 {
35 --frame;
36 if(stack[frame].index < 2) {
37 stack[frame].index = 0;
38 skip();
39 return scrBreak();
40 }
41 stack[frame].index -= 2;
42 return true;
43 }
44
45 bool Script::methods::scrExpand(void)
46 {
47 unsigned index = 1;
48 Script::line_t *line = stack[frame].line;
49 const char *tuples = getContent(line->argv[0]);
50 unsigned tcount = Script::count(tuples);
51 Script::symbol *sym;
52 const char *cp;
53
54 while(line->argv[index]) {
55 sym = find(line->argv[index]);
56
57 if(!sym)
58 sym = getVar(line->argv[index]);
59
60 if(!sym)
61 return error("symbol not found");
62
63 if(!sym->size)
64 return error("symbol not writable");
65
66 if(index > tcount)
67 String::set(sym->data, sym->size + 1, "");
68 else {
69 cp = Script::get(tuples, index - 1);
70 Script::copy(cp, sym->data, sym->size + 1);
71 }
72 ++index;
73 }
74 skip();
75 return true;
76 }
77
78 bool Script::methods::scrForeach(void)
79 {
80 Script::line_t *line = stack[frame].line;
81 Script::symbol *sym = find(line->argv[0]);
82 const char *cp;
83 unsigned index = stack[frame].index;
84
85 if(!sym)
86 sym = getVar(line->argv[0]);
87
88 if(!sym)
89 return error("symbol not found");
90
91 if(!sym->size)
92 return error("symbol not writable");
93
94 if(!index) {
95 cp = line->argv[2];
96 if(cp && (*cp == '%' || *cp == '&')) {
97 Script::symbol *skip = find(cp);
98 if(!skip)
99 skip = getVar(cp);
100 if(skip) {
101 index = atoi(skip->data);
102 if(skip->size)
103 String::set(skip->data, 2, "0");
104 }
105 }
106 else if(NULL != (cp = getContent(cp))) {
107 cp = getContent(cp);
108 if(cp)
109 index = atoi(cp);
110 }
111 }
112
113 cp = Script::get(getContent(line->argv[1]), index);
114 if(cp == NULL) {
115 stack[frame].index = 0;
116 skip();
117 return scrBreak();
118 }
119
120 Script::copy(cp, sym->data, sym->size + 1);
121 stack[frame].index = ++index;
122 push();
123 skip();
124 return true;
125 }
126
127 bool Script::methods::scrWhile(void)
128 {
129 if(isConditional(0)) {
130 push();
131 skip();
132 return true;
133 }
134 skip();
135 return scrBreak();
136 }
137
138 bool Script::methods::scrEndcase(void)
139 {
140 pullLoop();
141 return true;
142 }
143
144 bool Script::methods::scrCase(void)
145 {
146 Script::method_t method = getLooping();
147 Script::line_t *line = stack[frame].line;
148
149 if(method == (method_t)&Script::methods::scrCase) {
150 skip();
151 while(stack[frame].line && stack[frame].line->loop > line->loop)
152 skip();
153 return true;
154 }
155
156 if(isConditional(0)) {
157 push();
158 skip();
159 return true;
160 }
161
162 return scrOtherwise();
163
164 if(stack[frame].line->method == (method_t)&Script::methods::scrOtherwise) {
165 push();
166 skip();
167 return false;
168 }
169 return false;
170 }
171
172 bool Script::methods::scrOtherwise(void)
173 {
174 Script::line_t *line = stack[frame].line;
175
176 skip();
177 while(stack[frame].line && stack[frame].line->loop > line->loop)
178 skip();
179
180 return true;
181 }
182
183 bool Script::methods::scrUntil(void)
184 {
185 if(isConditional(0))
186 pullLoop();
187 else
188 --frame;
189 return true;
190 }
191
192 bool Script::methods::scrLoop(void)
193 {
194 --frame;
195 return true;
196 }
197
198 bool Script::methods::scrElif(void)
199 {
200 return scrElse();
201 }
202
203 bool Script::methods::scrEndif(void)
204 {
205 return scrNop();
206 }
207
208 bool Script::methods::scrDefine(void)
209 {
210 return scrNop();
211 }
212
213 bool Script::methods::scrInvoke(void)
214 {
215 Script::line_t *line = stack[frame].line;
216 unsigned mask;
217
218 getParams(line->sub, line->sub->first);
219 getParams(line->sub, line);
220
221 skip(); // return to next line
222 push(); // push where we are
223 stack[frame].scope = line->sub;
224 stack[frame].line = line->sub->first->next;
225 startScript(line->sub);
226
227 mask = stack[frame].resmask |= line->sub->resmask;
228 if(mask != stack[frame].resmask) {
229 stack[frame].resmask = mask;
230 return false;
231 }
232 return true;
233 }
234
235 bool Script::methods::scrElse(void)
236 {
237 Script::line_t *line = stack[frame].line;
238 unsigned loop = 0;
239
240 skip();
241 while(NULL != (line = stack[frame].line)) {
242 if(line->method == (method_t)&Script::methods::scrIf)
243 ++loop;
244 else if(line->method == (method_t)&Script::methods::scrEndif) {
245 if(!loop) {
246 skip();
247 return true;
248 }
249 --loop;
250 }
251 skip();
252 }
253 return true;
254 }
255
256 bool Script::methods::scrIf(void)
257 {
258 Script::line_t *line = stack[frame].line;
259 unsigned loop = 0;
260
261 if(isConditional(0)) {
262 skip();
263 return true;
264 }
265
266 skip();
267 while(NULL != (line = stack[frame].line)) {
268 if(line->method == (method_t)&Script::methods::scrIf)
269 ++loop;
270 else if(line->method == (method_t)&Script::methods::scrEndif) {
271 if(!loop) {
272 skip();
273 return true;
274 }
275 --loop;
276 }
277 else if(!loop && line->method == (method_t)&Script::methods::scrElse) {
278 skip();
279 return true;
280 }
281 else if(!loop && line->method == (method_t)&Script::methods::scrElif) {
282 if(isConditional(0)) {
283 skip();
284 return true;
285 }
286 }
287 skip();
288 }
289 return false;
290 }
291
292 bool Script::methods::scrPause(void)
293 {
294 return false;
295 }
296
297 bool Script::methods::scrBreak(void)
298 {
299 Script::line_t *line = stack[frame].line;
300 Script::method_t method = getLooping();
301
302 if(method == (method_t)&Script::methods::scrCase || method == (method_t)&Script::methods::scrOtherwise) {
303 skip();
304 while(stack[frame].line && stack[frame].line->loop >= line->loop)
305 skip();
306 return true;
307 }
308
309 pullLoop();
310 while(stack[frame].line && stack[frame].line->loop >= line->loop)
311 skip();
312 return true;
313 }
314
315 bool Script::methods::scrRepeat(void)
316 {
317 --frame;
318 --stack[frame].index;
319 return true;
320 }
321
322 bool Script::methods::scrContinue(void)
323 {
324 --frame;
325 return true;
326 }
327
328 bool Script::methods::scrNop(void)
329 {
330 skip();
331 return true;
332 }
333
334 bool Script::methods::scrWhen(void)
335 {
336 if(!isConditional(0))
337 skip();
338
339 skip();
340 return true;
341 }
342
343 bool Script::methods::scrExit(void)
344 {
345 frame = 0;
346 stack[frame].line = NULL;
347 return false;
348 }
349
350 bool Script::methods::scrRestart(void)
351 {
352 unsigned mask = stack[frame].resmask;
353 pullBase();
354 setStack(stack[frame].scr);
355 if(mask == stack[frame].resmask)
356 return true;
357 return false;
358 }
359
360 bool Script::methods::scrGoto(void)
361 {
362 Script::line_t *line = stack[frame].line;
363 const char *cp;
364 Script::header *scr = NULL;
365 unsigned index = 0;
366 unsigned mask = stack[frame].resmask;
367
368 while(!scr && index < line->argc) {
369 cp = line->argv[index++];
370 if(*cp == '^') {
371 if(scriptEvent(++cp))
372 return true;
373 }
374 else
375 scr = Script::find(*image, line->argv[0]);
376 }
377 if(!scr)
378 return error("label not found");
379
380 pullBase();
381 setStack(scr);
382 startScript(scr);
383 if(mask == stack[frame].resmask)
384 return true;
385 return false;
386 }
387
388 bool Script::methods::scrGosub(void)
389 {
390 unsigned index = stack[frame].index;
391 Script::line_t *line = stack[frame].line;
392 Script::header *scr = NULL;
393 const char *cp;
394 unsigned mask = stack[frame].resmask;
395 Script::event *ev = NULL;
396
397 while(ev == NULL && scr == NULL && index < line->argc) {
398 cp = line->argv[index++];
399 if(*cp == '@') {
400 scr = Script::find(*image, cp);
401 if(!scr && image->shared.get())
402 scr = Script::find(image->shared.get(), cp);
403 }
404 else
405 ev = scriptMethod(cp);
406 }
407
408 if(!scr && !ev) {
409 if(!stack[frame].index)
410 return error("label not found");
411
412 stack[frame].index = 0;
413 skip();
414 return true;
415 }
416
417 stack[frame].index = index; // save index for re-call on return...
418 push();
419 if(scr) {
420 setStack(scr);
421 startScript(scr);
422 stack[frame].base = frame; // set base level to new script...
423 if(mask == stack[frame].resmask)
424 return true;
425 }
426 else {
427 stack[frame].line = ev->first;
428 stack[frame].index = 0;
429 return true;
430 }
431 return false;
432 }
433
434 bool Script::methods::scrReturn(void)
435 {
436 unsigned mask = stack[frame].resmask;
437 if(!pop())
438 return scrExit();
439
440 if(mask == stack[frame].resmask)
441 return true;
442 return false;
443 }
444
445 bool Script::methods::scrIndex(void)
446 {
447 const char *op;
448 int result = 0, value;
449
450 stack[frame].index = 0;
451 result = atoi(getValue());
452
453 while(NULL != (op = getValue())) {
454 switch(*op) {
455 case '+':
456 result += atoi(getValue());
457 break;
458 case '-':
459 result -= atoi(getValue());
460 break;
461 case '*':
462 result *= atoi(getValue());
463 break;
464 case '/':
465 value = atoi(getValue());
466 if(value == 0)
467 return error("div by zero");
468 result /= value;
469 break;
470 case '#':
471 value = atoi(getValue());
472 if(value == 0)
473 return error("div by zero");
474 result %= value;
475 break;
476 }
477 }
478
479 --frame;
480 if(!result) {
481 skip();
482 return scrBreak();
483 }
484 else
485 stack[frame].index = --result;
486
487 return true;
488 }
489
490 bool Script::methods::scrRef(void)
491 {
492 const char *cp = stack[frame].line->argv[0];
493 cp = getContent(cp);
494 skip();
495 return true;
496 }
497
498 bool Script::methods::scrExpr(void)
499 {
500 unsigned exdecimals = Script::decimals;
501 const char *id, *cp, *op, *aop;
502 double result, value;
503 long lvalue;
504 char cvt[8];
505 char buf[32];
506
507 stack[frame].index = 0;
508
509 cp = getKeyword("decimals");
510 if(cp)
511 exdecimals = atoi(cp);
512
513 id = getContent();
514 aop = getValue();
515 result = atof(getValue());
516
517 while(NULL != (op = getValue())) {
518 switch(*op) {
519 case '+':
520 result += atof(getValue());
521 break;
522 case '-':
523 result -= atof(getValue());
524 break;
525 case '*':
526 result *= atof(getValue());
527 break;
528 case '/':
529 value = atof(getValue());
530 if(value == 0.) {
531 return error("div by zero");
532 }
533 result /= value;
534 break;
535 case '#':
536 lvalue = atol(getValue());
537 if(lvalue == 0)
538 return error("div by zero");
539 result = (long)result % lvalue;
540 }
541 }
542 cp = getContent(id);
543 if(cp)
544 value = atof(cp);
545 else
546 value = 0;
547 if(eq(aop, "+="))
548 value += result;
549 else if(eq(aop, "#="))
550 value = (long)value % (long)result;
551 else if(eq(aop, "-="))
552 value -= result;
553 else if(eq(aop, "*="))
554 value *= result;
555 else if(eq(aop, "/=") && result)
556 value /= result;
557 else if(eq(aop, "?=") || eq(aop, ":="))
558 value = result;
559
560 stack[frame].index = 0;
561 cvt[0] = '%';
562 cvt[1] = '.';
563 cvt[2] = '0' + exdecimals;
564 cvt[3] = 'f';
565 cvt[4] = 0;
566 snprintf(buf, sizeof(buf), cvt, value);
567
568 if(!getVar(id, buf))
569 return error("invalid symbol");
570
571 skip();
572 return true;
573 }
574
575 bool Script::methods::scrVar(void)
576 {
577 unsigned index = 0;
578 Script::line_t *line = stack[frame].line;
579 const char *id;
580
581 while(index < line->argc) {
582 id = line->argv[index++];
583 if(*id == '=') {
584 if(!getVar(++id, getContent(line->argv[index++])))
585 return error("invalid symbol");
586 }
587 else {
588 if(!getVar(id))
589 return error("invalid symbol");
590 }
591 }
592 skip();
593 return true;
594 }
595
596 bool Script::methods::scrConst(void)
597 {
598 unsigned index = 0;
599 Script::line_t *line = stack[frame].line;
600 const char *id;
601
602 while(index < line->argc) {
603 id = line->argv[index++];
604 if(*id == '=') {
605 if(!setConst(++id, getContent(line->argv[index++])))
606 return error("invalid constant");
607 }
608 }
609 skip();
610 return true;
611 }
612
613 bool Script::methods::scrError(void)
614 {
615 char msg[65];
616 unsigned index = 0;
617 Script::line_t *line = stack[frame].line;
618 bool space = false;
619 const char *cp;
620
621 msg[0] = 0;
622 while(index < line->argc) {
623 if(space) {
624 String::add(msg, 65, " ");
625 space = false;
626 }
627 cp = line->argv[index++];
628 if(*cp != '&')
629 space = true;
630 String::add(msg, 65, getContent(cp));
631 }
632 return error(msg);
633 }
634
635 bool Script::methods::scrClear(void)
636 {
637 unsigned index = 0;
638 Script::line_t *line = stack[frame].line;
639 const char *id;
640 Script::symbol *sym;
641
642 while(index < line->argc) {
643 id = line->argv[index++];
644 sym = find(id);
645
646 if(!sym || !sym->size)
647 return error("symbol not found");
648
649 sym->data[0] = 0;
650 }
651 skip();
652 return true;
653 }
654
655 bool Script::methods::scrAdd(void)
656 {
657 unsigned index = 1;
658 Script::line_t *line = stack[frame].line;
659 Script::symbol *sym = find(line->argv[0]);
660 const char *cp;
661
662 if(!sym)
663 sym = getVar(line->argv[0]);
664
665 if(!sym)
666 return error("symbol not found");
667
668 if(!sym->size)
669 return error("symbol not writable");
670
671 while(index < line->argc) {
672 cp = getContent(line->argv[index++]);
673 String::add(sym->data, sym->size + 1, cp);
674 }
675 skip();
676 return true;
677 }
678
679 bool Script::methods::scrPack(void)
680 {
681 unsigned index = 1;
682 Script::line_t *line = stack[frame].line;
683 Script::symbol *sym = find(line->argv[0]);
684 const char *cp;
685 char quote[2] = {0,0};
686
687 if(!sym)
688 sym = getVar(line->argv[0]);
689
690 if(!sym)
691 return error("symbol not found");
692
693 if(!sym->size)
694 return error("symbol not writable");
695
696 while(index < line->argc) {
697 cp = line->argv[index++];
698 if(*cp == '=') {
699 if(sym->data[0])
700 String::add(sym->data, sym->size + 1, ",");
701
702 String::add(sym->data, sym->size + 1, ++cp);
703 String::add(sym->data, sym->size + 1, "=");
704 cp = getContent(line->argv[index++]);
705 quote[0] = '\'';
706 goto add;
707 }
708 else {
709 cp = getContent(cp);
710 quote[0] = 0;
711 add:
712 if(sym->data[0])
713 String::add(sym->data, sym->size + 1, ",");
714
715 if(!quote[0] && strchr(cp, ',')) {
716 if(*cp != '\'' && *cp != '\"')
717 quote[0] = '\'';
718 }
719 // tuple nesting...
720 if(!quote[0] && *cp == '\'')
721 quote[0] = '(';
722 if(quote[0])
723 String::add(sym->data, sym->size + 1, quote);
724 String::add(sym->data, sym->size + 1, cp);
725 if(quote[0] == '(')
726 quote[0] = ')';
727 if(quote[0])
728 String::add(sym->data, sym->size + 1, quote);
729 }
730 }
731 skip();
732 return true;
733 }
734
735 bool Script::methods::scrPush(void)
736 {
737 Script::line_t *line = stack[frame].line;
738 Script::symbol *sym = createSymbol(line->argv[0]);
739 unsigned size = 0;
740 bool qflag = false;
741 const char *key = NULL, *value;
742
743 if(!sym)
744 return error("invalid symbol id");
745
746 if(!sym->size)
747 return error("symbol not writable");
748
749 if(line->argv[2]) {
750 key = line->argv[1];
751 value = line->argv[2];
752 }
753 else
754 value = line->argv[1];
755
756 if(key)
757 size = strlen(key) + 1;
758
759 if(*value != '\"' && *value != '\'') {
760 qflag = true;
761 size += 2;
762 }
763 size += strlen(value);
764
765 size = strlen(line->argv[1]) + 3;
766 if(line->argv[2])
767 size += strlen(line->argv[2]);
768
769 if(strlen(sym->data) + size > sym->size)
770 return error("symbol too small");
771
772 if(sym->data[0])
773 String::add(sym->data, sym->size + 1, ",");
774
775 size = strlen(sym->data);
776 if(key && qflag)
777 snprintf(sym->data + size, sym->size + 1 - size, "%s='%s'", key, value);
778 else if(key)
779 snprintf(sym->data + size, sym->size + 1 - size, "%s=%s", key, value);
780 else if(qflag)
781 snprintf(sym->data + size, sym->size + 1 - size, "'%s'", value);
782 else
783 String::set(sym->data + size, sym->size + 1, value);
784 skip();
785 return true;
786 }
787
788 bool Script::methods::scrSet(void)
789 {
790 unsigned index = 1;
791 Script::line_t *line = stack[frame].line;
792 Script::symbol *sym = createSymbol(line->argv[0]);
793 const char *cp;
794
795 if(!sym)
796 return error("invalid symbol id");
797
798 if(!sym->size)
799 return error("symbol not writable");
800
801 sym->data[0] = 0;
802 while(index < line->argc) {
803 cp = getContent(line->argv[index++]);
804 String::add(sym->data, sym->size + 1, cp);
805 }
806 skip();
807 return true;
808 }
809
#define BAYONNE_NAMESPACE
GNU Bayonne library namespace.