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 optimize = 0;
44 static int override_outputname = 0;
46 static struct options_t options[] = {
55 int args_callback_option(char*name,char*val)
57 if(!strcmp(name, "V")) {
58 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
61 else if(!strcmp(name, "o")) {
63 override_outputname = 1;
66 else if(!strcmp(name, "O")) {
70 else if(!strcmp(name, "v")) {
75 printf("Unknown option: -%s\n", name);
80 int args_callback_longoption(char*name,char*val)
82 return args_long2shortoption(options, name, val);
84 void args_callback_usage(char *name)
87 printf("Usage: %s [-o file.swf] file.sc\n", name);
89 printf("-h , --help Print short help message and exit\n");
90 printf("-V , --version Print version info and exit\n");
91 printf("-v , --verbose Increase verbosity. \n");
92 printf("-o , --output <filename> Set output file to <filename>.\n");
95 int args_callback_command(char*name,char*val)
98 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
105 static struct token_t* file;
114 static void syntaxerror(char*format, ...)
118 va_start(arglist, format);
119 vsprintf(buf, format, arglist);
121 printf("\"%s\", line %d column %d: error- %s\n", filename, line, column, buf);
125 static void warning(char*format, ...)
129 va_start(arglist, format);
130 vsprintf(buf, format, arglist);
132 printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
135 static void readToken()
137 type = file[pos].type;
139 syntaxerror("unexpected end of file");
141 text = file[pos].text;
142 textlen = strlen(text);
143 line = file[pos].line;
144 column = file[pos].column;
146 //printf("---> %d(%s) %s\n", type, type_names[type], text);
149 static void pushBack()
152 if(!pos) syntaxerror("internal error 3");
157 textlen = strlen(text);
160 column = file[p].column;
163 static int noMoreTokens()
165 if(file[pos].type == END)
170 // ------------------------------ swf routines ----------------------------
174 int type; //0=swf, 1=sprite, 2=clip, 3=button
180 /* for sprites (1): */
186 dictionary_t oldinstances;
191 static int stackpos = 0;
193 static dictionary_t characters;
194 static dictionary_t images;
195 static dictionary_t outlines;
196 static dictionary_t gradients;
197 static char idmap[65536];
198 static TAG*tag = 0; //current tag
200 static int id; //current character id
201 static int currentframe; //current frame in current level
202 static SRECT currentrect; //current bounding box in current level
203 static U16 currentdepth;
204 static dictionary_t instances;
205 static dictionary_t fonts;
206 static dictionary_t sounds;
208 typedef struct _parameters {
210 float scalex, scaley;
218 typedef struct _character {
224 typedef struct _instance {
225 character_t*character;
227 parameters_t parameters;
228 TAG* lastTag; //last tag which set the object
229 U16 lastFrame; //frame lastTag is in
232 typedef struct _outline {
237 typedef struct _gradient {
243 static void character_init(character_t*c)
245 memset(c, 0, sizeof(character_t));
247 static character_t* character_new()
250 c = (character_t*)malloc(sizeof(character_t));
254 static void instance_init(instance_t*i)
256 memset(i, 0, sizeof(instance_t));
258 static instance_t* instance_new()
261 c = (instance_t*)malloc(sizeof(instance_t));
266 static void incrementid()
270 syntaxerror("Out of character ids.");
275 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
277 character_t* c = character_new();
279 c->definingTag = ctag;
282 if(dictionary_lookup(&characters, name))
283 syntaxerror("character %s defined twice", name);
284 dictionary_put2(&characters, name, c);
286 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
288 swf_SetString(tag, name);
289 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
292 swf_SetString(tag, name);
294 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
296 character_t* c = character_new();
297 c->definingTag = ctag;
301 if(dictionary_lookup(&images, name))
302 syntaxerror("image %s defined twice", name);
303 dictionary_put2(&images, name, c);
305 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
307 instance_t* i = instance_new();
310 //swf_GetMatrix(0, &i->matrix);
311 if(dictionary_lookup(&instances, name))
312 syntaxerror("object %s defined twice", name);
313 dictionary_put2(&instances, name, i);
317 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)
320 p->scalex = scalex; p->scaley = scaley;
321 p->pin = pin; p->pivot = pivot;
322 p->rotate = rotate; p->cxform = cxform;
326 static void parameters_clear(parameters_t*p)
329 p->scalex = 1.0; p->scaley = 1.0;
332 p->pivot.x = 0; p->pivot.y = 0;
335 swf_GetCXForm(0, &p->cxform, 1);
338 static void makeMatrix(MATRIX*m, parameters_t*p)
347 sx = p->scalex*cos(p->rotate/360*2*3.14159265358979);
348 r1 = -p->scalex*sin(p->rotate/360*2*3.14159265358979)+sx*p->shear;
349 r0 = p->scaley*sin(p->rotate/360*2*3.14159265358979);
350 sy = p->scaley*cos(p->rotate/360*2*3.14159265358979)+r0*p->shear;
352 m->sx = (int)(sx*65536+0.5);
353 m->r1 = (int)(r1*65536+0.5);
354 m->r0 = (int)(r0*65536+0.5);
355 m->sy = (int)(sy*65536+0.5);
359 h = swf_TurnPoint(p->pin, m);
364 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
369 r = swf_TurnRect(rect, &m);
370 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
371 currentrect.xmax == 0 && currentrect.ymax == 0)
374 swf_ExpandRect2(¤trect, &r);
378 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
380 SWF*swf = (SWF*)malloc(sizeof(SWF));
383 syntaxerror(".swf blocks can't be nested");
385 memset(swf, 0, sizeof(swf));
386 swf->fileVersion = version;
388 swf->frameRate = fps;
389 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
390 swf->compressed = compress;
391 swf_SetRGB(tag,&background);
393 if(stackpos==sizeof(stack)/sizeof(stack[0]))
394 syntaxerror("too many levels of recursion");
396 dictionary_init(&characters);
397 dictionary_init(&images);
398 dictionary_init(&outlines);
399 dictionary_init(&gradients);
400 dictionary_init(&instances);
401 dictionary_init(&fonts);
402 dictionary_init(&sounds);
404 memset(&stack[stackpos], 0, sizeof(stack[0]));
405 stack[stackpos].type = 0;
406 stack[stackpos].filename = strdup(name);
407 stack[stackpos].swf = swf;
408 stack[stackpos].oldframe = -1;
413 memset(¤trect, 0, sizeof(currentrect));
416 memset(idmap, 0, sizeof(idmap));
420 void s_sprite(char*name)
422 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
423 swf_SetU16(tag, id); //id
424 swf_SetU16(tag, 0); //frames
426 memset(&stack[stackpos], 0, sizeof(stack[0]));
427 stack[stackpos].type = 1;
428 stack[stackpos].oldframe = currentframe;
429 stack[stackpos].olddepth = currentdepth;
430 stack[stackpos].oldrect = currentrect;
431 stack[stackpos].oldinstances = instances;
432 stack[stackpos].tag = tag;
433 stack[stackpos].id = id;
434 stack[stackpos].name = strdup(name);
436 /* FIXME: those four fields should be bundled together */
437 dictionary_init(&instances);
440 memset(¤trect, 0, sizeof(currentrect));
446 typedef struct _buttonrecord
454 typedef struct _button
458 buttonrecord_t records[4];
461 static button_t mybutton;
463 void s_button(char*name)
465 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
466 swf_SetU16(tag, id); //id
467 swf_ButtonSetFlags(tag, 0); //menu=no
469 memset(&mybutton, 0, sizeof(mybutton));
471 memset(&stack[stackpos], 0, sizeof(stack[0]));
472 stack[stackpos].type = 3;
473 stack[stackpos].tag = tag;
474 stack[stackpos].id = id;
475 stack[stackpos].name = strdup(name);
476 stack[stackpos].oldrect = currentrect;
477 memset(¤trect, 0, sizeof(currentrect));
482 void s_buttonput(char*character, char*as, parameters_t p)
484 character_t* c = dictionary_lookup(&characters, character);
489 if(!stackpos || (stack[stackpos-1].type != 3)) {
490 syntaxerror(".show may only appear in .button");
493 syntaxerror("character %s not known (in .shape %s)", character, character);
495 if(mybutton.endofshapes) {
496 syntaxerror("a .do may not precede a .show", character, character);
499 m = s_instancepos(c->size, &p);
507 if(*s==',' || *s==0) {
508 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
509 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
510 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
511 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
512 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
513 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
520 static void setbuttonrecords(TAG*tag)
522 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
523 if(!mybutton.endofshapes) {
526 if(!mybutton.records[3].set) {
527 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
531 if(mybutton.records[t].set) {
532 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
535 swf_SetU8(tag,0); // end of button records
536 mybutton.endofshapes = 1;
540 void s_buttonaction(int flags, char*action)
546 setbuttonrecords(stack[stackpos-1].tag);
548 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
550 syntaxerror("Couldn't compile ActionScript");
553 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
554 swf_ActionSet(stack[stackpos-1].tag, a);
555 mybutton.nr_actions++;
560 static void setactionend(TAG*tag)
562 if(!mybutton.nr_actions) {
563 /* no actions means we didn't have an actionoffset,
564 which means we can't signal the end of the
565 buttonaction records, so, *sigh*, we have
566 to insert a dummy record */
567 swf_SetU16(tag, 0); //offset
568 swf_SetU16(tag, 0); //condition
569 swf_SetU8(tag, 0); //action
573 static void s_endButton()
576 setbuttonrecords(stack[stackpos-1].tag);
577 setactionend(stack[stackpos-1].tag);
580 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
584 tag = stack[stackpos].tag;
585 currentrect = stack[stackpos].oldrect;
587 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
588 free(stack[stackpos].name);
591 TAG* removeFromTo(TAG*from, TAG*to)
593 TAG*save = from->prev;
595 TAG*next = from->next;
603 static void s_endSprite()
605 SRECT r = currentrect;
607 if(stack[stackpos].cut)
608 tag = removeFromTo(stack[stackpos].cut, tag);
612 /* TODO: before clearing, prepend "<spritename>." to names and
613 copy into old instances dict */
614 dictionary_clear(&instances);
616 currentframe = stack[stackpos].oldframe;
617 currentrect = stack[stackpos].oldrect;
618 currentdepth = stack[stackpos].olddepth;
619 instances = stack[stackpos].oldinstances;
621 tag = swf_InsertTag(tag, ST_END);
623 tag = stack[stackpos].tag;
626 syntaxerror("internal error(7)");
628 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
629 free(stack[stackpos].name);
632 static void s_endSWF()
638 if(stack[stackpos].cut)
639 tag = removeFromTo(stack[stackpos].cut, tag);
643 swf = stack[stackpos].swf;
644 filename = stack[stackpos].filename;
646 tag = swf_InsertTag(tag, ST_SHOWFRAME);
647 tag = swf_InsertTag(tag, ST_END);
649 swf_OptimizeTagOrder(swf);
655 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
656 swf->movieSize = currentrect; /* "autocrop" */
659 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
660 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
661 swf->movieSize.ymax += 20;
664 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
666 syntaxerror("couldn't create output file %s", filename);
669 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
671 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
675 dictionary_clear(&instances);
676 dictionary_clear(&characters);
677 dictionary_clear(&images);
678 dictionary_clear(&outlines);
679 dictionary_clear(&gradients);
680 dictionary_clear(&fonts);
681 dictionary_clear(&sounds);
691 if(stack[stackpos-1].type == 0)
692 syntaxerror("End of file encountered in .flash block");
693 if(stack[stackpos-1].type == 1)
694 syntaxerror("End of file encountered in .sprite block");
695 if(stack[stackpos-1].type == 2)
696 syntaxerror("End of file encountered in .clip block");
702 return currentframe+1;
705 void s_frame(int nr, int cut, char*name)
711 syntaxerror("Illegal frame number");
712 nr--; // internally, frame 1 is frame 0
714 for(t=currentframe;t<nr;t++) {
715 tag = swf_InsertTag(tag, ST_SHOWFRAME);
716 if(t==nr-1 && name && *name) {
717 tag = swf_InsertTag(tag, ST_FRAMELABEL);
718 swf_SetString(tag, name);
721 if(nr == 0 && currentframe == 0 && name) {
722 tag = swf_InsertTag(tag, ST_FRAMELABEL);
723 swf_SetString(tag, name);
728 syntaxerror("Can't cut, frame empty");
730 stack[stackpos].cut = tag;
736 int parseColor2(char*str, RGBA*color);
738 int addFillStyle(SHAPE*s, SRECT*r, char*texture)
743 if(texture[0] == '#') {
744 parseColor2(texture, &color);
745 return swf_ShapeAddSolidFillStyle(s, &color);
746 } else if((image = dictionary_lookup(&images, texture))) {
748 swf_GetMatrix(0, &m);
749 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
750 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
753 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
754 } /*else if ((texture = dictionary_lookup(&textures, texture))) {
755 } */ else if ((gradient = dictionary_lookup(&gradients, texture))) {
759 swf_GetMatrix(0, &rot);
760 ccos = cos(-gradient->rotate*2*3.14159265358979/360);
761 csin = sin(-gradient->rotate*2*3.14159265358979/360);
763 rot.r1 = -csin*65536;
766 r2 = swf_TurnRect(*r, &rot);
767 swf_GetMatrix(0, &m);
768 m.sx = (r2.xmax - r2.xmin)*2*ccos;
769 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
770 m.r0 = (r2.ymax - r2.ymin)*2*csin;
771 m.sy = (r2.ymax - r2.ymin)*2*ccos;
772 m.tx = r->xmin + (r->xmax - r->xmin)/2;
773 m.ty = r->ymin + (r->ymax - r->ymin)/2;
774 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
775 } else if (parseColor2(texture, &color)) {
776 return swf_ShapeAddSolidFillStyle(s, &color);
778 syntaxerror("not a color/fillstyle: %s", texture);
783 RGBA black={r:0,g:0,b:0,a:0};
784 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
793 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
795 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
798 fs1 = addFillStyle(s, &r2, texture);
801 r.xmin = r2.xmin-linewidth-linewidth/2;
802 r.ymin = r2.ymin-linewidth-linewidth/2;
803 r.xmax = r2.xmax+linewidth+linewidth/2;
804 r.ymax = r2.ymax+linewidth+linewidth/2;
806 swf_SetShapeHeader(tag,s);
807 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
808 swf_ShapeSetLine(tag,s,width,0);
809 swf_ShapeSetLine(tag,s,0,height);
810 swf_ShapeSetLine(tag,s,-width,0);
811 swf_ShapeSetLine(tag,s,0,-height);
812 swf_ShapeSetEnd(tag);
815 s_addcharacter(name, id, tag, r);
819 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
825 outline = dictionary_lookup(&outlines, outlinename);
827 syntaxerror("outline %s not defined", outlinename);
831 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
833 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
835 fs1 = addFillStyle(s, &r2, texture);
837 syntaxerror("non filled outlines not yet supported- please supply a fill=<color/texture> argument");
839 rect.xmin = r2.xmin-linewidth-linewidth/2;
840 rect.ymin = r2.ymin-linewidth-linewidth/2;
841 rect.xmax = r2.xmax+linewidth+linewidth/2;
842 rect.ymax = r2.ymax+linewidth+linewidth/2;
844 swf_SetRect(tag,&rect);
845 swf_SetShapeStyles(tag, s);
846 swf_SetShapeBits(tag, outline->shape); //does not count bits!
847 swf_SetBlock(tag, outline->shape->data, (outline->shape->bitlen+7)/8);
850 s_addcharacter(name, id, tag, rect);
854 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
859 r2.xmin = r2.ymin = 0;
863 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
865 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
867 fs1 = addFillStyle(s, &r2, texture);
869 rect.xmin = r2.xmin-linewidth-linewidth/2;
870 rect.ymin = r2.ymin-linewidth-linewidth/2;
871 rect.xmax = r2.xmax+linewidth+linewidth/2;
872 rect.ymax = r2.ymax+linewidth+linewidth/2;
874 swf_SetRect(tag,&rect);
875 swf_SetShapeHeader(tag,s);
876 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
877 swf_ShapeSetCircle(tag, s, r,r,r,r);
878 swf_ShapeSetEnd(tag);
881 s_addcharacter(name, id, tag, rect);
885 void s_textshape(char*name, char*fontname, float size, char*_text)
888 U8*text = (U8*)_text;
892 font = dictionary_lookup(&fonts, fontname);
894 syntaxerror("font \"%s\" not known!", fontname);
896 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
897 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
898 s_box(name, 0, 0, black, 20, 0);
901 g = font->ascii2glyph[text[0]];
903 outline = malloc(sizeof(outline_t));
904 memset(outline, 0, sizeof(outline_t));
905 outline->shape = font->glyph[g].shape;
906 outline->bbox = font->layout->bounds[g];
910 swf_Shape11DrawerInit(&draw, 0);
911 swf_DrawText(&draw, font, (int)(size*100), _text);
913 outline->shape = swf_ShapeDrawerToShape(&draw);
914 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
918 if(dictionary_lookup(&outlines, name))
919 syntaxerror("outline %s defined twice", name);
920 dictionary_put2(&outlines, name, outline);
923 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
928 font = dictionary_lookup(&fonts, fontname);
930 syntaxerror("font \"%s\" not known!", fontname);
932 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
934 if(!font->numchars) {
935 s_box(name, 0, 0, black, 20, 0);
938 r = swf_SetDefineText(tag, font, &color, text, size);
940 s_addcharacter(name, id, tag, r);
944 void s_quicktime(char*name, char*url)
949 memset(&r, 0, sizeof(r));
951 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
953 swf_SetString(tag, url);
955 s_addcharacter(name, id, tag, r);
959 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags)
962 EditTextLayout layout;
965 font = dictionary_lookup(&fonts, fontname);
967 syntaxerror("font \"%s\" not known!", fontname);
968 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
971 layout.leftmargin = 0;
972 layout.rightmargin = 0;
979 swf_SetEditText(tag, flags|ET_USEOUTLINES, r, text, color, maxlength, font->id, size, &layout, variable);
981 s_addcharacter(name, id, tag, r);
985 /* type: either "jpeg" or "png"
987 void s_image(char*name, char*type, char*filename, int quality)
989 /* an image is actually two folded: 1st bitmap, 2nd character.
990 Both of them can be used separately */
992 /* step 1: the bitmap */
997 warning("image type \"png\" not supported yet!");
998 s_box(name, 0, 0, black, 20, 0);
1002 #ifndef HAVE_LIBJPEG
1003 warning("no jpeg support compiled in");
1004 s_box(name, 0, 0, black, 20, 0);
1007 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1008 swf_SetU16(tag, imageID);
1010 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1011 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1014 swf_GetJPEGSize(filename, &width, &height);
1021 s_addimage(name, id, tag, r);
1026 /* step 2: the character */
1027 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1028 swf_SetU16(tag, id);
1029 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1031 s_addcharacter(name, id, tag, r);
1035 void dumpSWF(SWF*swf)
1037 TAG* tag = swf->firstTag;
1038 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1040 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1043 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1046 void s_font(char*name, char*filename)
1049 font = swf_LoadFont(filename);
1052 warning("Couldn't open font file \"%s\"", filename);
1053 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1054 memset(font, 0, sizeof(SWFFONT));
1055 dictionary_put2(&fonts, name, font);
1061 /* fix the layout. Only needed for old fonts */
1063 for(t=0;t<font->numchars;t++) {
1064 font->glyph[t].advance = 0;
1067 swf_FontCreateLayout(font);
1069 /* just in case this thing is used in .edittext later on */
1070 swf_FontPrepareForEditText(font);
1073 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1074 swf_FontSetDefine2(tag, font);
1077 if(dictionary_lookup(&fonts, name))
1078 syntaxerror("font %s defined twice", name);
1079 dictionary_put2(&fonts, name, font);
1084 typedef struct _sound_t
1090 void s_sound(char*name, char*filename)
1092 struct WAV wav, wav2;
1097 if(!readWAV(filename, &wav)) {
1098 warning("Couldn't read wav file \"%s\"", filename);
1102 convertWAV2mono(&wav, &wav2, 44100);
1103 samples = (U16*)wav2.data;
1104 numsamples = wav2.size/2;
1108 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1109 swf_SetU16(tag, id); //id
1110 swf_SetSoundDefine(tag, samples, numsamples);
1112 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1116 if(dictionary_lookup(&sounds, name))
1117 syntaxerror("sound %s defined twice", name);
1118 dictionary_put2(&sounds, name, sound);
1126 static char* gradient_getToken(const char**p)
1130 while(**p && strchr(" \t\n\r", **p)) {
1134 while(**p && !strchr(" \t\n\r", **p)) {
1137 result = malloc((*p)-start+1);
1138 memcpy(result,start,(*p)-start+1);
1139 result[(*p)-start] = 0;
1143 float parsePercent(char*str);
1144 RGBA parseColor(char*str);
1146 GRADIENT parseGradient(const char*str)
1149 const char* p = str;
1150 memset(&gradient, 0, sizeof(GRADIENT));
1152 char*posstr,*colorstr;
1155 posstr = gradient_getToken(&p);
1158 pos = parsePercent(posstr);
1159 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1160 colorstr = gradient_getToken(&p);
1161 color = parseColor(colorstr);
1162 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1163 warning("gradient record too big- max size is 8, rest ignored");
1166 gradient.ratios[gradient.num] = (int)(pos*255.0);
1167 gradient.rgba[gradient.num] = color;
1175 void s_gradient(char*name, const char*text, int radial, int rotate)
1177 gradient_t* gradient;
1178 gradient = malloc(sizeof(gradient_t));
1179 memset(gradient, 0, sizeof(gradient_t));
1180 gradient->gradient = parseGradient(text);
1181 gradient->radial = radial;
1182 gradient->rotate = rotate;
1184 if(dictionary_lookup(&gradients, name))
1185 syntaxerror("gradient %s defined twice", name);
1186 dictionary_put2(&gradients, name, gradient);
1189 void s_action(const char*text)
1192 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1194 syntaxerror("Couldn't compile ActionScript");
1197 tag = swf_InsertTag(tag, ST_DOACTION);
1199 swf_ActionSet(tag, a);
1204 int s_swf3action(char*name, char*action)
1207 instance_t* object = 0;
1209 dictionary_lookup(&instances, name);
1210 if(!object && name && *name) {
1211 /* we have a name, but couldn't find it. Abort. */
1214 a = action_SetTarget(0, name);
1215 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1216 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1217 else if(!strcmp(action, "stop")) a = action_Stop(a);
1218 else if(!strcmp(action, "play")) a = action_Play(a);
1219 a = action_SetTarget(a, "");
1222 tag = swf_InsertTag(tag, ST_DOACTION);
1223 swf_ActionSet(tag, a);
1228 void s_outline(char*name, char*format, char*source)
1237 swf_Shape11DrawerInit(&draw, 0);
1238 draw_string(&draw, source);
1240 shape = swf_ShapeDrawerToShape(&draw);
1241 //shape2 = swf_ShapeToShape2(shape);
1242 //bounds = swf_GetShapeBoundingBox(shape2);
1243 //swf_Shape2Free(shape2);
1244 bounds = swf_ShapeDrawerGetBBox(&draw);
1245 draw.dealloc(&draw);
1247 outline = (outline_t*)malloc(sizeof(outline_t));
1248 memset(outline, 0, sizeof(outline_t));
1249 outline->shape = shape;
1250 outline->bbox = bounds;
1252 if(dictionary_lookup(&outlines, name))
1253 syntaxerror("outline %s defined twice", name);
1254 dictionary_put2(&outlines, name, outline);
1257 int s_playsound(char*name, int loops, int nomultiple, int stop)
1262 sound = dictionary_lookup(&sounds, name);
1267 tag = swf_InsertTag(tag, ST_STARTSOUND);
1268 swf_SetU16(tag, sound->id); //id
1269 memset(&info, 0, sizeof(info));
1272 info.nomultiple = nomultiple;
1273 swf_SetSoundInfo(tag, &info);
1277 void s_includeswf(char*name, char*filename)
1285 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1286 f = open(filename,O_RDONLY|O_BINARY);
1288 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1289 s_box(name, 0, 0, black, 20, 0);
1292 if (swf_ReadSWF(f,&swf)<0) {
1293 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1294 s_box(name, 0, 0, black, 20, 0);
1299 /* FIXME: The following sets the bounding Box for the character.
1300 It is wrong for two reasons:
1301 a) It may be too small (in case objects in the movie clip at the borders)
1302 b) it may be too big (because the poor movie never got autocropped)
1306 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1307 swf_SetU16(tag, id);
1310 swf_Relocate(&swf, idmap);
1312 ftag = swf.firstTag;
1316 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1317 if(cutout[t] == ftag->id) {
1321 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1323 if(ftag->id == ST_END)
1327 /* We simply dump all tags right after the sprite
1328 header, relying on the fact that swf_OptimizeTagOrder() will
1329 sort things out for us later.
1330 We also rely on the fact that the imported SWF is well-formed.
1332 tag = swf_InsertTag(tag, ftag->id);
1333 swf_SetBlock(tag, ftag->data, ftag->len);
1337 syntaxerror("Included file %s contains errors", filename);
1338 tag = swf_InsertTag(tag, ST_END);
1342 s_addcharacter(name, id, tag, r);
1345 SRECT s_getCharBBox(char*name)
1347 character_t* c = dictionary_lookup(&characters, name);
1348 if(!c) syntaxerror("character '%s' unknown(2)", name);
1351 SRECT s_getInstanceBBox(char*name)
1353 instance_t * i = dictionary_lookup(&instances, name);
1355 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1357 if(!c) syntaxerror("internal error(5)");
1360 parameters_t s_getParameters(char*name)
1362 instance_t * i = dictionary_lookup(&instances, name);
1363 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1364 return i->parameters;
1366 void s_startclip(char*instance, char*character, parameters_t p)
1368 character_t* c = dictionary_lookup(&characters, character);
1372 syntaxerror("character %s not known", character);
1374 i = s_addinstance(instance, c, currentdepth);
1376 m = s_instancepos(i->character->size, &p);
1378 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1379 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1380 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1382 i->lastFrame= currentframe;
1384 stack[stackpos].tag = tag;
1385 stack[stackpos].type = 2;
1394 swf_SetTagPos(stack[stackpos].tag, 0);
1395 swf_GetPlaceObject(stack[stackpos].tag, &p);
1396 p.clipdepth = currentdepth;
1398 swf_ClearTag(stack[stackpos].tag);
1399 swf_SetPlaceObject(stack[stackpos].tag, &p);
1403 void s_put(char*instance, char*character, parameters_t p)
1405 character_t* c = dictionary_lookup(&characters, character);
1409 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1412 i = s_addinstance(instance, c, currentdepth);
1414 m = s_instancepos(i->character->size, &p);
1416 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1417 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1419 i->lastFrame = currentframe;
1423 void s_jump(char*instance, parameters_t p)
1425 instance_t* i = dictionary_lookup(&instances, instance);
1428 syntaxerror("instance %s not known", instance);
1432 m = s_instancepos(i->character->size, &p);
1434 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1435 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1437 i->lastFrame = currentframe;
1440 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1444 if(num==0 || num==1)
1446 ratio = (float)pos/(float)num;
1448 p.x = (p2->x-p1->x)*ratio + p1->x;
1449 p.y = (p2->y-p1->y)*ratio + p1->y;
1450 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1451 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1452 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1453 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1455 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1456 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1457 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1458 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1460 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1461 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1462 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1463 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1465 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1466 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1467 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1468 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1472 void s_change(char*instance, parameters_t p2)
1474 instance_t* i = dictionary_lookup(&instances, instance);
1478 int frame, allframes;
1480 syntaxerror("instance %s not known", instance);
1484 allframes = currentframe - i->lastFrame - 1;
1486 warning(".change ignored. can only .put/.change an object once per frame.");
1490 m = s_instancepos(i->character->size, &p2);
1491 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1492 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1495 /* o.k., we got the start and end point set. Now iterate though all the
1496 tags in between, inserting object changes after each new frame */
1499 if(!t) syntaxerror("internal error(6)");
1501 while(frame < allframes) {
1502 if(t->id == ST_SHOWFRAME) {
1507 p = s_interpolate(&p1, &p2, frame, allframes);
1508 m = s_instancepos(i->character->size, &p); //needed?
1509 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1510 i->lastFrame = currentframe;
1511 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1513 if(frame == allframes)
1518 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1522 void s_delinstance(char*instance)
1524 instance_t* i = dictionary_lookup(&instances, instance);
1526 syntaxerror("instance %s not known", instance);
1528 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1529 swf_SetU16(tag, i->depth);
1530 dictionary_del(&instances, instance);
1533 void s_qchange(char*instance, parameters_t p)
1540 syntaxerror(".end unexpected");
1541 if(stack[stackpos-1].type == 0)
1543 else if(stack[stackpos-1].type == 1)
1545 else if(stack[stackpos-1].type == 2)
1547 else if(stack[stackpos-1].type == 3)
1549 else syntaxerror("internal error 1");
1552 // ------------------------------------------------------------------------
1554 typedef int command_func_t(map_t*args);
1556 SRECT parseBox(char*str)
1559 float xmin, xmax, ymin, ymax;
1560 char*x = strchr(str, 'x');
1562 if(!strcmp(str, "autocrop")) {
1563 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1567 d1 = strchr(x+1, ':');
1569 d2 = strchr(d1+1, ':');
1571 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1575 else if(d1 && !d2) {
1576 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1582 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1587 r.xmin = (SCOORD)(xmin*20);
1588 r.ymin = (SCOORD)(ymin*20);
1589 r.xmax = (SCOORD)(xmax*20);
1590 r.ymax = (SCOORD)(ymax*20);
1593 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1596 float parseFloat(char*str)
1600 int parseInt(char*str)
1605 if(str[0]=='+' || str[0]=='-')
1609 if(str[t]<'0' || str[t]>'9')
1610 syntaxerror("Not an Integer: \"%s\"", str);
1613 int parseTwip(char*str)
1617 if(str[0]=='+' || str[0]=='-') {
1622 dot = strchr(str, '.');
1626 return sign*parseInt(str)*20;
1628 int l=strlen(++dot);
1630 for(s=str;s<dot-1;s++)
1631 if(*s<'0' || *s>'9')
1632 syntaxerror("Not a coordinate: \"%s\"", str);
1634 if(*s<'0' || *s>'9')
1635 syntaxerror("Not a coordinate: \"%s\"", str);
1637 if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) {
1638 warning("precision loss: %s converted to twip", str);
1643 return sign*atoi(str)*20;
1645 return sign*atoi(str)*20+atoi(dot)*2;
1647 return sign*atoi(str)*20+atoi(dot)/5;
1652 int isPoint(char*str)
1654 if(strchr(str, '('))
1660 SPOINT parsePoint(char*str)
1664 int l = strlen(str);
1665 char*comma = strchr(str, ',');
1666 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1667 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1668 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1669 p.x = parseTwip(tmp);
1670 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1671 p.y = parseTwip(tmp);
1675 int parseColor2(char*str, RGBA*color)
1677 int l = strlen(str);
1681 struct {unsigned char r,g,b;char*name;} colors[] =
1682 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1683 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1684 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1685 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1686 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1687 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1688 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1689 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1690 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1691 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1692 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1693 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1697 if(str[0]=='#' && (l==7 || l==9)) {
1698 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1700 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1702 color->r = r; color->g = g; color->b = b; color->a = a;
1705 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1706 if(!strcmp(str, colors[t].name)) {
1711 color->r = r; color->g = g; color->b = b; color->a = a;
1717 RGBA parseColor(char*str)
1720 if(!parseColor2(str, &c))
1721 syntaxerror("Expression '%s' is not a color", str);
1725 typedef struct _muladd {
1730 MULADD parseMulAdd(char*str)
1733 char* str2 = (char*)malloc(strlen(str)+5);
1740 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1741 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1742 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1743 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1744 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1745 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1746 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1747 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1748 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1749 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1751 syntaxerror("'%s' is not a valid color transform expression", str);
1753 m.add = (int)(add*256);
1754 m.mul = (int)(mul*256);
1759 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1761 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1762 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1764 if(a<-32768) a=-32768;
1765 if(a>32767) a=32767;
1766 if(m<-32768) m=-32768;
1767 if(m>32767) m=32767;
1773 float parsePercent(char*str)
1775 int l = strlen(str);
1779 return atoi(str)/100.0;
1781 syntaxerror("Expression '%s' is not a percentage", str);
1784 int isPercent(char*str)
1786 return str[strlen(str)-1]=='%';
1788 int parseNewSize(char*str, int size)
1791 return parsePercent(str)*size;
1793 return (int)(atof(str)*20);
1796 int isColor(char*str)
1799 return parseColor2(str, &c);
1802 static char* lu(map_t* args, char*name)
1804 char* value = map_lookup(args, name);
1806 map_dump(args, stdout, "");
1807 syntaxerror("internal error 2: value %s should be set", name);
1812 static int c_flash(map_t*args)
1814 char* name = lu(args, "name");
1815 char* compressstr = lu(args, "compress");
1816 SRECT bbox = parseBox(lu(args, "bbox"));
1817 int version = parseInt(lu(args, "version"));
1818 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1820 RGBA color = parseColor(lu(args, "background"));
1821 if(!strcmp(name, "!default!") || override_outputname)
1824 if(!strcmp(compressstr, "default"))
1825 compress = version==6;
1826 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1828 else if(!strcmp(compressstr, "no"))
1830 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1832 s_swf(name, bbox, version, fps, compress, color);
1835 int isRelative(char*str)
1837 return !strncmp(str, "<plus>", 6) ||
1838 !strncmp(str, "<minus>", 7);
1840 char* getOffset(char*str)
1842 if(!strncmp(str, "<plus>", 6))
1844 if(!strncmp(str, "<minus>", 7))
1846 syntaxerror("internal error (347)");
1849 int getSign(char*str)
1851 if(!strncmp(str, "<plus>", 6))
1853 if(!strncmp(str, "<minus>", 7))
1855 syntaxerror("internal error (348)");
1858 static dictionary_t points;
1859 static mem_t mpoints;
1860 int points_initialized = 0;
1862 SPOINT getPoint(SRECT r, char*name)
1865 if(!strcmp(name, "center")) {
1867 p.x = (r.xmin + r.xmax)/2;
1868 p.y = (r.ymin + r.ymax)/2;
1872 if(points_initialized)
1873 l = (int)dictionary_lookup(&points, name);
1875 syntaxerror("Invalid point: \"%s\".", name);
1878 return *(SPOINT*)&mpoints.buffer[l];
1880 static int c_gradient(map_t*args)
1882 char*name = lu(args, "name");
1883 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1884 int rotate = parseInt(lu(args, "rotate"));
1888 syntaxerror("colon (:) expected");
1890 s_gradient(name, text, radial,rotate);
1893 static int c_point(map_t*args)
1895 char*name = lu(args, "name");
1899 if(!points_initialized) {
1900 dictionary_init(&points);
1902 points_initialized = 1;
1904 p.x = parseTwip(lu(args, "x"));
1905 p.y = parseTwip(lu(args, "y"));
1906 pos = mem_put(&mpoints, &p, sizeof(p));
1907 string_set(&s1, name);
1909 dictionary_put(&points, s1, (void*)pos);
1912 static int c_play(map_t*args)
1914 char*name = lu(args, "name");
1915 char*loop = lu(args, "loop");
1916 char*nomultiple = lu(args, "nomultiple");
1918 if(!strcmp(nomultiple, "nomultiple"))
1921 nm = parseInt(nomultiple);
1923 if(s_playsound(name, parseInt(loop), nm, 0)) {
1925 } else if(s_swf3action(name, "play")) {
1931 static int c_stop(map_t*args)
1933 char*name = map_lookup(args, "name");
1935 if(s_playsound(name, 0,0,1)) {
1937 } else if(s_swf3action(name, "stop")) {
1940 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
1944 static int c_nextframe(map_t*args)
1946 char*name = lu(args, "name");
1948 if(s_swf3action(name, "nextframe")) {
1951 syntaxerror("I don't know anything about movie \"%s\"", name);
1955 static int c_previousframe(map_t*args)
1957 char*name = lu(args, "name");
1959 if(s_swf3action(name, "previousframe")) {
1962 syntaxerror("I don't know anything about movie \"%s\"", name);
1966 static int c_placement(map_t*args, int type)
1968 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1971 char* luminancestr = lu(args, "luminance");
1972 char* scalestr = lu(args, "scale");
1973 char* scalexstr = lu(args, "scalex");
1974 char* scaleystr = lu(args, "scaley");
1975 char* rotatestr = lu(args, "rotate");
1976 char* shearstr = lu(args, "shear");
1977 char* xstr="", *pivotstr="";
1978 char* ystr="", *anglestr="";
1979 char*above = lu(args, "above"); /*FIXME*/
1980 char*below = lu(args, "below");
1981 char* rstr = lu(args, "red");
1982 char* gstr = lu(args, "green");
1983 char* bstr = lu(args, "blue");
1984 char* astr = lu(args, "alpha");
1985 char* pinstr = lu(args, "pin");
1986 char* as = map_lookup(args, "as");
1994 if(type==9) { // (?) .rotate or .arcchange
1995 pivotstr = lu(args, "pivot");
1996 anglestr = lu(args, "angle");
1998 xstr = lu(args, "x");
1999 ystr = lu(args, "y");
2002 luminance = parseMulAdd(luminancestr);
2005 luminance.mul = 256;
2009 if(scalexstr[0]||scaleystr[0])
2010 syntaxerror("scalex/scaley and scale cannot both be set");
2011 scalexstr = scaleystr = scalestr;
2014 if(type == 0 || type == 4) {
2016 character = lu(args, "character");
2017 parameters_clear(&p);
2018 } else if (type == 5) {
2019 character = lu(args, "name");
2020 parameters_clear(&p);
2023 p = s_getParameters(instance);
2028 if(isRelative(xstr)) {
2029 if(type == 0 || type == 4)
2030 syntaxerror("relative x values not allowed for initial put or startclip");
2031 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2033 p.x = parseTwip(xstr);
2037 if(isRelative(ystr)) {
2038 if(type == 0 || type == 4)
2039 syntaxerror("relative y values not allowed for initial put or startclip");
2040 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2042 p.y = parseTwip(ystr);
2046 /* scale, scalex, scaley */
2048 oldbbox = s_getCharBBox(character);
2050 oldbbox = s_getInstanceBBox(instance);
2052 oldwidth = oldbbox.xmax - oldbbox.xmin;
2053 oldheight = oldbbox.ymax - oldbbox.ymin;
2055 if(oldwidth==0) p.scalex = 1.0;
2058 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2062 if(oldheight==0) p.scaley = 1.0;
2065 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2071 if(isRelative(rotatestr)) {
2072 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2074 p.rotate = parseFloat(rotatestr);
2080 if(isRelative(shearstr)) {
2081 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2083 p.shear = parseFloat(shearstr);
2088 if(isPoint(pivotstr))
2089 p.pivot = parsePoint(pivotstr);
2091 p.pivot = getPoint(oldbbox, pivotstr);
2095 p.pin = parsePoint(pinstr);
2097 p.pin = getPoint(oldbbox, pinstr);
2100 /* color transform */
2102 if(rstr[0] || luminancestr[0]) {
2105 r = parseMulAdd(rstr);
2107 r.add = p.cxform.r0;
2108 r.mul = p.cxform.r1;
2110 r = mergeMulAdd(r, luminance);
2111 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2113 if(gstr[0] || luminancestr[0]) {
2116 g = parseMulAdd(gstr);
2118 g.add = p.cxform.g0;
2119 g.mul = p.cxform.g1;
2121 g = mergeMulAdd(g, luminance);
2122 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2124 if(bstr[0] || luminancestr[0]) {
2127 b = parseMulAdd(bstr);
2129 b.add = p.cxform.b0;
2130 b.mul = p.cxform.b1;
2132 b = mergeMulAdd(b, luminance);
2133 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2136 MULADD a = parseMulAdd(astr);
2137 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2141 s_put(instance, character, p);
2143 s_change(instance, p);
2145 s_qchange(instance, p);
2147 s_jump(instance, p);
2149 s_startclip(instance, character, p);
2150 else if(type == 5) {
2152 s_buttonput(character, as, p);
2154 s_buttonput(character, "shape", p);
2159 static int c_put(map_t*args)
2161 c_placement(args, 0);
2164 static int c_change(map_t*args)
2166 c_placement(args, 1);
2169 static int c_qchange(map_t*args)
2171 c_placement(args, 2);
2174 static int c_arcchange(map_t*args)
2176 c_placement(args, 2);
2179 static int c_jump(map_t*args)
2181 c_placement(args, 3);
2184 static int c_startclip(map_t*args)
2186 c_placement(args, 4);
2189 static int c_show(map_t*args)
2191 c_placement(args, 5);
2194 static int c_del(map_t*args)
2196 char*instance = lu(args, "name");
2197 s_delinstance(instance);
2200 static int c_end(map_t*args)
2205 static int c_sprite(map_t*args)
2207 char* name = lu(args, "name");
2211 static int c_frame(map_t*args)
2213 char*framestr = lu(args, "n");
2214 char*cutstr = lu(args, "cut");
2215 char*name = lu(args, "name");
2218 if(strcmp(cutstr, "no"))
2220 if(isRelative(framestr)) {
2221 frame = s_getframe();
2222 if(getSign(framestr)<0)
2223 syntaxerror("relative frame expressions must be positive");
2224 frame += parseInt(getOffset(framestr));
2227 frame = parseInt(framestr);
2228 if(s_getframe() >= frame
2229 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2230 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2232 s_frame(frame, cut, name);
2235 static int c_primitive(map_t*args)
2237 char*name = lu(args, "name");
2238 char*command = lu(args, "commandname");
2239 int width=0, height=0, r=0;
2240 int linewidth = parseTwip(lu(args, "line"));
2241 char*colorstr = lu(args, "color");
2242 RGBA color = parseColor(colorstr);
2243 char*fillstr = lu(args, "fill");
2250 if(!strcmp(command, "circle"))
2252 else if(!strcmp(command, "filled"))
2256 width = parseTwip(lu(args, "width"));
2257 height = parseTwip(lu(args, "height"));
2258 } else if (type==1) {
2259 r = parseTwip(lu(args, "r"));
2260 } else if (type==2) {
2261 outline = lu(args, "outline");
2264 if(!strcmp(fillstr, "fill"))
2266 if(!strcmp(fillstr, "none"))
2268 if(width<0 || height<0 || linewidth<0 || r<0)
2269 syntaxerror("values width, height, line, r must be positive");
2271 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2272 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2273 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2277 static int c_textshape(map_t*args)
2279 char*name = lu(args, "name");
2280 char*text = lu(args, "text");
2281 char*font = lu(args, "font");
2282 float size = parsePercent(lu(args, "size"));
2284 s_textshape(name, font, size, text);
2288 static int c_swf(map_t*args)
2290 char*name = lu(args, "name");
2291 char*filename = lu(args, "filename");
2292 char*command = lu(args, "commandname");
2293 if(!strcmp(command, "shape"))
2294 warning("Please use .swf instead of .shape");
2295 s_includeswf(name, filename);
2299 static int c_font(map_t*args)
2301 char*name = lu(args, "name");
2302 char*filename = lu(args, "filename");
2303 s_font(name, filename);
2307 static int c_sound(map_t*args)
2309 char*name = lu(args, "name");
2310 char*filename = lu(args, "filename");
2311 s_sound(name, filename);
2315 static int c_text(map_t*args)
2317 char*name = lu(args, "name");
2318 char*text = lu(args, "text");
2319 char*font = lu(args, "font");
2320 float size = parsePercent(lu(args, "size"));
2321 RGBA color = parseColor(lu(args, "color"));
2322 s_text(name, font, text, (int)(size*100), color);
2326 static int c_soundtrack(map_t*args)
2331 static int c_quicktime(map_t*args)
2333 char*name = lu(args, "name");
2334 char*url = lu(args, "url");
2335 s_quicktime(name, url);
2339 static int c_image(map_t*args)
2341 char*command = lu(args, "commandname");
2342 char*name = lu(args, "name");
2343 char*filename = lu(args, "filename");
2344 if(!strcmp(command,"jpeg")) {
2345 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2346 s_image(name, "jpeg", filename, quality);
2348 s_image(name, "png", filename, 0);
2353 static int c_outline(map_t*args)
2355 char*name = lu(args, "name");
2356 char*format = lu(args, "format");
2360 syntaxerror("colon (:) expected");
2362 s_outline(name, format, text);
2366 int fakechar(map_t*args)
2368 char*name = lu(args, "name");
2369 s_box(name, 0, 0, black, 20, 0);
2373 static int c_egon(map_t*args) {return fakechar(args);}
2374 static int c_button(map_t*args) {
2375 char*name = lu(args, "name");
2379 static int current_button_flags = 0;
2380 static int c_on_press(map_t*args)
2382 char*position = lu(args, "position");
2384 if(!strcmp(position, "inside")) {
2385 current_button_flags |= BC_OVERUP_OVERDOWN;
2386 } else if(!strcmp(position, "outside")) {
2387 //current_button_flags |= BC_IDLE_OUTDOWN;
2388 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2389 } else if(!strcmp(position, "anywhere")) {
2390 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2393 if(type == RAWDATA) {
2395 s_buttonaction(current_button_flags, action);
2396 current_button_flags = 0;
2402 static int c_on_release(map_t*args)
2404 char*position = lu(args, "position");
2406 if(!strcmp(position, "inside")) {
2407 current_button_flags |= BC_OVERDOWN_OVERUP;
2408 } else if(!strcmp(position, "outside")) {
2409 current_button_flags |= BC_OUTDOWN_IDLE;
2410 } else if(!strcmp(position, "anywhere")) {
2411 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2414 if(type == RAWDATA) {
2416 s_buttonaction(current_button_flags, action);
2417 current_button_flags = 0;
2423 static int c_on_move_in(map_t*args)
2425 char*position = lu(args, "state");
2427 if(!strcmp(position, "pressed")) {
2428 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2429 } else if(!strcmp(position, "not_pressed")) {
2430 current_button_flags |= BC_IDLE_OVERUP;
2431 } else if(!strcmp(position, "any")) {
2432 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2435 if(type == RAWDATA) {
2437 s_buttonaction(current_button_flags, action);
2438 current_button_flags = 0;
2444 static int c_on_move_out(map_t*args)
2446 char*position = lu(args, "state");
2448 if(!strcmp(position, "pressed")) {
2449 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2450 } else if(!strcmp(position, "not_pressed")) {
2451 current_button_flags |= BC_OVERUP_IDLE;
2452 } else if(!strcmp(position, "any")) {
2453 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2456 if(type == RAWDATA) {
2458 s_buttonaction(current_button_flags, action);
2459 current_button_flags = 0;
2465 static int c_on_key(map_t*args)
2467 char*key = lu(args, "key");
2469 if(strlen(key)==1) {
2472 current_button_flags |= 0x4000 + (key[0]*0x200);
2474 syntaxerror("invalid character: %c"+key[0]);
2479 <ctrl-x> = 0x200*(x-'a')
2483 syntaxerror("invalid key: %s",key);
2486 if(type == RAWDATA) {
2488 s_buttonaction(current_button_flags, action);
2489 current_button_flags = 0;
2496 static int c_edittext(map_t*args)
2498 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
2499 char*name = lu(args, "name");
2500 char*font = lu(args, "font");
2501 int size = (int)(1024*parsePercent(lu(args, "size")));
2502 int width = parseTwip(lu(args, "width"));
2503 int height = parseTwip(lu(args, "height"));
2504 char*text = lu(args, "text");
2505 RGBA color = parseColor(lu(args, "color"));
2506 int maxlength = parseInt(lu(args, "maxlength"));
2507 char*variable = lu(args, "variable");
2508 char*passwordstr = lu(args, "password");
2509 char*wordwrapstr = lu(args, "wordwrap");
2510 char*multilinestr = lu(args, "multiline");
2511 char*htmlstr = lu(args, "html");
2512 char*noselectstr = lu(args, "noselect");
2513 char*readonlystr = lu(args, "readonly");
2514 char*borderstr = lu(args, "border");
2517 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2518 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2519 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2520 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2521 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2522 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2523 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2525 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags);
2529 static int c_morphshape(map_t*args) {return fakechar(args);}
2530 static int c_movie(map_t*args) {return fakechar(args);}
2532 static int c_texture(map_t*args) {return 0;}
2534 static int c_action(map_t*args)
2537 if(type != RAWDATA) {
2538 syntaxerror("colon (:) expected");
2548 command_func_t* func;
2551 {{"flash", c_flash, "bbox=autocrop background=black version=5 fps=50 name=!default! @compress=default"},
2552 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2553 // "import" type stuff
2554 {"swf", c_swf, "name filename"},
2555 {"shape", c_swf, "name filename"},
2556 {"jpeg", c_image, "name filename quality=80%"},
2557 {"png", c_image, "name filename"},
2558 {"movie", c_movie, "name filename"},
2559 {"sound", c_sound, "name filename"},
2560 {"font", c_font, "name filename"},
2561 {"soundtrack", c_soundtrack, "filename"},
2562 {"quicktime", c_quicktime, "url"},
2564 // generators of primitives
2566 {"point", c_point, "name x=0 y=0"},
2567 {"gradient", c_gradient, "name @radial=0 rotate=0"},
2568 {"outline", c_outline, "name format=simple"},
2569 {"textshape", c_textshape, "name font size=100% text"},
2571 // character generators
2572 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2573 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2574 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2576 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2577 {"text", c_text, "name text font size=100% color=white"},
2578 {"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"},
2579 {"morphshape", c_morphshape, "name start end"},
2580 {"button", c_button, "name"},
2581 {"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="},
2582 {"on_press", c_on_press, "position=inside"},
2583 {"on_release", c_on_release, "position=anywhere"},
2584 {"on_move_in", c_on_move_in, "state=not_pressed"},
2585 {"on_move_out", c_on_move_out, "state=not_pressed"},
2586 {"on_key", c_on_key, "key=any"},
2589 {"play", c_play, "name loop=0 @nomultiple=0"},
2590 {"stop", c_stop, "name= "},
2591 {"nextframe", c_nextframe, "name"},
2592 {"previousframe", c_previousframe, "name"},
2594 // object placement tags
2595 {"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="},
2596 {"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="},
2597 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2598 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2599 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2600 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2601 {"del", c_del, "name"},
2602 // virtual object placement
2603 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2605 // commands which start a block
2606 //startclip (see above)
2607 {"sprite", c_sprite, "name"},
2608 {"action", c_action, ""},
2614 static map_t parseArguments(char*command, char*pattern)
2630 string_set(&t1, "commandname");
2631 string_set(&t2, command);
2632 map_put(&result, t1, t2);
2634 if(!pattern || !*pattern)
2641 if(!strncmp("<i> ", x, 3)) {
2643 if(type == COMMAND || type == RAWDATA) {
2645 syntaxerror("character name expected");
2647 name[pos].str = "instance";
2649 value[pos].str = text;
2650 value[pos].len = strlen(text);
2654 if(type == ASSIGNMENT)
2657 name[pos].str = "character";
2659 value[pos].str = text;
2660 value[pos].len = strlen(text);
2668 isboolean[pos] = (x[0] =='@');
2681 name[pos].len = d-x;
2686 name[pos].len = e-x;
2687 value[pos].str = e+1;
2688 value[pos].len = d-e-1;
2696 /* for(t=0;t<len;t++) {
2697 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2698 isboolean[t]?"(boolean)":"");
2703 if(type == RAWDATA || type == COMMAND) {
2708 // first, search for boolean arguments
2709 for(pos=0;pos<len;pos++)
2711 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2713 if(type == ASSIGNMENT)
2715 value[pos].str = text;
2716 value[pos].len = strlen(text);
2717 /*printf("setting boolean parameter %s (to %s)\n",
2718 strdup_n(name[pos], namelen[pos]),
2719 strdup_n(value[pos], valuelen[pos]));*/
2724 // second, search for normal arguments
2726 for(pos=0;pos<len;pos++)
2728 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2729 (type != ASSIGNMENT && !set[pos])) {
2731 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2733 if(type == ASSIGNMENT)
2736 value[pos].str = text;
2737 value[pos].len = strlen(text);
2739 printf("setting parameter %s (to %s)\n",
2740 strdup_n(name[pos].str, name[pos].len),
2741 strdup_n(value[pos].str, value[pos].len));
2747 syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
2751 for(t=0;t<len;t++) {
2752 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2755 for(t=0;t<len;t++) {
2756 if(value[t].str && value[t].str[0] == '*') {
2757 //relative default- take value from some other parameter
2759 for(s=0;s<len;s++) {
2760 if(value[s].len == value[t].len-1 &&
2761 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2762 value[t].str = value[s].str;
2765 if(value[t].str == 0) {
2767 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2771 /* ok, now construct the dictionary from the parameters */
2775 map_put(&result, name[t], value[t]);
2779 static void parseArgumentsForCommand(char*command)
2784 msg("<verbose> parse Command: %s (line %d)", command, line);
2786 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2787 if(!strcmp(arguments[t].command, command)) {
2789 /* ugly hack- will be removed soon (once documentation and .sc generating
2790 utilities have been changed) */
2791 if(!strcmp(command, "swf") && !stackpos) {
2792 warning("Please use .flash instead of .swf- this will be mandatory soon");
2797 args = parseArguments(command, arguments[t].arguments);
2803 syntaxerror("command %s not known", command);
2805 // catch missing .flash directives at the beginning of a file
2806 if(strcmp(command, "flash") && !stackpos)
2808 syntaxerror("No movie defined- use .flash first");
2812 printf(".%s\n", command);fflush(stdout);
2813 map_dump(&args, stdout, "\t");fflush(stdout);
2816 (*arguments[nr].func)(&args);
2818 /*if(!strcmp(command, "button") ||
2819 !strcmp(command, "action")) {
2822 if(type == COMMAND) {
2823 if(!strcmp(text, "end"))
2837 int main (int argc,char ** argv)
2840 processargs(argc, argv);
2841 initLog(0,-1,0,0,-1,verbose);
2844 args_callback_usage(argv[0]);
2848 file = generateTokens(filename);
2850 printf("parser returned error.\n");
2856 while(!noMoreTokens()) {
2859 syntaxerror("command expected");
2860 parseArgumentsForCommand(text);