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);
646 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
647 swf->movieSize = currentrect; /* "autocrop" */
650 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
651 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
652 swf->movieSize.ymax += 20;
655 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
657 syntaxerror("couldn't create output file %s", filename);
660 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
662 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
666 dictionary_clear(&instances);
667 dictionary_clear(&characters);
668 dictionary_clear(&images);
669 dictionary_clear(&outlines);
670 dictionary_clear(&gradients);
671 dictionary_clear(&fonts);
672 dictionary_clear(&sounds);
682 if(stack[stackpos-1].type == 0)
683 syntaxerror("End of file encountered in .flash block");
684 if(stack[stackpos-1].type == 1)
685 syntaxerror("End of file encountered in .sprite block");
686 if(stack[stackpos-1].type == 2)
687 syntaxerror("End of file encountered in .clip block");
696 void s_frame(int nr, int cut, char*name)
701 for(t=currentframe;t<nr;t++) {
702 tag = swf_InsertTag(tag, ST_SHOWFRAME);
703 if(t==nr-1 && name && *name) {
704 tag = swf_InsertTag(tag, ST_FRAMELABEL);
705 swf_SetString(tag, name);
708 if(nr == 0 && currentframe == 0 && name) {
709 tag = swf_InsertTag(tag, ST_FRAMELABEL);
710 swf_SetString(tag, name);
715 syntaxerror("Can't cut, frame empty");
717 stack[stackpos].cut = tag;
723 int parseColor2(char*str, RGBA*color);
725 int addFillStyle(SHAPE*s, SRECT*r, char*texture)
730 if(texture[0] == '#') {
731 parseColor2(texture, &color);
732 return swf_ShapeAddSolidFillStyle(s, &color);
733 } else if((image = dictionary_lookup(&images, texture))) {
735 swf_GetMatrix(0, &m);
736 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
737 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
740 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
741 } /*else if ((texture = dictionary_lookup(&textures, texture))) {
742 } */ else if ((gradient = dictionary_lookup(&gradients, texture))) {
746 swf_GetMatrix(0, &rot);
747 ccos = cos(-gradient->rotate*2*3.14159265358979/360);
748 csin = sin(-gradient->rotate*2*3.14159265358979/360);
750 rot.r1 = -csin*65536;
753 r2 = swf_TurnRect(*r, &rot);
754 swf_GetMatrix(0, &m);
755 m.sx = (r2.xmax - r2.xmin)*2*ccos;
756 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
757 m.r0 = (r2.ymax - r2.ymin)*2*csin;
758 m.sy = (r2.ymax - r2.ymin)*2*ccos;
759 m.tx = r->xmin + (r->xmax - r->xmin)/2;
760 m.ty = r->ymin + (r->ymax - r->ymin)/2;
761 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
762 } else if (parseColor2(texture, &color)) {
763 return swf_ShapeAddSolidFillStyle(s, &color);
765 syntaxerror("not a color/fillstyle: %s", texture);
770 RGBA black={r:0,g:0,b:0,a:0};
771 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
780 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
782 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
785 fs1 = addFillStyle(s, &r2, texture);
788 r.xmin = r2.xmin-linewidth-linewidth/2;
789 r.ymin = r2.ymin-linewidth-linewidth/2;
790 r.xmax = r2.xmax+linewidth+linewidth/2;
791 r.ymax = r2.ymax+linewidth+linewidth/2;
793 swf_SetShapeHeader(tag,s);
794 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
795 swf_ShapeSetLine(tag,s,width,0);
796 swf_ShapeSetLine(tag,s,0,height);
797 swf_ShapeSetLine(tag,s,-width,0);
798 swf_ShapeSetLine(tag,s,0,-height);
799 swf_ShapeSetEnd(tag);
802 s_addcharacter(name, id, tag, r);
806 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
812 outline = dictionary_lookup(&outlines, outlinename);
814 syntaxerror("outline %s not defined", outlinename);
818 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
820 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
822 fs1 = addFillStyle(s, &r2, texture);
824 syntaxerror("non filled outlines not yet supported- please supply a fill=<color/texture> argument");
826 rect.xmin = r2.xmin-linewidth-linewidth/2;
827 rect.ymin = r2.ymin-linewidth-linewidth/2;
828 rect.xmax = r2.xmax+linewidth+linewidth/2;
829 rect.ymax = r2.ymax+linewidth+linewidth/2;
831 swf_SetRect(tag,&rect);
832 swf_SetShapeStyles(tag, s);
833 swf_SetShapeBits(tag, outline->shape); //does not count bits!
834 swf_SetBlock(tag, outline->shape->data, (outline->shape->bitlen+7)/8);
837 s_addcharacter(name, id, tag, rect);
841 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
846 r2.xmin = r2.ymin = 0;
850 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
852 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
854 fs1 = addFillStyle(s, &r2, texture);
856 rect.xmin = r2.xmin-linewidth-linewidth/2;
857 rect.ymin = r2.ymin-linewidth-linewidth/2;
858 rect.xmax = r2.xmax+linewidth+linewidth/2;
859 rect.ymax = r2.ymax+linewidth+linewidth/2;
861 swf_SetRect(tag,&rect);
862 swf_SetShapeHeader(tag,s);
863 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
864 swf_ShapeSetCircle(tag, s, r,r,r,r);
865 swf_ShapeSetEnd(tag);
868 s_addcharacter(name, id, tag, rect);
872 void s_textshape(char*name, char*fontname, float size, char*_text)
875 U8*text = (U8*)_text;
879 font = dictionary_lookup(&fonts, fontname);
881 syntaxerror("font \"%s\" not known!", fontname);
883 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
884 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
885 s_box(name, 0, 0, black, 20, 0);
888 g = font->ascii2glyph[text[0]];
890 outline = malloc(sizeof(outline_t));
891 memset(outline, 0, sizeof(outline_t));
892 outline->shape = font->glyph[g].shape;
893 outline->bbox = font->layout->bounds[g];
897 swf_Shape11DrawerInit(&draw, 0);
898 swf_DrawText(&draw, font, (int)(size*100), _text);
900 outline->shape = swf_ShapeDrawerToShape(&draw);
901 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
905 if(dictionary_lookup(&outlines, name))
906 syntaxerror("outline %s defined twice", name);
907 dictionary_put2(&outlines, name, outline);
910 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
915 font = dictionary_lookup(&fonts, fontname);
917 syntaxerror("font \"%s\" not known!", fontname);
919 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
921 if(!font->numchars) {
922 s_box(name, 0, 0, black, 20, 0);
925 r = swf_SetDefineText(tag, font, &color, text, size);
927 s_addcharacter(name, id, tag, r);
931 void s_quicktime(char*name, char*url)
936 memset(&r, 0, sizeof(r));
938 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
940 swf_SetString(tag, url);
942 s_addcharacter(name, id, tag, r);
946 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags)
949 EditTextLayout layout;
952 font = dictionary_lookup(&fonts, fontname);
954 syntaxerror("font \"%s\" not known!", fontname);
955 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
958 layout.leftmargin = 0;
959 layout.rightmargin = 0;
966 swf_SetEditText(tag, flags|ET_USEOUTLINES, r, text, color, maxlength, font->id, size, &layout, variable);
968 s_addcharacter(name, id, tag, r);
972 /* type: either "jpeg" or "png"
974 void s_image(char*name, char*type, char*filename, int quality)
976 /* an image is actually two folded: 1st bitmap, 2nd character.
977 Both of them can be used separately */
979 /* step 1: the bitmap */
984 warning("image type \"png\" not supported yet!");
985 s_box(name, 0, 0, black, 20, 0);
990 warning("no jpeg support compiled in");
991 s_box(name, 0, 0, black, 20, 0);
994 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
995 swf_SetU16(tag, imageID);
997 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
998 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1001 swf_GetJPEGSize(filename, &width, &height);
1008 s_addimage(name, id, tag, r);
1013 /* step 2: the character */
1014 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1015 swf_SetU16(tag, id);
1016 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1018 s_addcharacter(name, id, tag, r);
1022 void dumpSWF(SWF*swf)
1024 TAG* tag = swf->firstTag;
1025 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1027 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1030 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1033 void s_font(char*name, char*filename)
1036 font = swf_LoadFont(filename);
1039 warning("Couldn't open font file \"%s\"", filename);
1040 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1041 memset(font, 0, sizeof(SWFFONT));
1042 dictionary_put2(&fonts, name, font);
1048 /* fix the layout. Only needed for old fonts */
1050 for(t=0;t<font->numchars;t++) {
1051 font->glyph[t].advance = 0;
1054 swf_FontCreateLayout(font);
1056 /* just in case this thing is used in .edittext later on */
1057 swf_FontPrepareForEditText(font);
1060 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1061 swf_FontSetDefine2(tag, font);
1064 if(dictionary_lookup(&fonts, name))
1065 syntaxerror("font %s defined twice", name);
1066 dictionary_put2(&fonts, name, font);
1071 typedef struct _sound_t
1077 void s_sound(char*name, char*filename)
1079 struct WAV wav, wav2;
1084 if(!readWAV(filename, &wav)) {
1085 warning("Couldn't read wav file \"%s\"", filename);
1089 convertWAV2mono(&wav, &wav2, 44100);
1090 samples = (U16*)wav2.data;
1091 numsamples = wav2.size/2;
1095 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1096 swf_SetU16(tag, id); //id
1097 swf_SetSoundDefine(tag, samples, numsamples);
1099 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1103 if(dictionary_lookup(&sounds, name))
1104 syntaxerror("sound %s defined twice", name);
1105 dictionary_put2(&sounds, name, sound);
1113 static char* gradient_getToken(const char**p)
1117 while(**p && strchr(" \t\n\r", **p)) {
1121 while(**p && !strchr(" \t\n\r", **p)) {
1124 result = malloc((*p)-start+1);
1125 memcpy(result,start,(*p)-start+1);
1126 result[(*p)-start] = 0;
1130 float parsePercent(char*str);
1131 RGBA parseColor(char*str);
1133 GRADIENT parseGradient(const char*str)
1136 const char* p = str;
1137 memset(&gradient, 0, sizeof(GRADIENT));
1139 char*posstr,*colorstr;
1142 posstr = gradient_getToken(&p);
1145 pos = parsePercent(posstr);
1146 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1147 colorstr = gradient_getToken(&p);
1148 color = parseColor(colorstr);
1149 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1150 warning("gradient record too big- max size is 8, rest ignored");
1153 gradient.ratios[gradient.num] = (int)(pos*255.0);
1154 gradient.rgba[gradient.num] = color;
1162 void s_gradient(char*name, const char*text, int radial, int rotate)
1164 gradient_t* gradient;
1165 gradient = malloc(sizeof(gradient_t));
1166 memset(gradient, 0, sizeof(gradient_t));
1167 gradient->gradient = parseGradient(text);
1168 gradient->radial = radial;
1169 gradient->rotate = rotate;
1171 if(dictionary_lookup(&gradients, name))
1172 syntaxerror("gradient %s defined twice", name);
1173 dictionary_put2(&gradients, name, gradient);
1176 void s_action(const char*text)
1179 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1181 syntaxerror("Couldn't compile ActionScript");
1184 tag = swf_InsertTag(tag, ST_DOACTION);
1186 swf_ActionSet(tag, a);
1191 int s_swf3action(char*name, char*action)
1194 instance_t* object = dictionary_lookup(&instances, name);
1198 a = action_SetTarget(0, name);
1199 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1200 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1201 else if(!strcmp(action, "stop")) a = action_Stop(a);
1202 else if(!strcmp(action, "play")) a = action_Play(a);
1203 a = action_SetTarget(a, "");
1206 tag = swf_InsertTag(tag, ST_DOACTION);
1207 swf_ActionSet(tag, a);
1212 void s_outline(char*name, char*format, char*source)
1221 swf_Shape11DrawerInit(&draw, 0);
1222 draw_string(&draw, source);
1224 shape = swf_ShapeDrawerToShape(&draw);
1225 //shape2 = swf_ShapeToShape2(shape);
1226 //bounds = swf_GetShapeBoundingBox(shape2);
1227 //swf_Shape2Free(shape2);
1228 bounds = swf_ShapeDrawerGetBBox(&draw);
1229 draw.dealloc(&draw);
1231 outline = (outline_t*)malloc(sizeof(outline_t));
1232 memset(outline, 0, sizeof(outline_t));
1233 outline->shape = shape;
1234 outline->bbox = bounds;
1236 if(dictionary_lookup(&outlines, name))
1237 syntaxerror("outline %s defined twice", name);
1238 dictionary_put2(&outlines, name, outline);
1241 int s_playsound(char*name, int loops, int nomultiple, int stop)
1243 sound_t* sound = dictionary_lookup(&sounds, name);
1248 tag = swf_InsertTag(tag, ST_STARTSOUND);
1249 swf_SetU16(tag, sound->id); //id
1250 memset(&info, 0, sizeof(info));
1253 info.nomultiple = nomultiple;
1254 swf_SetSoundInfo(tag, &info);
1258 void s_includeswf(char*name, char*filename)
1266 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1267 f = open(filename,O_RDONLY|O_BINARY);
1269 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1270 s_box(name, 0, 0, black, 20, 0);
1273 if (swf_ReadSWF(f,&swf)<0) {
1274 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1275 s_box(name, 0, 0, black, 20, 0);
1280 /* FIXME: The following sets the bounding Box for the character.
1281 It is wrong for two reasons:
1282 a) It may be too small (in case objects in the movie clip at the borders)
1283 b) it may be too big (because the poor movie never got autocropped)
1287 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1288 swf_SetU16(tag, id);
1291 swf_Relocate(&swf, idmap);
1293 ftag = swf.firstTag;
1297 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1298 if(cutout[t] == ftag->id) {
1302 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1304 if(ftag->id == ST_END)
1308 /* We simply dump all tags right after the sprite
1309 header, relying on the fact that swf_OptimizeTagOrder() will
1310 sort things out for us later.
1311 We also rely on the fact that the imported SWF is well-formed.
1313 tag = swf_InsertTag(tag, ftag->id);
1314 swf_SetBlock(tag, ftag->data, ftag->len);
1318 syntaxerror("Included file %s contains errors", filename);
1319 tag = swf_InsertTag(tag, ST_END);
1323 s_addcharacter(name, id, tag, r);
1326 SRECT s_getCharBBox(char*name)
1328 character_t* c = dictionary_lookup(&characters, name);
1329 if(!c) syntaxerror("character '%s' unknown(2)", name);
1332 SRECT s_getInstanceBBox(char*name)
1334 instance_t * i = dictionary_lookup(&instances, name);
1336 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1338 if(!c) syntaxerror("internal error(5)");
1341 parameters_t s_getParameters(char*name)
1343 instance_t * i = dictionary_lookup(&instances, name);
1344 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1345 return i->parameters;
1347 void s_startclip(char*instance, char*character, parameters_t p)
1349 character_t* c = dictionary_lookup(&characters, character);
1353 syntaxerror("character %s not known", character);
1355 i = s_addinstance(instance, c, currentdepth);
1357 m = s_instancepos(i->character->size, &p);
1359 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1360 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1361 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1363 i->lastFrame= currentframe;
1365 stack[stackpos].tag = tag;
1366 stack[stackpos].type = 2;
1375 swf_SetTagPos(stack[stackpos].tag, 0);
1376 swf_GetPlaceObject(stack[stackpos].tag, &p);
1377 p.clipdepth = currentdepth;
1379 swf_ClearTag(stack[stackpos].tag);
1380 swf_SetPlaceObject(stack[stackpos].tag, &p);
1384 void s_put(char*instance, char*character, parameters_t p)
1386 character_t* c = dictionary_lookup(&characters, character);
1390 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1393 i = s_addinstance(instance, c, currentdepth);
1395 m = s_instancepos(i->character->size, &p);
1397 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1398 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1400 i->lastFrame = currentframe;
1404 void s_jump(char*instance, parameters_t p)
1406 instance_t* i = dictionary_lookup(&instances, instance);
1409 syntaxerror("instance %s not known", instance);
1413 m = s_instancepos(i->character->size, &p);
1415 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1416 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1418 i->lastFrame = currentframe;
1421 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1425 if(num==0 || num==1)
1427 ratio = (float)pos/(float)num;
1429 p.x = (p2->x-p1->x)*ratio + p1->x;
1430 p.y = (p2->y-p1->y)*ratio + p1->y;
1431 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1432 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1433 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1434 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1436 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1437 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1438 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1439 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1441 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1442 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1443 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1444 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1446 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1447 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1448 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1449 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1453 void s_change(char*instance, parameters_t p2)
1455 instance_t* i = dictionary_lookup(&instances, instance);
1459 int frame, allframes;
1461 syntaxerror("instance %s not known", instance);
1465 allframes = currentframe - i->lastFrame - 1;
1467 warning(".change ignored. can only .put/.change an object once per frame.");
1471 m = s_instancepos(i->character->size, &p2);
1472 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1473 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1476 /* o.k., we got the start and end point set. Now iterate though all the
1477 tags in between, inserting object changes after each new frame */
1480 if(!t) syntaxerror("internal error(6)");
1482 while(frame < allframes) {
1483 if(t->id == ST_SHOWFRAME) {
1488 p = s_interpolate(&p1, &p2, frame, allframes);
1489 m = s_instancepos(i->character->size, &p); //needed?
1490 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1491 i->lastFrame = currentframe;
1492 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1494 if(frame == allframes)
1499 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1503 void s_delinstance(char*instance)
1505 instance_t* i = dictionary_lookup(&instances, instance);
1507 syntaxerror("instance %s not known", instance);
1509 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1510 swf_SetU16(tag, i->depth);
1511 dictionary_del(&instances, instance);
1514 void s_qchange(char*instance, parameters_t p)
1521 syntaxerror(".end unexpected");
1522 if(stack[stackpos-1].type == 0)
1524 else if(stack[stackpos-1].type == 1)
1526 else if(stack[stackpos-1].type == 2)
1528 else if(stack[stackpos-1].type == 3)
1530 else syntaxerror("internal error 1");
1533 // ------------------------------------------------------------------------
1535 typedef int command_func_t(map_t*args);
1537 SRECT parseBox(char*str)
1540 float xmin, xmax, ymin, ymax;
1541 char*x = strchr(str, 'x');
1543 if(!strcmp(str, "autocrop")) {
1544 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1548 d1 = strchr(x+1, ':');
1550 d2 = strchr(d1+1, ':');
1552 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1556 else if(d1 && !d2) {
1557 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1563 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1568 r.xmin = (SCOORD)(xmin*20);
1569 r.ymin = (SCOORD)(ymin*20);
1570 r.xmax = (SCOORD)(xmax*20);
1571 r.ymax = (SCOORD)(ymax*20);
1574 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1577 float parseFloat(char*str)
1581 int parseInt(char*str)
1586 if(str[0]=='+' || str[0]=='-')
1590 if(str[t]<'0' || str[t]>'9')
1591 syntaxerror("Not an Integer: \"%s\"", str);
1594 int parseTwip(char*str)
1598 if(str[0]=='+' || str[0]=='-') {
1603 dot = strchr(str, '.');
1607 return sign*parseInt(str)*20;
1609 int l=strlen(++dot);
1611 for(s=str;s<dot-1;s++)
1612 if(*s<'0' || *s>'9')
1613 syntaxerror("Not a coordinate: \"%s\"", str);
1615 if(*s<'0' || *s>'9')
1616 syntaxerror("Not a coordinate: \"%s\"", str);
1618 if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) {
1619 warning("precision loss: %s converted to twip", str);
1624 return sign*atoi(str)*20;
1626 return sign*atoi(str)*20+atoi(dot)*2;
1628 return sign*atoi(str)*20+atoi(dot)/5;
1633 int isPoint(char*str)
1635 if(strchr(str, '('))
1641 SPOINT parsePoint(char*str)
1645 int l = strlen(str);
1646 char*comma = strchr(str, ',');
1647 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1648 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1649 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1650 p.x = parseTwip(tmp);
1651 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1652 p.y = parseTwip(tmp);
1656 int parseColor2(char*str, RGBA*color)
1658 int l = strlen(str);
1662 struct {unsigned char r,g,b;char*name;} colors[] =
1663 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1664 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1665 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1666 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1667 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1668 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1669 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1670 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1671 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1672 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1673 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1674 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1678 if(str[0]=='#' && (l==7 || l==9)) {
1679 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1681 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1683 color->r = r; color->g = g; color->b = b; color->a = a;
1686 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1687 if(!strcmp(str, colors[t].name)) {
1692 color->r = r; color->g = g; color->b = b; color->a = a;
1698 RGBA parseColor(char*str)
1701 if(!parseColor2(str, &c))
1702 syntaxerror("Expression '%s' is not a color", str);
1706 typedef struct _muladd {
1711 MULADD parseMulAdd(char*str)
1714 char* str2 = (char*)malloc(strlen(str)+5);
1721 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1722 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1723 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1724 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1725 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1726 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1727 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1728 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1729 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1730 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1732 syntaxerror("'%s' is not a valid color transform expression", str);
1734 m.add = (int)(add*256);
1735 m.mul = (int)(mul*256);
1740 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1742 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1743 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1745 if(a<-32768) a=-32768;
1746 if(a>32767) a=32767;
1747 if(m<-32768) m=-32768;
1748 if(m>32767) m=32767;
1754 float parsePercent(char*str)
1756 int l = strlen(str);
1760 return atoi(str)/100.0;
1762 syntaxerror("Expression '%s' is not a percentage", str);
1765 int isPercent(char*str)
1767 return str[strlen(str)-1]=='%';
1769 int parseNewSize(char*str, int size)
1772 return parsePercent(str)*size;
1774 return (int)(atof(str)*20);
1777 int isColor(char*str)
1780 return parseColor2(str, &c);
1783 static char* lu(map_t* args, char*name)
1785 char* value = map_lookup(args, name);
1787 map_dump(args, stdout, "");
1788 syntaxerror("internal error 2: value %s should be set", name);
1793 static int c_flash(map_t*args)
1795 char* name = lu(args, "name");
1796 char* compressstr = lu(args, "compress");
1797 SRECT bbox = parseBox(lu(args, "bbox"));
1798 int version = parseInt(lu(args, "version"));
1799 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1801 RGBA color = parseColor(lu(args, "background"));
1802 if(!strcmp(name, "!default!") || override_outputname)
1805 if(!strcmp(compressstr, "default"))
1806 compress = version==6;
1807 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1809 else if(!strcmp(compressstr, "no"))
1811 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1813 s_swf(name, bbox, version, fps, compress, color);
1816 int isRelative(char*str)
1818 return !strncmp(str, "<plus>", 6) ||
1819 !strncmp(str, "<minus>", 7);
1821 char* getOffset(char*str)
1823 if(!strncmp(str, "<plus>", 6))
1825 if(!strncmp(str, "<minus>", 7))
1827 syntaxerror("internal error (347)");
1830 int getSign(char*str)
1832 if(!strncmp(str, "<plus>", 6))
1834 if(!strncmp(str, "<minus>", 7))
1836 syntaxerror("internal error (348)");
1839 static dictionary_t points;
1840 static mem_t mpoints;
1841 int points_initialized = 0;
1843 SPOINT getPoint(SRECT r, char*name)
1846 if(!strcmp(name, "center")) {
1848 p.x = (r.xmin + r.xmax)/2;
1849 p.y = (r.ymin + r.ymax)/2;
1853 if(points_initialized)
1854 l = (int)dictionary_lookup(&points, name);
1856 syntaxerror("Invalid point: \"%s\".", name);
1859 return *(SPOINT*)&mpoints.buffer[l];
1861 static int c_gradient(map_t*args)
1863 char*name = lu(args, "name");
1864 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1865 int rotate = parseInt(lu(args, "rotate"));
1869 syntaxerror("colon (:) expected");
1871 s_gradient(name, text, radial,rotate);
1874 static int c_point(map_t*args)
1876 char*name = lu(args, "name");
1880 if(!points_initialized) {
1881 dictionary_init(&points);
1883 points_initialized = 1;
1885 p.x = parseTwip(lu(args, "x"));
1886 p.y = parseTwip(lu(args, "y"));
1887 pos = mem_put(&mpoints, &p, sizeof(p));
1888 string_set(&s1, name);
1890 dictionary_put(&points, s1, (void*)pos);
1893 static int c_play(map_t*args)
1895 char*name = lu(args, "name");
1896 char*loop = lu(args, "loop");
1897 char*nomultiple = lu(args, "nomultiple");
1899 if(!strcmp(nomultiple, "nomultiple"))
1902 nm = parseInt(nomultiple);
1904 if(s_playsound(name, parseInt(loop), nm, 0)) {
1906 } else if(s_swf3action(name, "play")) {
1912 static int c_stop(map_t*args)
1914 char*name = lu(args, "name");
1916 if(s_playsound(name, 0,0,1)) {
1918 } else if(s_swf3action(name, "stop")) {
1921 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
1925 static int c_nextframe(map_t*args)
1927 char*name = lu(args, "name");
1929 if(s_swf3action(name, "nextframe")) {
1932 syntaxerror("I don't know anything about movie \"%s\"", name);
1936 static int c_previousframe(map_t*args)
1938 char*name = lu(args, "name");
1940 if(s_swf3action(name, "previousframe")) {
1943 syntaxerror("I don't know anything about movie \"%s\"", name);
1947 static int c_placement(map_t*args, int type)
1949 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1952 char* luminancestr = lu(args, "luminance");
1953 char* scalestr = lu(args, "scale");
1954 char* scalexstr = lu(args, "scalex");
1955 char* scaleystr = lu(args, "scaley");
1956 char* rotatestr = lu(args, "rotate");
1957 char* shearstr = lu(args, "shear");
1958 char* xstr="", *pivotstr="";
1959 char* ystr="", *anglestr="";
1960 char*above = lu(args, "above"); /*FIXME*/
1961 char*below = lu(args, "below");
1962 char* rstr = lu(args, "red");
1963 char* gstr = lu(args, "green");
1964 char* bstr = lu(args, "blue");
1965 char* astr = lu(args, "alpha");
1966 char* pinstr = lu(args, "pin");
1967 char* as = map_lookup(args, "as");
1975 if(type==9) { // (?) .rotate or .arcchange
1976 pivotstr = lu(args, "pivot");
1977 anglestr = lu(args, "angle");
1979 xstr = lu(args, "x");
1980 ystr = lu(args, "y");
1983 luminance = parseMulAdd(luminancestr);
1986 luminance.mul = 256;
1990 if(scalexstr[0]||scaleystr[0])
1991 syntaxerror("scalex/scaley and scale cannot both be set");
1992 scalexstr = scaleystr = scalestr;
1995 if(type == 0 || type == 4) {
1997 character = lu(args, "character");
1998 parameters_clear(&p);
1999 } else if (type == 5) {
2000 character = lu(args, "name");
2001 parameters_clear(&p);
2004 p = s_getParameters(instance);
2009 if(isRelative(xstr)) {
2010 if(type == 0 || type == 4)
2011 syntaxerror("relative x values not allowed for initial put or startclip");
2012 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2014 p.x = parseTwip(xstr);
2018 if(isRelative(ystr)) {
2019 if(type == 0 || type == 4)
2020 syntaxerror("relative y values not allowed for initial put or startclip");
2021 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2023 p.y = parseTwip(ystr);
2027 /* scale, scalex, scaley */
2029 oldbbox = s_getCharBBox(character);
2031 oldbbox = s_getInstanceBBox(instance);
2033 oldwidth = oldbbox.xmax - oldbbox.xmin;
2034 oldheight = oldbbox.ymax - oldbbox.ymin;
2036 if(oldwidth==0) p.scalex = 1.0;
2039 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2043 if(oldheight==0) p.scaley = 1.0;
2046 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2052 if(isRelative(rotatestr)) {
2053 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2055 p.rotate = parseFloat(rotatestr);
2061 if(isRelative(shearstr)) {
2062 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2064 p.shear = parseFloat(shearstr);
2069 if(isPoint(pivotstr))
2070 p.pivot = parsePoint(pivotstr);
2072 p.pivot = getPoint(oldbbox, pivotstr);
2076 p.pin = parsePoint(pinstr);
2078 p.pin = getPoint(oldbbox, pinstr);
2081 /* color transform */
2083 if(rstr[0] || luminancestr[0]) {
2086 r = parseMulAdd(rstr);
2088 r.add = p.cxform.r0;
2089 r.mul = p.cxform.r1;
2091 r = mergeMulAdd(r, luminance);
2092 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2094 if(gstr[0] || luminancestr[0]) {
2097 g = parseMulAdd(gstr);
2099 g.add = p.cxform.g0;
2100 g.mul = p.cxform.g1;
2102 g = mergeMulAdd(g, luminance);
2103 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2105 if(bstr[0] || luminancestr[0]) {
2108 b = parseMulAdd(bstr);
2110 b.add = p.cxform.b0;
2111 b.mul = p.cxform.b1;
2113 b = mergeMulAdd(b, luminance);
2114 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2117 MULADD a = parseMulAdd(astr);
2118 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2122 s_put(instance, character, p);
2124 s_change(instance, p);
2126 s_qchange(instance, p);
2128 s_jump(instance, p);
2130 s_startclip(instance, character, p);
2131 else if(type == 5) {
2133 s_buttonput(character, as, p);
2135 s_buttonput(character, "shape", p);
2140 static int c_put(map_t*args)
2142 c_placement(args, 0);
2145 static int c_change(map_t*args)
2147 c_placement(args, 1);
2150 static int c_qchange(map_t*args)
2152 c_placement(args, 2);
2155 static int c_arcchange(map_t*args)
2157 c_placement(args, 2);
2160 static int c_jump(map_t*args)
2162 c_placement(args, 3);
2165 static int c_startclip(map_t*args)
2167 c_placement(args, 4);
2170 static int c_show(map_t*args)
2172 c_placement(args, 5);
2175 static int c_del(map_t*args)
2177 char*instance = lu(args, "name");
2178 s_delinstance(instance);
2181 static int c_end(map_t*args)
2186 static int c_sprite(map_t*args)
2188 char* name = lu(args, "name");
2192 static int c_frame(map_t*args)
2194 char*framestr = lu(args, "n");
2195 char*cutstr = lu(args, "cut");
2196 char*name = lu(args, "name");
2199 if(strcmp(cutstr, "no"))
2201 if(isRelative(framestr)) {
2202 frame = s_getframe();
2203 if(getSign(framestr)<0)
2204 syntaxerror("relative frame expressions must be positive");
2205 frame += parseInt(getOffset(framestr));
2208 frame = parseInt(framestr);
2209 if(s_getframe() >= frame
2210 && !(frame==0 && s_getframe()==frame)) // equality is o.k. for frame 0
2211 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2213 s_frame(frame, cut, name);
2216 static int c_primitive(map_t*args)
2218 char*name = lu(args, "name");
2219 char*command = lu(args, "commandname");
2220 int width=0, height=0, r=0;
2221 int linewidth = parseTwip(lu(args, "line"));
2222 char*colorstr = lu(args, "color");
2223 RGBA color = parseColor(colorstr);
2224 char*fillstr = lu(args, "fill");
2231 if(!strcmp(command, "circle"))
2233 else if(!strcmp(command, "filled"))
2237 width = parseTwip(lu(args, "width"));
2238 height = parseTwip(lu(args, "height"));
2239 } else if (type==1) {
2240 r = parseTwip(lu(args, "r"));
2241 } else if (type==2) {
2242 outline = lu(args, "outline");
2245 if(!strcmp(fillstr, "fill"))
2247 if(!strcmp(fillstr, "none"))
2249 if(width<0 || height<0 || linewidth<0 || r<0)
2250 syntaxerror("values width, height, line, r must be positive");
2252 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2253 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2254 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2258 static int c_textshape(map_t*args)
2260 char*name = lu(args, "name");
2261 char*text = lu(args, "text");
2262 char*font = lu(args, "font");
2263 float size = parsePercent(lu(args, "size"));
2265 s_textshape(name, font, size, text);
2269 static int c_swf(map_t*args)
2271 char*name = lu(args, "name");
2272 char*filename = lu(args, "filename");
2273 char*command = lu(args, "commandname");
2274 if(!strcmp(command, "shape"))
2275 warning("Please use .swf instead of .shape");
2276 s_includeswf(name, filename);
2280 static int c_font(map_t*args)
2282 char*name = lu(args, "name");
2283 char*filename = lu(args, "filename");
2284 s_font(name, filename);
2288 static int c_sound(map_t*args)
2290 char*name = lu(args, "name");
2291 char*filename = lu(args, "filename");
2292 s_sound(name, filename);
2296 static int c_text(map_t*args)
2298 char*name = lu(args, "name");
2299 char*text = lu(args, "text");
2300 char*font = lu(args, "font");
2301 float size = parsePercent(lu(args, "size"));
2302 RGBA color = parseColor(lu(args, "color"));
2303 s_text(name, font, text, (int)(size*100), color);
2307 static int c_soundtrack(map_t*args)
2312 static int c_quicktime(map_t*args)
2314 char*name = lu(args, "name");
2315 char*url = lu(args, "url");
2316 s_quicktime(name, url);
2320 static int c_image(map_t*args)
2322 char*command = lu(args, "commandname");
2323 char*name = lu(args, "name");
2324 char*filename = lu(args, "filename");
2325 if(!strcmp(command,"jpeg")) {
2326 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2327 s_image(name, "jpeg", filename, quality);
2329 s_image(name, "png", filename, 0);
2334 static int c_outline(map_t*args)
2336 char*name = lu(args, "name");
2337 char*format = lu(args, "format");
2341 syntaxerror("colon (:) expected");
2343 s_outline(name, format, text);
2347 int fakechar(map_t*args)
2349 char*name = lu(args, "name");
2350 s_box(name, 0, 0, black, 20, 0);
2354 static int c_egon(map_t*args) {return fakechar(args);}
2355 static int c_button(map_t*args) {
2356 char*name = lu(args, "name");
2360 static int current_button_flags = 0;
2361 static int c_on_press(map_t*args)
2363 char*position = lu(args, "position");
2365 if(!strcmp(position, "inside")) {
2366 current_button_flags |= BC_OVERUP_OVERDOWN;
2367 } else if(!strcmp(position, "outside")) {
2368 //current_button_flags |= BC_IDLE_OUTDOWN;
2369 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2370 } else if(!strcmp(position, "anywhere")) {
2371 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2374 if(type == RAWDATA) {
2376 s_buttonaction(current_button_flags, action);
2377 current_button_flags = 0;
2383 static int c_on_release(map_t*args)
2385 char*position = lu(args, "position");
2387 if(!strcmp(position, "inside")) {
2388 current_button_flags |= BC_OVERDOWN_OVERUP;
2389 } else if(!strcmp(position, "outside")) {
2390 current_button_flags |= BC_OUTDOWN_IDLE;
2391 } else if(!strcmp(position, "anywhere")) {
2392 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2395 if(type == RAWDATA) {
2397 s_buttonaction(current_button_flags, action);
2398 current_button_flags = 0;
2404 static int c_on_move_in(map_t*args)
2406 char*position = lu(args, "state");
2408 if(!strcmp(position, "pressed")) {
2409 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2410 } else if(!strcmp(position, "not_pressed")) {
2411 current_button_flags |= BC_IDLE_OVERUP;
2412 } else if(!strcmp(position, "any")) {
2413 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2416 if(type == RAWDATA) {
2418 s_buttonaction(current_button_flags, action);
2419 current_button_flags = 0;
2425 static int c_on_move_out(map_t*args)
2427 char*position = lu(args, "state");
2429 if(!strcmp(position, "pressed")) {
2430 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2431 } else if(!strcmp(position, "not_pressed")) {
2432 current_button_flags |= BC_OVERUP_IDLE;
2433 } else if(!strcmp(position, "any")) {
2434 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2437 if(type == RAWDATA) {
2439 s_buttonaction(current_button_flags, action);
2440 current_button_flags = 0;
2446 static int c_on_key(map_t*args)
2448 char*key = lu(args, "key");
2450 if(strlen(key)==1) {
2453 current_button_flags |= 0x4000 + (key[0]*0x200);
2455 syntaxerror("invalid character: %c"+key[0]);
2460 <ctrl-x> = 0x200*(x-'a')
2464 syntaxerror("invalid key: %s",key);
2467 if(type == RAWDATA) {
2469 s_buttonaction(current_button_flags, action);
2470 current_button_flags = 0;
2477 static int c_edittext(map_t*args)
2479 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
2480 char*name = lu(args, "name");
2481 char*font = lu(args, "font");
2482 int size = (int)(1024*parsePercent(lu(args, "size")));
2483 int width = parseTwip(lu(args, "width"));
2484 int height = parseTwip(lu(args, "height"));
2485 char*text = lu(args, "text");
2486 RGBA color = parseColor(lu(args, "color"));
2487 int maxlength = parseInt(lu(args, "maxlength"));
2488 char*variable = lu(args, "variable");
2489 char*passwordstr = lu(args, "password");
2490 char*wordwrapstr = lu(args, "wordwrap");
2491 char*multilinestr = lu(args, "multiline");
2492 char*htmlstr = lu(args, "html");
2493 char*noselectstr = lu(args, "noselect");
2494 char*readonlystr = lu(args, "readonly");
2495 char*borderstr = lu(args, "border");
2498 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2499 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2500 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2501 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2502 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2503 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2504 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2506 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags);
2510 static int c_morphshape(map_t*args) {return fakechar(args);}
2511 static int c_movie(map_t*args) {return fakechar(args);}
2513 static int c_texture(map_t*args) {return 0;}
2515 static int c_action(map_t*args)
2518 if(type != RAWDATA) {
2519 syntaxerror("colon (:) expected");
2529 command_func_t* func;
2532 {{"flash", c_flash, "bbox=autocrop background=black version=5 fps=50 name=!default! @compress=default"},
2533 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2534 // "import" type stuff
2535 {"swf", c_swf, "name filename"},
2536 {"shape", c_swf, "name filename"},
2537 {"jpeg", c_image, "name filename quality=80%"},
2538 {"png", c_image, "name filename"},
2539 {"movie", c_movie, "name filename"},
2540 {"sound", c_sound, "name filename"},
2541 {"font", c_font, "name filename"},
2542 {"soundtrack", c_soundtrack, "filename"},
2543 {"quicktime", c_quicktime, "url"},
2545 // generators of primitives
2547 {"point", c_point, "name x=0 y=0"},
2548 {"gradient", c_gradient, "name @radial=0 rotate=0"},
2549 {"outline", c_outline, "name format=simple"},
2550 {"textshape", c_textshape, "name font size=100% text"},
2552 // character generators
2553 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2554 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2555 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2557 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2558 {"text", c_text, "name text font size=100% color=white"},
2559 {"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"},
2560 {"morphshape", c_morphshape, "name start end"},
2561 {"button", c_button, "name"},
2562 {"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="},
2563 {"on_press", c_on_press, "position=inside"},
2564 {"on_release", c_on_release, "position=anywhere"},
2565 {"on_move_in", c_on_move_in, "state=not_pressed"},
2566 {"on_move_out", c_on_move_out, "state=not_pressed"},
2567 {"on_key", c_on_key, "key=any"},
2570 {"play", c_play, "name loop=0 @nomultiple=0"},
2571 {"stop", c_stop, "name"},
2572 {"nextframe", c_nextframe, "name"},
2573 {"previousframe", c_previousframe, "name"},
2575 // object placement tags
2576 {"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="},
2577 {"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="},
2578 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2579 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2580 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2581 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2582 {"del", c_del, "name"},
2583 // virtual object placement
2584 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2586 // commands which start a block
2587 //startclip (see above)
2588 {"sprite", c_sprite, "name"},
2589 {"action", c_action, ""},
2595 static map_t parseArguments(char*command, char*pattern)
2611 string_set(&t1, "commandname");
2612 string_set(&t2, command);
2613 map_put(&result, t1, t2);
2615 if(!pattern || !*pattern)
2622 if(!strncmp("<i> ", x, 3)) {
2624 if(type == COMMAND || type == RAWDATA) {
2626 syntaxerror("character name expected");
2628 name[pos].str = "instance";
2630 value[pos].str = text;
2631 value[pos].len = strlen(text);
2635 if(type == ASSIGNMENT)
2638 name[pos].str = "character";
2640 value[pos].str = text;
2641 value[pos].len = strlen(text);
2649 isboolean[pos] = (x[0] =='@');
2662 name[pos].len = d-x;
2667 name[pos].len = e-x;
2668 value[pos].str = e+1;
2669 value[pos].len = d-e-1;
2677 /* for(t=0;t<len;t++) {
2678 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2679 isboolean[t]?"(boolean)":"");
2684 if(type == RAWDATA || type == COMMAND) {
2689 // first, search for boolean arguments
2690 for(pos=0;pos<len;pos++)
2692 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2694 if(type == ASSIGNMENT)
2696 value[pos].str = text;
2697 value[pos].len = strlen(text);
2698 /*printf("setting boolean parameter %s (to %s)\n",
2699 strdup_n(name[pos], namelen[pos]),
2700 strdup_n(value[pos], valuelen[pos]));*/
2705 // second, search for normal arguments
2707 for(pos=0;pos<len;pos++)
2709 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2710 (type != ASSIGNMENT && !set[pos])) {
2712 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2714 if(type == ASSIGNMENT)
2717 value[pos].str = text;
2718 value[pos].len = strlen(text);
2720 printf("setting parameter %s (to %s)\n",
2721 strdup_n(name[pos].str, name[pos].len),
2722 strdup_n(value[pos].str, value[pos].len));
2728 syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
2732 for(t=0;t<len;t++) {
2733 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2736 for(t=0;t<len;t++) {
2737 if(value[t].str && value[t].str[0] == '*') {
2738 //relative default- take value from some other parameter
2740 for(s=0;s<len;s++) {
2741 if(value[s].len == value[t].len-1 &&
2742 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2743 value[t].str = value[s].str;
2746 if(value[t].str == 0) {
2748 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2752 /* ok, now construct the dictionary from the parameters */
2756 map_put(&result, name[t], value[t]);
2760 static void parseArgumentsForCommand(char*command)
2765 msg("<verbose> parse Command: %s (line %d)", command, line);
2767 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2768 if(!strcmp(arguments[t].command, command)) {
2770 /* ugly hack- will be removed soon (once documentation and .sc generating
2771 utilities have been changed) */
2772 if(!strcmp(command, "swf") && !stackpos) {
2773 warning("Please use .flash instead of .swf- this will be mandatory soon");
2778 args = parseArguments(command, arguments[t].arguments);
2784 syntaxerror("command %s not known", command);
2786 // catch missing .flash directives at the beginning of a file
2787 if(strcmp(command, "flash") && !stackpos)
2789 syntaxerror("No movie defined- use .flash first");
2793 printf(".%s\n", command);fflush(stdout);
2794 map_dump(&args, stdout, "\t");fflush(stdout);
2797 (*arguments[nr].func)(&args);
2799 /*if(!strcmp(command, "button") ||
2800 !strcmp(command, "action")) {
2803 if(type == COMMAND) {
2804 if(!strcmp(text, "end"))
2818 int main (int argc,char ** argv)
2821 processargs(argc, argv);
2822 initLog(0,-1,0,0,-1,verbose);
2825 args_callback_usage(argv[0]);
2829 file = generateTokens(filename);
2831 printf("parser returned error.\n");
2837 while(!noMoreTokens()) {
2840 syntaxerror("command expected");
2841 parseArgumentsForCommand(text);