2 Compiles swf code (.sc) files into .swf files.
4 Part of the swftools package.
6 Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
8 This program 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 2 of the License, or
11 (at your option) any later version.
13 This program 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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
29 #include "../config.h"
30 #include "../lib/rfxswf.h"
31 #include "../lib/drawer.h"
32 #include "../lib/log.h"
33 #include "../lib/args.h"
40 static char * filename = 0;
41 static char * outputname = "output.swf";
42 static int verbose = 2;
43 static int override_outputname = 0;
45 static struct options_t options[] = {
53 int args_callback_option(char*name,char*val)
55 if(!strcmp(name, "V")) {
56 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
59 else if(!strcmp(name, "o")) {
61 override_outputname = 1;
64 else if(!strcmp(name, "v")) {
69 printf("Unknown option: -%s\n", name);
74 int args_callback_longoption(char*name,char*val)
76 return args_long2shortoption(options, name, val);
78 void args_callback_usage(char *name)
81 printf("Usage: %s [-o file.swf] file.sc\n", name);
83 printf("-h , --help Print short help message and exit\n");
84 printf("-V , --version Print version info and exit\n");
85 printf("-v , --verbose Increase verbosity. \n");
86 printf("-o , --output <filename> Set output file to <filename>.\n");
89 int args_callback_command(char*name,char*val)
92 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
99 static struct token_t* file;
108 static void syntaxerror(char*format, ...)
112 va_start(arglist, format);
113 vsprintf(buf, format, arglist);
115 printf("\"%s\", line %d column %d: error- %s\n", filename, line, column, buf);
119 static void warning(char*format, ...)
123 va_start(arglist, format);
124 vsprintf(buf, format, arglist);
126 printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
129 static void readToken()
131 type = file[pos].type;
133 syntaxerror("unexpected end of file");
135 text = file[pos].text;
136 textlen = strlen(text);
137 line = file[pos].line;
138 column = file[pos].column;
140 //printf("---> %d(%s) %s\n", type, type_names[type], text);
143 static void pushBack()
146 if(!pos) syntaxerror("internal error 3");
151 textlen = strlen(text);
154 column = file[p].column;
157 static int noMoreTokens()
159 if(file[pos].type == END)
164 // ------------------------------ swf routines ----------------------------
168 int type; //0=swf, 1=sprite, 2=clip, 3=button
174 /* for sprites (1): */
180 dictionary_t oldinstances;
185 static int stackpos = 0;
187 static dictionary_t characters;
188 static dictionary_t images;
189 static dictionary_t outlines;
190 static dictionary_t gradients;
191 static char idmap[65536];
192 static TAG*tag = 0; //current tag
194 static int id; //current character id
195 static int currentframe; //current frame in current level
196 static SRECT currentrect; //current bounding box in current level
197 static U16 currentdepth;
198 static dictionary_t instances;
199 static dictionary_t fonts;
200 static dictionary_t sounds;
202 typedef struct _parameters {
204 float scalex, scaley;
212 typedef struct _character {
218 typedef struct _instance {
219 character_t*character;
221 parameters_t parameters;
222 TAG* lastTag; //last tag which set the object
223 U16 lastFrame; //frame lastTag is in
226 typedef struct _outline {
231 typedef struct _gradient {
237 static void character_init(character_t*c)
239 memset(c, 0, sizeof(character_t));
241 static character_t* character_new()
244 c = (character_t*)malloc(sizeof(character_t));
248 static void instance_init(instance_t*i)
250 memset(i, 0, sizeof(instance_t));
252 static instance_t* instance_new()
255 c = (instance_t*)malloc(sizeof(instance_t));
260 static void incrementid()
264 syntaxerror("Out of character ids.");
269 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
271 character_t* c = character_new();
273 c->definingTag = ctag;
276 if(dictionary_lookup(&characters, name))
277 syntaxerror("character %s defined twice", name);
278 dictionary_put2(&characters, name, c);
280 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
282 swf_SetString(tag, name);
283 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
286 swf_SetString(tag, name);
288 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
290 character_t* c = character_new();
291 c->definingTag = ctag;
295 if(dictionary_lookup(&images, name))
296 syntaxerror("image %s defined twice", name);
297 dictionary_put2(&images, name, c);
299 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
301 instance_t* i = instance_new();
304 //swf_GetMatrix(0, &i->matrix);
305 if(dictionary_lookup(&instances, name))
306 syntaxerror("object %s defined twice", name);
307 dictionary_put2(&instances, name, i);
311 static void parameters_set(parameters_t*p, int x,int y, float scalex, float scaley, float rotate, float shear, SPOINT pivot, SPOINT pin, CXFORM cxform)
314 p->scalex = scalex; p->scaley = scaley;
315 p->pin = pin; p->pivot = pivot;
316 p->rotate = rotate; p->cxform = cxform;
320 static void parameters_clear(parameters_t*p)
323 p->scalex = 1.0; p->scaley = 1.0;
326 p->pivot.x = 0; p->pivot.y = 0;
329 swf_GetCXForm(0, &p->cxform, 1);
332 static void makeMatrix(MATRIX*m, parameters_t*p)
341 sx = p->scalex*cos(p->rotate/360*2*3.14159265358979);
342 r1 = -p->scalex*sin(p->rotate/360*2*3.14159265358979)+sx*p->shear;
343 r0 = p->scaley*sin(p->rotate/360*2*3.14159265358979);
344 sy = p->scaley*cos(p->rotate/360*2*3.14159265358979)+r0*p->shear;
346 m->sx = (int)(sx*65536+0.5);
347 m->r1 = (int)(r1*65536+0.5);
348 m->r0 = (int)(r0*65536+0.5);
349 m->sy = (int)(sy*65536+0.5);
353 h = swf_TurnPoint(p->pin, m);
358 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
363 r = swf_TurnRect(rect, &m);
364 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
365 currentrect.xmax == 0 && currentrect.ymax == 0)
368 swf_ExpandRect2(¤trect, &r);
372 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
374 SWF*swf = (SWF*)malloc(sizeof(SWF));
377 syntaxerror(".swf blocks can't be nested");
379 memset(swf, 0, sizeof(swf));
380 swf->fileVersion = version;
382 swf->frameRate = fps;
383 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
384 swf->compressed = compress;
385 swf_SetRGB(tag,&background);
387 if(stackpos==sizeof(stack)/sizeof(stack[0]))
388 syntaxerror("too many levels of recursion");
390 dictionary_init(&characters);
391 dictionary_init(&images);
392 dictionary_init(&outlines);
393 dictionary_init(&gradients);
394 dictionary_init(&instances);
395 dictionary_init(&fonts);
396 dictionary_init(&sounds);
398 memset(&stack[stackpos], 0, sizeof(stack[0]));
399 stack[stackpos].type = 0;
400 stack[stackpos].filename = strdup(name);
401 stack[stackpos].swf = swf;
402 stack[stackpos].oldframe = -1;
407 memset(¤trect, 0, sizeof(currentrect));
410 memset(idmap, 0, sizeof(idmap));
414 void s_sprite(char*name)
416 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
417 swf_SetU16(tag, id); //id
418 swf_SetU16(tag, 0); //frames
420 memset(&stack[stackpos], 0, sizeof(stack[0]));
421 stack[stackpos].type = 1;
422 stack[stackpos].oldframe = currentframe;
423 stack[stackpos].olddepth = currentdepth;
424 stack[stackpos].oldrect = currentrect;
425 stack[stackpos].oldinstances = instances;
426 stack[stackpos].tag = tag;
427 stack[stackpos].id = id;
428 stack[stackpos].name = strdup(name);
430 /* FIXME: those four fields should be bundled together */
431 dictionary_init(&instances);
434 memset(¤trect, 0, sizeof(currentrect));
440 typedef struct _buttonrecord
448 typedef struct _button
452 buttonrecord_t records[4];
455 static button_t mybutton;
457 void s_button(char*name)
459 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
460 swf_SetU16(tag, id); //id
461 swf_ButtonSetFlags(tag, 0); //menu=no
463 memset(&mybutton, 0, sizeof(mybutton));
465 memset(&stack[stackpos], 0, sizeof(stack[0]));
466 stack[stackpos].type = 3;
467 stack[stackpos].tag = tag;
468 stack[stackpos].id = id;
469 stack[stackpos].name = strdup(name);
470 stack[stackpos].oldrect = currentrect;
471 memset(¤trect, 0, sizeof(currentrect));
476 void s_buttonput(char*character, char*as, parameters_t p)
478 character_t* c = dictionary_lookup(&characters, character);
483 if(!stackpos || (stack[stackpos-1].type != 3)) {
484 syntaxerror(".show may only appear in .button");
487 syntaxerror("character %s not known (in .shape %s)", character, character);
489 if(mybutton.endofshapes) {
490 syntaxerror("a .do may not precede a .show", character, character);
493 m = s_instancepos(c->size, &p);
501 if(*s==',' || *s==0) {
502 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
503 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
504 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
505 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
506 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
507 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
514 static void setbuttonrecords(TAG*tag)
516 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
517 if(!mybutton.endofshapes) {
520 if(!mybutton.records[3].set) {
521 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
525 if(mybutton.records[t].set) {
526 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
529 swf_SetU8(tag,0); // end of button records
530 mybutton.endofshapes = 1;
534 void s_buttonaction(int flags, char*action)
540 setbuttonrecords(stack[stackpos-1].tag);
542 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
544 syntaxerror("Couldn't compile ActionScript");
547 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
548 swf_ActionSet(stack[stackpos-1].tag, a);
549 mybutton.nr_actions++;
554 static void setactionend(TAG*tag)
556 if(!mybutton.nr_actions) {
557 /* no actions means we didn't have an actionoffset,
558 which means we can't signal the end of the
559 buttonaction records, so, *sigh*, we have
560 to insert a dummy record */
561 swf_SetU16(tag, 0); //offset
562 swf_SetU16(tag, 0); //condition
563 swf_SetU8(tag, 0); //action
567 static void s_endButton()
570 setbuttonrecords(stack[stackpos-1].tag);
571 setactionend(stack[stackpos-1].tag);
574 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
578 tag = stack[stackpos].tag;
579 currentrect = stack[stackpos].oldrect;
581 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
582 free(stack[stackpos].name);
585 TAG* removeFromTo(TAG*from, TAG*to)
587 TAG*save = from->prev;
589 TAG*next = from->next;
597 static void s_endSprite()
599 SRECT r = currentrect;
601 if(stack[stackpos].cut)
602 tag = removeFromTo(stack[stackpos].cut, tag);
606 /* TODO: before clearing, prepend "<spritename>." to names and
607 copy into old instances dict */
608 dictionary_clear(&instances);
610 currentframe = stack[stackpos].oldframe;
611 currentrect = stack[stackpos].oldrect;
612 currentdepth = stack[stackpos].olddepth;
613 instances = stack[stackpos].oldinstances;
615 tag = swf_InsertTag(tag, ST_END);
617 tag = stack[stackpos].tag;
620 syntaxerror("internal error(7)");
622 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
623 free(stack[stackpos].name);
626 static void s_endSWF()
632 if(stack[stackpos].cut)
633 tag = removeFromTo(stack[stackpos].cut, tag);
637 swf = stack[stackpos].swf;
638 filename = stack[stackpos].filename;
640 //tag = swf_InsertTag(tag, ST_SHOWFRAME); //?
642 tag = swf_InsertTag(tag, ST_END);
644 swf_OptimizeTagOrder(swf);
648 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
649 swf->movieSize = currentrect; /* "autocrop" */
652 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
653 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
654 swf->movieSize.ymax += 20;
657 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
659 syntaxerror("couldn't create output file %s", filename);
662 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
664 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
668 dictionary_clear(&instances);
669 dictionary_clear(&characters);
670 dictionary_clear(&images);
671 dictionary_clear(&outlines);
672 dictionary_clear(&gradients);
673 dictionary_clear(&fonts);
674 dictionary_clear(&sounds);
684 if(stack[stackpos-1].type == 0)
685 syntaxerror("End of file encountered in .flash block");
686 if(stack[stackpos-1].type == 1)
687 syntaxerror("End of file encountered in .sprite block");
688 if(stack[stackpos-1].type == 2)
689 syntaxerror("End of file encountered in .clip block");
698 void s_frame(int nr, int cut, char*name)
703 for(t=currentframe;t<nr;t++) {
704 tag = swf_InsertTag(tag, ST_SHOWFRAME);
705 if(t==nr-1 && name && *name) {
706 tag = swf_InsertTag(tag, ST_FRAMELABEL);
707 swf_SetString(tag, name);
710 if(nr == 0 && currentframe == 0 && name) {
711 tag = swf_InsertTag(tag, ST_FRAMELABEL);
712 swf_SetString(tag, name);
717 syntaxerror("Can't cut, frame empty");
719 stack[stackpos].cut = tag;
725 int parseColor2(char*str, RGBA*color);
727 int addFillStyle(SHAPE*s, SRECT*r, char*texture)
732 if(texture[0] == '#') {
733 parseColor2(texture, &color);
734 return swf_ShapeAddSolidFillStyle(s, &color);
735 } else if((image = dictionary_lookup(&images, texture))) {
737 swf_GetMatrix(0, &m);
738 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
739 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
742 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
743 } /*else if ((texture = dictionary_lookup(&textures, texture))) {
744 } */ else if ((gradient = dictionary_lookup(&gradients, texture))) {
748 swf_GetMatrix(0, &rot);
749 ccos = cos(-gradient->rotate*2*3.14159265358979/360);
750 csin = sin(-gradient->rotate*2*3.14159265358979/360);
752 rot.r1 = -csin*65536;
755 r2 = swf_TurnRect(*r, &rot);
756 swf_GetMatrix(0, &m);
757 m.sx = (r2.xmax - r2.xmin)*2*ccos;
758 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
759 m.r0 = (r2.ymax - r2.ymin)*2*csin;
760 m.sy = (r2.ymax - r2.ymin)*2*ccos;
761 m.tx = r->xmin + (r->xmax - r->xmin)/2;
762 m.ty = r->ymin + (r->ymax - r->ymin)/2;
763 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
764 } else if (parseColor2(texture, &color)) {
765 return swf_ShapeAddSolidFillStyle(s, &color);
767 syntaxerror("not a color/fillstyle: %s", texture);
772 RGBA black={r:0,g:0,b:0,a:0};
773 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
782 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
784 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
787 fs1 = addFillStyle(s, &r2, texture);
790 r.xmin = r2.xmin-linewidth-linewidth/2;
791 r.ymin = r2.ymin-linewidth-linewidth/2;
792 r.xmax = r2.xmax+linewidth+linewidth/2;
793 r.ymax = r2.ymax+linewidth+linewidth/2;
795 swf_SetShapeHeader(tag,s);
796 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
797 swf_ShapeSetLine(tag,s,width,0);
798 swf_ShapeSetLine(tag,s,0,height);
799 swf_ShapeSetLine(tag,s,-width,0);
800 swf_ShapeSetLine(tag,s,0,-height);
801 swf_ShapeSetEnd(tag);
804 s_addcharacter(name, id, tag, r);
808 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
814 outline = dictionary_lookup(&outlines, outlinename);
816 syntaxerror("outline %s not defined", outlinename);
820 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
822 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
824 fs1 = addFillStyle(s, &r2, texture);
826 syntaxerror("non filled outlines not yet supported- please supply a fill=<color/texture> argument");
828 rect.xmin = r2.xmin-linewidth-linewidth/2;
829 rect.ymin = r2.ymin-linewidth-linewidth/2;
830 rect.xmax = r2.xmax+linewidth+linewidth/2;
831 rect.ymax = r2.ymax+linewidth+linewidth/2;
833 swf_SetRect(tag,&rect);
834 swf_SetShapeStyles(tag, s);
835 swf_SetShapeBits(tag, outline->shape); //does not count bits!
836 swf_SetBlock(tag, outline->shape->data, (outline->shape->bitlen+7)/8);
839 s_addcharacter(name, id, tag, rect);
843 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
848 r2.xmin = r2.ymin = 0;
852 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
854 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
856 fs1 = addFillStyle(s, &r2, texture);
858 rect.xmin = r2.xmin-linewidth-linewidth/2;
859 rect.ymin = r2.ymin-linewidth-linewidth/2;
860 rect.xmax = r2.xmax+linewidth+linewidth/2;
861 rect.ymax = r2.ymax+linewidth+linewidth/2;
863 swf_SetRect(tag,&rect);
864 swf_SetShapeHeader(tag,s);
865 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
866 swf_ShapeSetCircle(tag, s, r,r,r,r);
867 swf_ShapeSetEnd(tag);
870 s_addcharacter(name, id, tag, rect);
874 void s_textshape(char*name, char*fontname, float size, char*_text)
877 U8*text = (U8*)_text;
881 font = dictionary_lookup(&fonts, fontname);
883 syntaxerror("font \"%s\" not known!", fontname);
885 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
886 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
887 s_box(name, 0, 0, black, 20, 0);
890 g = font->ascii2glyph[text[0]];
892 outline = malloc(sizeof(outline_t));
893 memset(outline, 0, sizeof(outline_t));
894 outline->shape = font->glyph[g].shape;
895 outline->bbox = font->layout->bounds[g];
899 swf_Shape11DrawerInit(&draw, 0);
900 swf_DrawText(&draw, font, (int)(size*100), _text);
902 outline->shape = swf_ShapeDrawerToShape(&draw);
903 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
907 if(dictionary_lookup(&outlines, name))
908 syntaxerror("outline %s defined twice", name);
909 dictionary_put2(&outlines, name, outline);
912 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
917 font = dictionary_lookup(&fonts, fontname);
919 syntaxerror("font \"%s\" not known!", fontname);
921 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
923 if(!font->numchars) {
924 s_box(name, 0, 0, black, 20, 0);
927 r = swf_SetDefineText(tag, font, &color, text, size);
929 s_addcharacter(name, id, tag, r);
933 void s_quicktime(char*name, char*url)
938 memset(&r, 0, sizeof(r));
940 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
942 swf_SetString(tag, url);
944 s_addcharacter(name, id, tag, r);
948 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags)
951 EditTextLayout layout;
954 font = dictionary_lookup(&fonts, fontname);
956 syntaxerror("font \"%s\" not known!", fontname);
957 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
960 layout.leftmargin = 0;
961 layout.rightmargin = 0;
968 swf_SetEditText(tag, flags|ET_USEOUTLINES, r, text, color, maxlength, font->id, size, &layout, variable);
970 s_addcharacter(name, id, tag, r);
974 /* type: either "jpeg" or "png"
976 void s_image(char*name, char*type, char*filename, int quality)
978 /* an image is actually two folded: 1st bitmap, 2nd character.
979 Both of them can be used separately */
981 /* step 1: the bitmap */
986 warning("image type \"png\" not supported yet!");
987 s_box(name, 0, 0, black, 20, 0);
992 warning("no jpeg support compiled in");
993 s_box(name, 0, 0, black, 20, 0);
996 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
997 swf_SetU16(tag, imageID);
999 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1000 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1003 swf_GetJPEGSize(filename, &width, &height);
1010 s_addimage(name, id, tag, r);
1015 /* step 2: the character */
1016 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1017 swf_SetU16(tag, id);
1018 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1020 s_addcharacter(name, id, tag, r);
1024 void dumpSWF(SWF*swf)
1026 TAG* tag = swf->firstTag;
1027 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1029 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1032 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1035 void s_font(char*name, char*filename)
1038 font = swf_LoadFont(filename);
1041 warning("Couldn't open font file \"%s\"", filename);
1042 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1043 memset(font, 0, sizeof(SWFFONT));
1044 dictionary_put2(&fonts, name, font);
1050 /* fix the layout. Only needed for old fonts */
1052 for(t=0;t<font->numchars;t++) {
1053 font->glyph[t].advance = 0;
1056 swf_FontCreateLayout(font);
1058 /* just in case this thing is used in .edittext later on */
1059 swf_FontPrepareForEditText(font);
1062 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1063 swf_FontSetDefine2(tag, font);
1066 if(dictionary_lookup(&fonts, name))
1067 syntaxerror("font %s defined twice", name);
1068 dictionary_put2(&fonts, name, font);
1073 typedef struct _sound_t
1079 void s_sound(char*name, char*filename)
1081 struct WAV wav, wav2;
1086 if(!readWAV(filename, &wav)) {
1087 warning("Couldn't read wav file \"%s\"", filename);
1091 convertWAV2mono(&wav, &wav2, 44100);
1092 samples = (U16*)wav2.data;
1093 numsamples = wav2.size/2;
1097 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1098 swf_SetU16(tag, id); //id
1099 swf_SetSoundDefine(tag, samples, numsamples);
1101 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1105 if(dictionary_lookup(&sounds, name))
1106 syntaxerror("sound %s defined twice", name);
1107 dictionary_put2(&sounds, name, sound);
1115 static char* gradient_getToken(const char**p)
1119 while(**p && strchr(" \t\n\r", **p)) {
1123 while(**p && !strchr(" \t\n\r", **p)) {
1126 result = malloc((*p)-start+1);
1127 memcpy(result,start,(*p)-start+1);
1128 result[(*p)-start] = 0;
1132 float parsePercent(char*str);
1133 RGBA parseColor(char*str);
1135 GRADIENT parseGradient(const char*str)
1138 const char* p = str;
1139 memset(&gradient, 0, sizeof(GRADIENT));
1141 char*posstr,*colorstr;
1144 posstr = gradient_getToken(&p);
1147 pos = parsePercent(posstr);
1148 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1149 colorstr = gradient_getToken(&p);
1150 color = parseColor(colorstr);
1151 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1152 warning("gradient record too big- max size is 8, rest ignored");
1155 gradient.ratios[gradient.num] = (int)(pos*255.0);
1156 gradient.rgba[gradient.num] = color;
1164 void s_gradient(char*name, const char*text, int radial, int rotate)
1166 gradient_t* gradient;
1167 gradient = malloc(sizeof(gradient_t));
1168 memset(gradient, 0, sizeof(gradient_t));
1169 gradient->gradient = parseGradient(text);
1170 gradient->radial = radial;
1171 gradient->rotate = rotate;
1173 if(dictionary_lookup(&gradients, name))
1174 syntaxerror("gradient %s defined twice", name);
1175 dictionary_put2(&gradients, name, gradient);
1178 void s_action(const char*text)
1181 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1183 syntaxerror("Couldn't compile ActionScript");
1186 tag = swf_InsertTag(tag, ST_DOACTION);
1188 swf_ActionSet(tag, a);
1193 int s_swf3action(char*name, char*action)
1196 instance_t* object = dictionary_lookup(&instances, name);
1200 a = action_SetTarget(0, name);
1201 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1202 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1203 else if(!strcmp(action, "stop")) a = action_Stop(a);
1204 else if(!strcmp(action, "play")) a = action_Play(a);
1205 a = action_SetTarget(a, "");
1208 tag = swf_InsertTag(tag, ST_DOACTION);
1209 swf_ActionSet(tag, a);
1214 void s_outline(char*name, char*format, char*source)
1223 swf_Shape11DrawerInit(&draw, 0);
1224 draw_string(&draw, source);
1226 shape = swf_ShapeDrawerToShape(&draw);
1227 //shape2 = swf_ShapeToShape2(shape);
1228 //bounds = swf_GetShapeBoundingBox(shape2);
1229 //swf_Shape2Free(shape2);
1230 bounds = swf_ShapeDrawerGetBBox(&draw);
1231 draw.dealloc(&draw);
1233 outline = (outline_t*)malloc(sizeof(outline_t));
1234 memset(outline, 0, sizeof(outline_t));
1235 outline->shape = shape;
1236 outline->bbox = bounds;
1238 if(dictionary_lookup(&outlines, name))
1239 syntaxerror("outline %s defined twice", name);
1240 dictionary_put2(&outlines, name, outline);
1243 int s_playsound(char*name, int loops, int nomultiple, int stop)
1245 sound_t* sound = dictionary_lookup(&sounds, name);
1250 tag = swf_InsertTag(tag, ST_STARTSOUND);
1251 swf_SetU16(tag, sound->id); //id
1252 memset(&info, 0, sizeof(info));
1255 info.nomultiple = nomultiple;
1256 swf_SetSoundInfo(tag, &info);
1260 void s_includeswf(char*name, char*filename)
1268 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1269 f = open(filename,O_RDONLY|O_BINARY);
1271 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1272 s_box(name, 0, 0, black, 20, 0);
1275 if (swf_ReadSWF(f,&swf)<0) {
1276 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1277 s_box(name, 0, 0, black, 20, 0);
1282 /* FIXME: The following sets the bounding Box for the character.
1283 It is wrong for two reasons:
1284 a) It may be too small (in case objects in the movie clip at the borders)
1285 b) it may be too big (because the poor movie never got autocropped)
1289 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1290 swf_SetU16(tag, id);
1293 swf_Relocate(&swf, idmap);
1295 ftag = swf.firstTag;
1299 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1300 if(cutout[t] == ftag->id) {
1304 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1306 if(ftag->id == ST_END)
1310 /* We simply dump all tags right after the sprite
1311 header, relying on the fact that swf_OptimizeTagOrder() will
1312 sort things out for us later.
1313 We also rely on the fact that the imported SWF is well-formed.
1315 tag = swf_InsertTag(tag, ftag->id);
1316 swf_SetBlock(tag, ftag->data, ftag->len);
1320 syntaxerror("Included file %s contains errors", filename);
1321 tag = swf_InsertTag(tag, ST_END);
1325 s_addcharacter(name, id, tag, r);
1328 SRECT s_getCharBBox(char*name)
1330 character_t* c = dictionary_lookup(&characters, name);
1331 if(!c) syntaxerror("character '%s' unknown(2)", name);
1334 SRECT s_getInstanceBBox(char*name)
1336 instance_t * i = dictionary_lookup(&instances, name);
1338 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1340 if(!c) syntaxerror("internal error(5)");
1343 parameters_t s_getParameters(char*name)
1345 instance_t * i = dictionary_lookup(&instances, name);
1346 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1347 return i->parameters;
1349 void s_startclip(char*instance, char*character, parameters_t p)
1351 character_t* c = dictionary_lookup(&characters, character);
1355 syntaxerror("character %s not known", character);
1357 i = s_addinstance(instance, c, currentdepth);
1359 m = s_instancepos(i->character->size, &p);
1361 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1362 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1363 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1365 i->lastFrame= currentframe;
1367 stack[stackpos].tag = tag;
1368 stack[stackpos].type = 2;
1377 swf_SetTagPos(stack[stackpos].tag, 0);
1378 swf_GetPlaceObject(stack[stackpos].tag, &p);
1379 p.clipdepth = currentdepth;
1381 swf_ClearTag(stack[stackpos].tag);
1382 swf_SetPlaceObject(stack[stackpos].tag, &p);
1386 void s_put(char*instance, char*character, parameters_t p)
1388 character_t* c = dictionary_lookup(&characters, character);
1392 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1395 i = s_addinstance(instance, c, currentdepth);
1397 m = s_instancepos(i->character->size, &p);
1399 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1400 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1402 i->lastFrame = currentframe;
1406 void s_jump(char*instance, parameters_t p)
1408 instance_t* i = dictionary_lookup(&instances, instance);
1411 syntaxerror("instance %s not known", instance);
1415 m = s_instancepos(i->character->size, &p);
1417 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1418 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1420 i->lastFrame = currentframe;
1423 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1427 if(num==0 || num==1)
1429 ratio = (float)pos/(float)num;
1431 p.x = (p2->x-p1->x)*ratio + p1->x;
1432 p.y = (p2->y-p1->y)*ratio + p1->y;
1433 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1434 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1435 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1436 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1438 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1439 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1440 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1441 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1443 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1444 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1445 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1446 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1448 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1449 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1450 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1451 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1455 void s_change(char*instance, parameters_t p2)
1457 instance_t* i = dictionary_lookup(&instances, instance);
1461 int frame, allframes;
1463 syntaxerror("instance %s not known", instance);
1467 allframes = currentframe - i->lastFrame - 1;
1469 warning(".change ignored. can only .put/.change an object once per frame.");
1473 m = s_instancepos(i->character->size, &p2);
1474 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1475 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1478 /* o.k., we got the start and end point set. Now iterate though all the
1479 tags in between, inserting object changes after each new frame */
1482 if(!t) syntaxerror("internal error(6)");
1484 while(frame < allframes) {
1485 if(t->id == ST_SHOWFRAME) {
1490 p = s_interpolate(&p1, &p2, frame, allframes);
1491 m = s_instancepos(i->character->size, &p); //needed?
1492 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1493 i->lastFrame = currentframe;
1494 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1496 if(frame == allframes)
1501 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1505 void s_delinstance(char*instance)
1507 instance_t* i = dictionary_lookup(&instances, instance);
1509 syntaxerror("instance %s not known", instance);
1511 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1512 swf_SetU16(tag, i->depth);
1513 dictionary_del(&instances, instance);
1516 void s_qchange(char*instance, parameters_t p)
1523 syntaxerror(".end unexpected");
1524 if(stack[stackpos-1].type == 0)
1526 else if(stack[stackpos-1].type == 1)
1528 else if(stack[stackpos-1].type == 2)
1530 else if(stack[stackpos-1].type == 3)
1532 else syntaxerror("internal error 1");
1535 // ------------------------------------------------------------------------
1537 typedef int command_func_t(map_t*args);
1539 SRECT parseBox(char*str)
1542 float xmin, xmax, ymin, ymax;
1543 char*x = strchr(str, 'x');
1545 if(!strcmp(str, "autocrop")) {
1546 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1550 d1 = strchr(x+1, ':');
1552 d2 = strchr(d1+1, ':');
1554 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1558 else if(d1 && !d2) {
1559 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1565 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1570 r.xmin = (SCOORD)(xmin*20);
1571 r.ymin = (SCOORD)(ymin*20);
1572 r.xmax = (SCOORD)(xmax*20);
1573 r.ymax = (SCOORD)(ymax*20);
1576 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1579 float parseFloat(char*str)
1583 int parseInt(char*str)
1588 if(str[0]=='+' || str[0]=='-')
1592 if(str[t]<'0' || str[t]>'9')
1593 syntaxerror("Not an Integer: \"%s\"", str);
1596 int parseTwip(char*str)
1600 if(str[0]=='+' || str[0]=='-') {
1605 dot = strchr(str, '.');
1609 return sign*parseInt(str)*20;
1611 int l=strlen(++dot);
1613 for(s=str;s<dot-1;s++)
1614 if(*s<'0' || *s>'9')
1615 syntaxerror("Not a coordinate: \"%s\"", str);
1617 if(*s<'0' || *s>'9')
1618 syntaxerror("Not a coordinate: \"%s\"", str);
1620 if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) {
1621 warning("precision loss: %s converted to twip", str);
1626 return sign*atoi(str)*20;
1628 return sign*atoi(str)*20+atoi(dot)*2;
1630 return sign*atoi(str)*20+atoi(dot)/5;
1635 int isPoint(char*str)
1637 if(strchr(str, '('))
1643 SPOINT parsePoint(char*str)
1647 int l = strlen(str);
1648 char*comma = strchr(str, ',');
1649 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1650 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1651 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1652 p.x = parseTwip(tmp);
1653 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1654 p.y = parseTwip(tmp);
1658 int parseColor2(char*str, RGBA*color)
1660 int l = strlen(str);
1664 struct {unsigned char r,g,b;char*name;} colors[] =
1665 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1666 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1667 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1668 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1669 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1670 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1671 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1672 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1673 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1674 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1675 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1676 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1680 if(str[0]=='#' && (l==7 || l==9)) {
1681 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1683 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1685 color->r = r; color->g = g; color->b = b; color->a = a;
1688 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1689 if(!strcmp(str, colors[t].name)) {
1694 color->r = r; color->g = g; color->b = b; color->a = a;
1700 RGBA parseColor(char*str)
1703 if(!parseColor2(str, &c))
1704 syntaxerror("Expression '%s' is not a color", str);
1708 typedef struct _muladd {
1713 MULADD parseMulAdd(char*str)
1716 char* str2 = (char*)malloc(strlen(str)+5);
1723 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1724 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1725 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1726 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1727 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1728 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1729 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1730 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1731 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1732 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1734 syntaxerror("'%s' is not a valid color transform expression", str);
1736 m.add = (int)(add*256);
1737 m.mul = (int)(mul*256);
1742 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1744 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1745 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1747 if(a<-32768) a=-32768;
1748 if(a>32767) a=32767;
1749 if(m<-32768) m=-32768;
1750 if(m>32767) m=32767;
1756 float parsePercent(char*str)
1758 int l = strlen(str);
1762 return atoi(str)/100.0;
1764 syntaxerror("Expression '%s' is not a percentage", str);
1767 int isPercent(char*str)
1769 return str[strlen(str)-1]=='%';
1771 int parseNewSize(char*str, int size)
1774 return parsePercent(str)*size;
1776 return (int)(atof(str)*20);
1779 int isColor(char*str)
1782 return parseColor2(str, &c);
1785 static char* lu(map_t* args, char*name)
1787 char* value = map_lookup(args, name);
1789 map_dump(args, stdout, "");
1790 syntaxerror("internal error 2: value %s should be set", name);
1795 static int c_flash(map_t*args)
1797 char* name = lu(args, "name");
1798 char* compressstr = lu(args, "compress");
1799 SRECT bbox = parseBox(lu(args, "bbox"));
1800 int version = parseInt(lu(args, "version"));
1801 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1803 RGBA color = parseColor(lu(args, "background"));
1804 if(!strcmp(name, "!default!") || override_outputname)
1807 if(!strcmp(compressstr, "default"))
1808 compress = version==6;
1809 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1811 else if(!strcmp(compressstr, "no"))
1813 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1815 s_swf(name, bbox, version, fps, compress, color);
1818 int isRelative(char*str)
1820 return !strncmp(str, "<plus>", 6) ||
1821 !strncmp(str, "<minus>", 7);
1823 char* getOffset(char*str)
1825 if(!strncmp(str, "<plus>", 6))
1827 if(!strncmp(str, "<minus>", 7))
1829 syntaxerror("internal error (347)");
1832 int getSign(char*str)
1834 if(!strncmp(str, "<plus>", 6))
1836 if(!strncmp(str, "<minus>", 7))
1838 syntaxerror("internal error (348)");
1841 static dictionary_t points;
1842 static mem_t mpoints;
1843 int points_initialized = 0;
1845 SPOINT getPoint(SRECT r, char*name)
1848 if(!strcmp(name, "center")) {
1850 p.x = (r.xmin + r.xmax)/2;
1851 p.y = (r.ymin + r.ymax)/2;
1855 if(points_initialized)
1856 l = (int)dictionary_lookup(&points, name);
1858 syntaxerror("Invalid point: \"%s\".", name);
1861 return *(SPOINT*)&mpoints.buffer[l];
1863 static int c_gradient(map_t*args)
1865 char*name = lu(args, "name");
1866 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1867 int rotate = parseInt(lu(args, "rotate"));
1871 syntaxerror("colon (:) expected");
1873 s_gradient(name, text, radial,rotate);
1876 static int c_point(map_t*args)
1878 char*name = lu(args, "name");
1882 if(!points_initialized) {
1883 dictionary_init(&points);
1885 points_initialized = 1;
1887 p.x = parseTwip(lu(args, "x"));
1888 p.y = parseTwip(lu(args, "y"));
1889 pos = mem_put(&mpoints, &p, sizeof(p));
1890 string_set(&s1, name);
1892 dictionary_put(&points, s1, (void*)pos);
1895 static int c_play(map_t*args)
1897 char*name = lu(args, "name");
1898 char*loop = lu(args, "loop");
1899 char*nomultiple = lu(args, "nomultiple");
1901 if(!strcmp(nomultiple, "nomultiple"))
1904 nm = parseInt(nomultiple);
1906 if(s_playsound(name, parseInt(loop), nm, 0)) {
1908 } else if(s_swf3action(name, "play")) {
1914 static int c_stop(map_t*args)
1916 char*name = lu(args, "name");
1918 if(s_playsound(name, 0,0,1)) {
1920 } else if(s_swf3action(name, "stop")) {
1923 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
1927 static int c_nextframe(map_t*args)
1929 char*name = lu(args, "name");
1931 if(s_swf3action(name, "nextframe")) {
1934 syntaxerror("I don't know anything about movie \"%s\"", name);
1938 static int c_previousframe(map_t*args)
1940 char*name = lu(args, "name");
1942 if(s_swf3action(name, "previousframe")) {
1945 syntaxerror("I don't know anything about movie \"%s\"", name);
1949 static int c_placement(map_t*args, int type)
1951 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1954 char* luminancestr = lu(args, "luminance");
1955 char* scalestr = lu(args, "scale");
1956 char* scalexstr = lu(args, "scalex");
1957 char* scaleystr = lu(args, "scaley");
1958 char* rotatestr = lu(args, "rotate");
1959 char* shearstr = lu(args, "shear");
1960 char* xstr="", *pivotstr="";
1961 char* ystr="", *anglestr="";
1962 char*above = lu(args, "above"); /*FIXME*/
1963 char*below = lu(args, "below");
1964 char* rstr = lu(args, "red");
1965 char* gstr = lu(args, "green");
1966 char* bstr = lu(args, "blue");
1967 char* astr = lu(args, "alpha");
1968 char* pinstr = lu(args, "pin");
1969 char* as = map_lookup(args, "as");
1977 if(type==9) { // (?) .rotate or .arcchange
1978 pivotstr = lu(args, "pivot");
1979 anglestr = lu(args, "angle");
1981 xstr = lu(args, "x");
1982 ystr = lu(args, "y");
1985 luminance = parseMulAdd(luminancestr);
1988 luminance.mul = 256;
1992 if(scalexstr[0]||scaleystr[0])
1993 syntaxerror("scalex/scaley and scale cannot both be set");
1994 scalexstr = scaleystr = scalestr;
1997 if(type == 0 || type == 4) {
1999 character = lu(args, "character");
2000 parameters_clear(&p);
2001 } else if (type == 5) {
2002 character = lu(args, "name");
2003 parameters_clear(&p);
2006 p = s_getParameters(instance);
2011 if(isRelative(xstr)) {
2012 if(type == 0 || type == 4)
2013 syntaxerror("relative x values not allowed for initial put or startclip");
2014 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2016 p.x = parseTwip(xstr);
2020 if(isRelative(ystr)) {
2021 if(type == 0 || type == 4)
2022 syntaxerror("relative y values not allowed for initial put or startclip");
2023 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2025 p.y = parseTwip(ystr);
2029 /* scale, scalex, scaley */
2031 oldbbox = s_getCharBBox(character);
2033 oldbbox = s_getInstanceBBox(instance);
2035 oldwidth = oldbbox.xmax - oldbbox.xmin;
2036 oldheight = oldbbox.ymax - oldbbox.ymin;
2038 if(oldwidth==0) p.scalex = 1.0;
2041 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2045 if(oldheight==0) p.scaley = 1.0;
2048 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2054 if(isRelative(rotatestr)) {
2055 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2057 p.rotate = parseFloat(rotatestr);
2063 if(isRelative(shearstr)) {
2064 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2066 p.shear = parseFloat(shearstr);
2071 if(isPoint(pivotstr))
2072 p.pivot = parsePoint(pivotstr);
2074 p.pivot = getPoint(oldbbox, pivotstr);
2078 p.pin = parsePoint(pinstr);
2080 p.pin = getPoint(oldbbox, pinstr);
2083 /* color transform */
2085 if(rstr[0] || luminancestr[0]) {
2088 r = parseMulAdd(rstr);
2090 r.add = p.cxform.r0;
2091 r.mul = p.cxform.r1;
2093 r = mergeMulAdd(r, luminance);
2094 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2096 if(gstr[0] || luminancestr[0]) {
2099 g = parseMulAdd(gstr);
2101 g.add = p.cxform.g0;
2102 g.mul = p.cxform.g1;
2104 g = mergeMulAdd(g, luminance);
2105 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2107 if(bstr[0] || luminancestr[0]) {
2110 b = parseMulAdd(bstr);
2112 b.add = p.cxform.b0;
2113 b.mul = p.cxform.b1;
2115 b = mergeMulAdd(b, luminance);
2116 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2119 MULADD a = parseMulAdd(astr);
2120 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2124 s_put(instance, character, p);
2126 s_change(instance, p);
2128 s_qchange(instance, p);
2130 s_jump(instance, p);
2132 s_startclip(instance, character, p);
2133 else if(type == 5) {
2135 s_buttonput(character, as, p);
2137 s_buttonput(character, "shape", p);
2142 static int c_put(map_t*args)
2144 c_placement(args, 0);
2147 static int c_change(map_t*args)
2149 c_placement(args, 1);
2152 static int c_qchange(map_t*args)
2154 c_placement(args, 2);
2157 static int c_arcchange(map_t*args)
2159 c_placement(args, 2);
2162 static int c_jump(map_t*args)
2164 c_placement(args, 3);
2167 static int c_startclip(map_t*args)
2169 c_placement(args, 4);
2172 static int c_show(map_t*args)
2174 c_placement(args, 5);
2177 static int c_del(map_t*args)
2179 char*instance = lu(args, "name");
2180 s_delinstance(instance);
2183 static int c_end(map_t*args)
2188 static int c_sprite(map_t*args)
2190 char* name = lu(args, "name");
2194 static int c_frame(map_t*args)
2196 char*framestr = lu(args, "n");
2197 char*cutstr = lu(args, "cut");
2198 char*name = lu(args, "name");
2201 if(strcmp(cutstr, "no"))
2203 if(isRelative(framestr)) {
2204 frame = s_getframe();
2205 if(getSign(framestr)<0)
2206 syntaxerror("relative frame expressions must be positive");
2207 frame += parseInt(getOffset(framestr));
2210 frame = parseInt(framestr);
2211 if(s_getframe() >= frame
2212 && !(frame==0 && s_getframe()==frame)) // equality is o.k. for frame 0
2213 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2215 s_frame(frame, cut, name);
2218 static int c_primitive(map_t*args)
2220 char*name = lu(args, "name");
2221 char*command = lu(args, "commandname");
2222 int width=0, height=0, r=0;
2223 int linewidth = parseTwip(lu(args, "line"));
2224 char*colorstr = lu(args, "color");
2225 RGBA color = parseColor(colorstr);
2226 char*fillstr = lu(args, "fill");
2233 if(!strcmp(command, "circle"))
2235 else if(!strcmp(command, "filled"))
2239 width = parseTwip(lu(args, "width"));
2240 height = parseTwip(lu(args, "height"));
2241 } else if (type==1) {
2242 r = parseTwip(lu(args, "r"));
2243 } else if (type==2) {
2244 outline = lu(args, "outline");
2247 if(!strcmp(fillstr, "fill"))
2249 if(!strcmp(fillstr, "none"))
2251 if(width<0 || height<0 || linewidth<0 || r<0)
2252 syntaxerror("values width, height, line, r must be positive");
2254 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2255 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2256 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2260 static int c_textshape(map_t*args)
2262 char*name = lu(args, "name");
2263 char*text = lu(args, "text");
2264 char*font = lu(args, "font");
2265 float size = parsePercent(lu(args, "size"));
2267 s_textshape(name, font, size, text);
2271 static int c_swf(map_t*args)
2273 char*name = lu(args, "name");
2274 char*filename = lu(args, "filename");
2275 char*command = lu(args, "commandname");
2276 if(!strcmp(command, "shape"))
2277 warning("Please use .swf instead of .shape");
2278 s_includeswf(name, filename);
2282 static int c_font(map_t*args)
2284 char*name = lu(args, "name");
2285 char*filename = lu(args, "filename");
2286 s_font(name, filename);
2290 static int c_sound(map_t*args)
2292 char*name = lu(args, "name");
2293 char*filename = lu(args, "filename");
2294 s_sound(name, filename);
2298 static int c_text(map_t*args)
2300 char*name = lu(args, "name");
2301 char*text = lu(args, "text");
2302 char*font = lu(args, "font");
2303 float size = parsePercent(lu(args, "size"));
2304 RGBA color = parseColor(lu(args, "color"));
2305 s_text(name, font, text, (int)(size*100), color);
2309 static int c_soundtrack(map_t*args)
2314 static int c_quicktime(map_t*args)
2316 char*name = lu(args, "name");
2317 char*url = lu(args, "url");
2318 s_quicktime(name, url);
2322 static int c_image(map_t*args)
2324 char*command = lu(args, "commandname");
2325 char*name = lu(args, "name");
2326 char*filename = lu(args, "filename");
2327 if(!strcmp(command,"jpeg")) {
2328 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2329 s_image(name, "jpeg", filename, quality);
2331 s_image(name, "png", filename, 0);
2336 static int c_outline(map_t*args)
2338 char*name = lu(args, "name");
2339 char*format = lu(args, "format");
2343 syntaxerror("colon (:) expected");
2345 s_outline(name, format, text);
2349 int fakechar(map_t*args)
2351 char*name = lu(args, "name");
2352 s_box(name, 0, 0, black, 20, 0);
2356 static int c_egon(map_t*args) {return fakechar(args);}
2357 static int c_button(map_t*args) {
2358 char*name = lu(args, "name");
2362 static int current_button_flags = 0;
2363 static int c_on_press(map_t*args)
2365 char*position = lu(args, "position");
2367 if(!strcmp(position, "inside")) {
2368 current_button_flags |= BC_OVERUP_OVERDOWN;
2369 } else if(!strcmp(position, "outside")) {
2370 //current_button_flags |= BC_IDLE_OUTDOWN;
2371 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2372 } else if(!strcmp(position, "anywhere")) {
2373 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2376 if(type == RAWDATA) {
2378 s_buttonaction(current_button_flags, action);
2379 current_button_flags = 0;
2385 static int c_on_release(map_t*args)
2387 char*position = lu(args, "position");
2389 if(!strcmp(position, "inside")) {
2390 current_button_flags |= BC_OVERDOWN_OVERUP;
2391 } else if(!strcmp(position, "outside")) {
2392 current_button_flags |= BC_OUTDOWN_IDLE;
2393 } else if(!strcmp(position, "anywhere")) {
2394 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2397 if(type == RAWDATA) {
2399 s_buttonaction(current_button_flags, action);
2400 current_button_flags = 0;
2406 static int c_on_move_in(map_t*args)
2408 char*position = lu(args, "state");
2410 if(!strcmp(position, "pressed")) {
2411 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2412 } else if(!strcmp(position, "not_pressed")) {
2413 current_button_flags |= BC_IDLE_OVERUP;
2414 } else if(!strcmp(position, "any")) {
2415 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2418 if(type == RAWDATA) {
2420 s_buttonaction(current_button_flags, action);
2421 current_button_flags = 0;
2427 static int c_on_move_out(map_t*args)
2429 char*position = lu(args, "state");
2431 if(!strcmp(position, "pressed")) {
2432 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2433 } else if(!strcmp(position, "not_pressed")) {
2434 current_button_flags |= BC_OVERUP_IDLE;
2435 } else if(!strcmp(position, "any")) {
2436 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2439 if(type == RAWDATA) {
2441 s_buttonaction(current_button_flags, action);
2442 current_button_flags = 0;
2448 static int c_on_key(map_t*args)
2450 char*key = lu(args, "key");
2452 if(strlen(key)==1) {
2455 current_button_flags |= 0x4000 + (key[0]*0x200);
2457 syntaxerror("invalid character: %c"+key[0]);
2462 <ctrl-x> = 0x200*(x-'a')
2466 syntaxerror("invalid key: %s",key);
2469 if(type == RAWDATA) {
2471 s_buttonaction(current_button_flags, action);
2472 current_button_flags = 0;
2479 static int c_edittext(map_t*args)
2481 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
2482 char*name = lu(args, "name");
2483 char*font = lu(args, "font");
2484 int size = (int)(1024*parsePercent(lu(args, "size")));
2485 int width = parseTwip(lu(args, "width"));
2486 int height = parseTwip(lu(args, "height"));
2487 char*text = lu(args, "text");
2488 RGBA color = parseColor(lu(args, "color"));
2489 int maxlength = parseInt(lu(args, "maxlength"));
2490 char*variable = lu(args, "variable");
2491 char*passwordstr = lu(args, "password");
2492 char*wordwrapstr = lu(args, "wordwrap");
2493 char*multilinestr = lu(args, "multiline");
2494 char*htmlstr = lu(args, "html");
2495 char*noselectstr = lu(args, "noselect");
2496 char*readonlystr = lu(args, "readonly");
2497 char*borderstr = lu(args, "border");
2500 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2501 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2502 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2503 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2504 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2505 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2506 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2508 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags);
2512 static int c_morphshape(map_t*args) {return fakechar(args);}
2513 static int c_movie(map_t*args) {return fakechar(args);}
2515 static int c_texture(map_t*args) {return 0;}
2517 static int c_action(map_t*args)
2520 if(type != RAWDATA) {
2521 syntaxerror("colon (:) expected");
2531 command_func_t* func;
2534 {{"flash", c_flash, "bbox=autocrop background=black version=5 fps=50 name=!default! @compress=default"},
2535 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2536 // "import" type stuff
2537 {"swf", c_swf, "name filename"},
2538 {"shape", c_swf, "name filename"},
2539 {"jpeg", c_image, "name filename quality=80%"},
2540 {"png", c_image, "name filename"},
2541 {"movie", c_movie, "name filename"},
2542 {"sound", c_sound, "name filename"},
2543 {"font", c_font, "name filename"},
2544 {"soundtrack", c_soundtrack, "filename"},
2545 {"quicktime", c_quicktime, "url"},
2547 // generators of primitives
2549 {"point", c_point, "name x=0 y=0"},
2550 {"gradient", c_gradient, "name @radial=0 rotate=0"},
2551 {"outline", c_outline, "name format=simple"},
2552 {"textshape", c_textshape, "name font size=100% text"},
2554 // character generators
2555 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2556 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2557 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2559 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2560 {"text", c_text, "name text font size=100% color=white"},
2561 {"edittext", c_edittext, "name font size=100% width height text="" color=white maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @border=0"},
2562 {"morphshape", c_morphshape, "name start end"},
2563 {"button", c_button, "name"},
2564 {"show", c_show, "name x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below= as="},
2565 {"on_press", c_on_press, "position=inside"},
2566 {"on_release", c_on_release, "position=anywhere"},
2567 {"on_move_in", c_on_move_in, "state=not_pressed"},
2568 {"on_move_out", c_on_move_out, "state=not_pressed"},
2569 {"on_key", c_on_key, "key=any"},
2572 {"play", c_play, "name loop=0 @nomultiple=0"},
2573 {"stop", c_stop, "name"},
2574 {"nextframe", c_nextframe, "name"},
2575 {"previousframe", c_previousframe, "name"},
2577 // object placement tags
2578 {"put", c_put, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2579 {"startclip", c_startclip, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2580 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2581 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2582 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2583 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2584 {"del", c_del, "name"},
2585 // virtual object placement
2586 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2588 // commands which start a block
2589 //startclip (see above)
2590 {"sprite", c_sprite, "name"},
2591 {"action", c_action, ""},
2597 static map_t parseArguments(char*command, char*pattern)
2613 string_set(&t1, "commandname");
2614 string_set(&t2, command);
2615 map_put(&result, t1, t2);
2617 if(!pattern || !*pattern)
2624 if(!strncmp("<i> ", x, 3)) {
2626 if(type == COMMAND || type == RAWDATA) {
2628 syntaxerror("character name expected");
2630 name[pos].str = "instance";
2632 value[pos].str = text;
2633 value[pos].len = strlen(text);
2637 if(type == ASSIGNMENT)
2640 name[pos].str = "character";
2642 value[pos].str = text;
2643 value[pos].len = strlen(text);
2651 isboolean[pos] = (x[0] =='@');
2664 name[pos].len = d-x;
2669 name[pos].len = e-x;
2670 value[pos].str = e+1;
2671 value[pos].len = d-e-1;
2679 /* for(t=0;t<len;t++) {
2680 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2681 isboolean[t]?"(boolean)":"");
2686 if(type == RAWDATA || type == COMMAND) {
2691 // first, search for boolean arguments
2692 for(pos=0;pos<len;pos++)
2694 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2696 if(type == ASSIGNMENT)
2698 value[pos].str = text;
2699 value[pos].len = strlen(text);
2700 /*printf("setting boolean parameter %s (to %s)\n",
2701 strdup_n(name[pos], namelen[pos]),
2702 strdup_n(value[pos], valuelen[pos]));*/
2707 // second, search for normal arguments
2709 for(pos=0;pos<len;pos++)
2711 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2712 (type != ASSIGNMENT && !set[pos])) {
2714 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2716 if(type == ASSIGNMENT)
2719 value[pos].str = text;
2720 value[pos].len = strlen(text);
2722 printf("setting parameter %s (to %s)\n",
2723 strdup_n(name[pos].str, name[pos].len),
2724 strdup_n(value[pos].str, value[pos].len));
2730 syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
2734 for(t=0;t<len;t++) {
2735 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2738 for(t=0;t<len;t++) {
2739 if(value[t].str && value[t].str[0] == '*') {
2740 //relative default- take value from some other parameter
2742 for(s=0;s<len;s++) {
2743 if(value[s].len == value[t].len-1 &&
2744 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2745 value[t].str = value[s].str;
2748 if(value[t].str == 0) {
2750 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2754 /* ok, now construct the dictionary from the parameters */
2758 map_put(&result, name[t], value[t]);
2762 static void parseArgumentsForCommand(char*command)
2767 msg("<verbose> parse Command: %s (line %d)", command, line);
2769 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2770 if(!strcmp(arguments[t].command, command)) {
2772 /* ugly hack- will be removed soon (once documentation and .sc generating
2773 utilities have been changed) */
2774 if(!strcmp(command, "swf") && !stackpos) {
2775 warning("Please use .flash instead of .swf- this will be mandatory soon");
2780 args = parseArguments(command, arguments[t].arguments);
2786 syntaxerror("command %s not known", command);
2788 // catch missing .flash directives at the beginning of a file
2789 if(strcmp(command, "flash") && !stackpos)
2791 syntaxerror("No movie defined- use .flash first");
2795 printf(".%s\n", command);fflush(stdout);
2796 map_dump(&args, stdout, "\t");fflush(stdout);
2799 (*arguments[nr].func)(&args);
2801 /*if(!strcmp(command, "button") ||
2802 !strcmp(command, "action")) {
2805 if(type == COMMAND) {
2806 if(!strcmp(text, "end"))
2820 int main (int argc,char ** argv)
2823 processargs(argc, argv);
2824 initLog(0,-1,0,0,-1,verbose);
2827 args_callback_usage(argv[0]);
2831 file = generateTokens(filename);
2833 printf("parser returned error.\n");
2839 while(!noMoreTokens()) {
2842 syntaxerror("command expected");
2843 parseArgumentsForCommand(text);