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");
705 void s_frame(int nr, int cut, char*name)
710 /* // enabling the following code will make the frame
711 handling much more intuitive, but also break old
715 syntaxerror("Frame number need to be at least 1");
718 for(t=currentframe;t<nr;t++) {
719 tag = swf_InsertTag(tag, ST_SHOWFRAME);
720 if(t==nr-1 && name && *name) {
721 tag = swf_InsertTag(tag, ST_FRAMELABEL);
722 swf_SetString(tag, name);
725 if(nr == 0 && currentframe == 0 && name) {
726 tag = swf_InsertTag(tag, ST_FRAMELABEL);
727 swf_SetString(tag, name);
732 syntaxerror("Can't cut, frame empty");
734 stack[stackpos].cut = tag;
740 int parseColor2(char*str, RGBA*color);
742 int addFillStyle(SHAPE*s, SRECT*r, char*texture)
747 if(texture[0] == '#') {
748 parseColor2(texture, &color);
749 return swf_ShapeAddSolidFillStyle(s, &color);
750 } else if((image = dictionary_lookup(&images, texture))) {
752 swf_GetMatrix(0, &m);
753 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
754 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
757 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
758 } /*else if ((texture = dictionary_lookup(&textures, texture))) {
759 } */ else if ((gradient = dictionary_lookup(&gradients, texture))) {
763 swf_GetMatrix(0, &rot);
764 ccos = cos(-gradient->rotate*2*3.14159265358979/360);
765 csin = sin(-gradient->rotate*2*3.14159265358979/360);
767 rot.r1 = -csin*65536;
770 r2 = swf_TurnRect(*r, &rot);
771 swf_GetMatrix(0, &m);
772 m.sx = (r2.xmax - r2.xmin)*2*ccos;
773 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
774 m.r0 = (r2.ymax - r2.ymin)*2*csin;
775 m.sy = (r2.ymax - r2.ymin)*2*ccos;
776 m.tx = r->xmin + (r->xmax - r->xmin)/2;
777 m.ty = r->ymin + (r->ymax - r->ymin)/2;
778 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
779 } else if (parseColor2(texture, &color)) {
780 return swf_ShapeAddSolidFillStyle(s, &color);
782 syntaxerror("not a color/fillstyle: %s", texture);
787 RGBA black={r:0,g:0,b:0,a:0};
788 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
797 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
799 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
802 fs1 = addFillStyle(s, &r2, texture);
805 r.xmin = r2.xmin-linewidth-linewidth/2;
806 r.ymin = r2.ymin-linewidth-linewidth/2;
807 r.xmax = r2.xmax+linewidth+linewidth/2;
808 r.ymax = r2.ymax+linewidth+linewidth/2;
810 swf_SetShapeHeader(tag,s);
811 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
812 swf_ShapeSetLine(tag,s,width,0);
813 swf_ShapeSetLine(tag,s,0,height);
814 swf_ShapeSetLine(tag,s,-width,0);
815 swf_ShapeSetLine(tag,s,0,-height);
816 swf_ShapeSetEnd(tag);
819 s_addcharacter(name, id, tag, r);
823 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
829 outline = dictionary_lookup(&outlines, outlinename);
831 syntaxerror("outline %s not defined", outlinename);
835 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
837 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
839 fs1 = addFillStyle(s, &r2, texture);
841 syntaxerror("non filled outlines not yet supported- please supply a fill=<color/texture> argument");
843 rect.xmin = r2.xmin-linewidth-linewidth/2;
844 rect.ymin = r2.ymin-linewidth-linewidth/2;
845 rect.xmax = r2.xmax+linewidth+linewidth/2;
846 rect.ymax = r2.ymax+linewidth+linewidth/2;
848 swf_SetRect(tag,&rect);
849 swf_SetShapeStyles(tag, s);
850 swf_SetShapeBits(tag, outline->shape); //does not count bits!
851 swf_SetBlock(tag, outline->shape->data, (outline->shape->bitlen+7)/8);
854 s_addcharacter(name, id, tag, rect);
858 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
863 r2.xmin = r2.ymin = 0;
867 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
869 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
871 fs1 = addFillStyle(s, &r2, texture);
873 rect.xmin = r2.xmin-linewidth-linewidth/2;
874 rect.ymin = r2.ymin-linewidth-linewidth/2;
875 rect.xmax = r2.xmax+linewidth+linewidth/2;
876 rect.ymax = r2.ymax+linewidth+linewidth/2;
878 swf_SetRect(tag,&rect);
879 swf_SetShapeHeader(tag,s);
880 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
881 swf_ShapeSetCircle(tag, s, r,r,r,r);
882 swf_ShapeSetEnd(tag);
885 s_addcharacter(name, id, tag, rect);
889 void s_textshape(char*name, char*fontname, float size, char*_text)
892 U8*text = (U8*)_text;
896 font = dictionary_lookup(&fonts, fontname);
898 syntaxerror("font \"%s\" not known!", fontname);
900 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
901 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
902 s_box(name, 0, 0, black, 20, 0);
905 g = font->ascii2glyph[text[0]];
907 outline = malloc(sizeof(outline_t));
908 memset(outline, 0, sizeof(outline_t));
909 outline->shape = font->glyph[g].shape;
910 outline->bbox = font->layout->bounds[g];
914 swf_Shape11DrawerInit(&draw, 0);
915 swf_DrawText(&draw, font, (int)(size*100), _text);
917 outline->shape = swf_ShapeDrawerToShape(&draw);
918 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
922 if(dictionary_lookup(&outlines, name))
923 syntaxerror("outline %s defined twice", name);
924 dictionary_put2(&outlines, name, outline);
927 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
932 font = dictionary_lookup(&fonts, fontname);
934 syntaxerror("font \"%s\" not known!", fontname);
936 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
938 if(!font->numchars) {
939 s_box(name, 0, 0, black, 20, 0);
942 r = swf_SetDefineText(tag, font, &color, text, size);
944 s_addcharacter(name, id, tag, r);
948 void s_quicktime(char*name, char*url)
953 memset(&r, 0, sizeof(r));
955 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
957 swf_SetString(tag, url);
959 s_addcharacter(name, id, tag, r);
963 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags)
966 EditTextLayout layout;
969 font = dictionary_lookup(&fonts, fontname);
971 syntaxerror("font \"%s\" not known!", fontname);
972 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
975 layout.leftmargin = 0;
976 layout.rightmargin = 0;
983 swf_SetEditText(tag, flags|ET_USEOUTLINES, r, text, color, maxlength, font->id, size, &layout, variable);
985 s_addcharacter(name, id, tag, r);
989 /* type: either "jpeg" or "png"
991 void s_image(char*name, char*type, char*filename, int quality)
993 /* an image is actually two folded: 1st bitmap, 2nd character.
994 Both of them can be used separately */
996 /* step 1: the bitmap */
1001 warning("image type \"png\" not supported yet!");
1002 s_box(name, 0, 0, black, 20, 0);
1006 #ifndef HAVE_LIBJPEG
1007 warning("no jpeg support compiled in");
1008 s_box(name, 0, 0, black, 20, 0);
1011 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1012 swf_SetU16(tag, imageID);
1014 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1015 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1018 swf_GetJPEGSize(filename, &width, &height);
1025 s_addimage(name, id, tag, r);
1030 /* step 2: the character */
1031 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1032 swf_SetU16(tag, id);
1033 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1035 s_addcharacter(name, id, tag, r);
1039 void dumpSWF(SWF*swf)
1041 TAG* tag = swf->firstTag;
1042 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1044 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1047 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1050 void s_font(char*name, char*filename)
1053 font = swf_LoadFont(filename);
1056 warning("Couldn't open font file \"%s\"", filename);
1057 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1058 memset(font, 0, sizeof(SWFFONT));
1059 dictionary_put2(&fonts, name, font);
1065 /* fix the layout. Only needed for old fonts */
1067 for(t=0;t<font->numchars;t++) {
1068 font->glyph[t].advance = 0;
1071 swf_FontCreateLayout(font);
1073 /* just in case this thing is used in .edittext later on */
1074 swf_FontPrepareForEditText(font);
1077 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1078 swf_FontSetDefine2(tag, font);
1081 if(dictionary_lookup(&fonts, name))
1082 syntaxerror("font %s defined twice", name);
1083 dictionary_put2(&fonts, name, font);
1088 typedef struct _sound_t
1094 void s_sound(char*name, char*filename)
1096 struct WAV wav, wav2;
1101 if(!readWAV(filename, &wav)) {
1102 warning("Couldn't read wav file \"%s\"", filename);
1106 convertWAV2mono(&wav, &wav2, 44100);
1107 samples = (U16*)wav2.data;
1108 numsamples = wav2.size/2;
1112 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1113 swf_SetU16(tag, id); //id
1114 swf_SetSoundDefine(tag, samples, numsamples);
1116 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1120 if(dictionary_lookup(&sounds, name))
1121 syntaxerror("sound %s defined twice", name);
1122 dictionary_put2(&sounds, name, sound);
1130 static char* gradient_getToken(const char**p)
1134 while(**p && strchr(" \t\n\r", **p)) {
1138 while(**p && !strchr(" \t\n\r", **p)) {
1141 result = malloc((*p)-start+1);
1142 memcpy(result,start,(*p)-start+1);
1143 result[(*p)-start] = 0;
1147 float parsePercent(char*str);
1148 RGBA parseColor(char*str);
1150 GRADIENT parseGradient(const char*str)
1153 const char* p = str;
1154 memset(&gradient, 0, sizeof(GRADIENT));
1156 char*posstr,*colorstr;
1159 posstr = gradient_getToken(&p);
1162 pos = parsePercent(posstr);
1163 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1164 colorstr = gradient_getToken(&p);
1165 color = parseColor(colorstr);
1166 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1167 warning("gradient record too big- max size is 8, rest ignored");
1170 gradient.ratios[gradient.num] = (int)(pos*255.0);
1171 gradient.rgba[gradient.num] = color;
1179 void s_gradient(char*name, const char*text, int radial, int rotate)
1181 gradient_t* gradient;
1182 gradient = malloc(sizeof(gradient_t));
1183 memset(gradient, 0, sizeof(gradient_t));
1184 gradient->gradient = parseGradient(text);
1185 gradient->radial = radial;
1186 gradient->rotate = rotate;
1188 if(dictionary_lookup(&gradients, name))
1189 syntaxerror("gradient %s defined twice", name);
1190 dictionary_put2(&gradients, name, gradient);
1193 void s_action(const char*text)
1196 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1198 syntaxerror("Couldn't compile ActionScript");
1201 tag = swf_InsertTag(tag, ST_DOACTION);
1203 swf_ActionSet(tag, a);
1208 int s_swf3action(char*name, char*action)
1211 instance_t* object = 0;
1213 dictionary_lookup(&instances, name);
1214 if(!object && name && *name) {
1215 /* we have a name, but couldn't find it. Abort. */
1218 a = action_SetTarget(0, name);
1219 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1220 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1221 else if(!strcmp(action, "stop")) a = action_Stop(a);
1222 else if(!strcmp(action, "play")) a = action_Play(a);
1223 a = action_SetTarget(a, "");
1226 tag = swf_InsertTag(tag, ST_DOACTION);
1227 swf_ActionSet(tag, a);
1232 void s_outline(char*name, char*format, char*source)
1241 swf_Shape11DrawerInit(&draw, 0);
1242 draw_string(&draw, source);
1244 shape = swf_ShapeDrawerToShape(&draw);
1245 //shape2 = swf_ShapeToShape2(shape);
1246 //bounds = swf_GetShapeBoundingBox(shape2);
1247 //swf_Shape2Free(shape2);
1248 bounds = swf_ShapeDrawerGetBBox(&draw);
1249 draw.dealloc(&draw);
1251 outline = (outline_t*)malloc(sizeof(outline_t));
1252 memset(outline, 0, sizeof(outline_t));
1253 outline->shape = shape;
1254 outline->bbox = bounds;
1256 if(dictionary_lookup(&outlines, name))
1257 syntaxerror("outline %s defined twice", name);
1258 dictionary_put2(&outlines, name, outline);
1261 int s_playsound(char*name, int loops, int nomultiple, int stop)
1266 sound = dictionary_lookup(&sounds, name);
1271 tag = swf_InsertTag(tag, ST_STARTSOUND);
1272 swf_SetU16(tag, sound->id); //id
1273 memset(&info, 0, sizeof(info));
1276 info.nomultiple = nomultiple;
1277 swf_SetSoundInfo(tag, &info);
1281 void s_includeswf(char*name, char*filename)
1289 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1290 f = open(filename,O_RDONLY|O_BINARY);
1292 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1293 s_box(name, 0, 0, black, 20, 0);
1296 if (swf_ReadSWF(f,&swf)<0) {
1297 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1298 s_box(name, 0, 0, black, 20, 0);
1303 /* FIXME: The following sets the bounding Box for the character.
1304 It is wrong for two reasons:
1305 a) It may be too small (in case objects in the movie clip at the borders)
1306 b) it may be too big (because the poor movie never got autocropped)
1310 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1311 swf_SetU16(tag, id);
1314 swf_Relocate(&swf, idmap);
1316 ftag = swf.firstTag;
1320 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1321 if(cutout[t] == ftag->id) {
1325 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1327 if(ftag->id == ST_END)
1331 /* We simply dump all tags right after the sprite
1332 header, relying on the fact that swf_OptimizeTagOrder() will
1333 sort things out for us later.
1334 We also rely on the fact that the imported SWF is well-formed.
1336 tag = swf_InsertTag(tag, ftag->id);
1337 swf_SetBlock(tag, ftag->data, ftag->len);
1341 syntaxerror("Included file %s contains errors", filename);
1342 tag = swf_InsertTag(tag, ST_END);
1346 s_addcharacter(name, id, tag, r);
1349 SRECT s_getCharBBox(char*name)
1351 character_t* c = dictionary_lookup(&characters, name);
1352 if(!c) syntaxerror("character '%s' unknown(2)", name);
1355 SRECT s_getInstanceBBox(char*name)
1357 instance_t * i = dictionary_lookup(&instances, name);
1359 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1361 if(!c) syntaxerror("internal error(5)");
1364 parameters_t s_getParameters(char*name)
1366 instance_t * i = dictionary_lookup(&instances, name);
1367 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1368 return i->parameters;
1370 void s_startclip(char*instance, char*character, parameters_t p)
1372 character_t* c = dictionary_lookup(&characters, character);
1376 syntaxerror("character %s not known", character);
1378 i = s_addinstance(instance, c, currentdepth);
1380 m = s_instancepos(i->character->size, &p);
1382 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1383 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1384 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1386 i->lastFrame= currentframe;
1388 stack[stackpos].tag = tag;
1389 stack[stackpos].type = 2;
1398 swf_SetTagPos(stack[stackpos].tag, 0);
1399 swf_GetPlaceObject(stack[stackpos].tag, &p);
1400 p.clipdepth = currentdepth;
1402 swf_ClearTag(stack[stackpos].tag);
1403 swf_SetPlaceObject(stack[stackpos].tag, &p);
1407 void s_put(char*instance, char*character, parameters_t p)
1409 character_t* c = dictionary_lookup(&characters, character);
1413 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1416 i = s_addinstance(instance, c, currentdepth);
1418 m = s_instancepos(i->character->size, &p);
1420 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1421 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1423 i->lastFrame = currentframe;
1427 void s_jump(char*instance, parameters_t p)
1429 instance_t* i = dictionary_lookup(&instances, instance);
1432 syntaxerror("instance %s not known", instance);
1436 m = s_instancepos(i->character->size, &p);
1438 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1439 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1441 i->lastFrame = currentframe;
1444 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1448 if(num==0 || num==1)
1450 ratio = (float)pos/(float)num;
1452 p.x = (p2->x-p1->x)*ratio + p1->x;
1453 p.y = (p2->y-p1->y)*ratio + p1->y;
1454 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1455 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1456 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1457 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1459 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1460 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1461 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1462 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1464 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1465 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1466 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1467 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1469 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1470 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1471 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1472 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1476 void s_change(char*instance, parameters_t p2)
1478 instance_t* i = dictionary_lookup(&instances, instance);
1482 int frame, allframes;
1484 syntaxerror("instance %s not known", instance);
1488 allframes = currentframe - i->lastFrame - 1;
1490 warning(".change ignored. can only .put/.change an object once per frame.");
1494 m = s_instancepos(i->character->size, &p2);
1495 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1496 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1499 /* o.k., we got the start and end point set. Now iterate though all the
1500 tags in between, inserting object changes after each new frame */
1503 if(!t) syntaxerror("internal error(6)");
1505 while(frame < allframes) {
1506 if(t->id == ST_SHOWFRAME) {
1511 p = s_interpolate(&p1, &p2, frame, allframes);
1512 m = s_instancepos(i->character->size, &p); //needed?
1513 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1514 i->lastFrame = currentframe;
1515 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1517 if(frame == allframes)
1522 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1526 void s_delinstance(char*instance)
1528 instance_t* i = dictionary_lookup(&instances, instance);
1530 syntaxerror("instance %s not known", instance);
1532 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1533 swf_SetU16(tag, i->depth);
1534 dictionary_del(&instances, instance);
1537 void s_qchange(char*instance, parameters_t p)
1544 syntaxerror(".end unexpected");
1545 if(stack[stackpos-1].type == 0)
1547 else if(stack[stackpos-1].type == 1)
1549 else if(stack[stackpos-1].type == 2)
1551 else if(stack[stackpos-1].type == 3)
1553 else syntaxerror("internal error 1");
1556 // ------------------------------------------------------------------------
1558 typedef int command_func_t(map_t*args);
1560 SRECT parseBox(char*str)
1563 float xmin, xmax, ymin, ymax;
1564 char*x = strchr(str, 'x');
1566 if(!strcmp(str, "autocrop")) {
1567 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1571 d1 = strchr(x+1, ':');
1573 d2 = strchr(d1+1, ':');
1575 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1579 else if(d1 && !d2) {
1580 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1586 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1591 r.xmin = (SCOORD)(xmin*20);
1592 r.ymin = (SCOORD)(ymin*20);
1593 r.xmax = (SCOORD)(xmax*20);
1594 r.ymax = (SCOORD)(ymax*20);
1597 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1600 float parseFloat(char*str)
1604 int parseInt(char*str)
1609 if(str[0]=='+' || str[0]=='-')
1613 if(str[t]<'0' || str[t]>'9')
1614 syntaxerror("Not an Integer: \"%s\"", str);
1617 int parseTwip(char*str)
1621 if(str[0]=='+' || str[0]=='-') {
1626 dot = strchr(str, '.');
1630 return sign*parseInt(str)*20;
1632 int l=strlen(++dot);
1634 for(s=str;s<dot-1;s++)
1635 if(*s<'0' || *s>'9')
1636 syntaxerror("Not a coordinate: \"%s\"", str);
1638 if(*s<'0' || *s>'9')
1639 syntaxerror("Not a coordinate: \"%s\"", str);
1641 if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) {
1642 warning("precision loss: %s converted to twip", str);
1647 return sign*atoi(str)*20;
1649 return sign*atoi(str)*20+atoi(dot)*2;
1651 return sign*atoi(str)*20+atoi(dot)/5;
1656 int isPoint(char*str)
1658 if(strchr(str, '('))
1664 SPOINT parsePoint(char*str)
1668 int l = strlen(str);
1669 char*comma = strchr(str, ',');
1670 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1671 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1672 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1673 p.x = parseTwip(tmp);
1674 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1675 p.y = parseTwip(tmp);
1679 int parseColor2(char*str, RGBA*color)
1681 int l = strlen(str);
1685 struct {unsigned char r,g,b;char*name;} colors[] =
1686 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1687 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1688 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1689 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1690 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1691 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1692 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1693 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1694 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1695 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1696 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1697 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1701 if(str[0]=='#' && (l==7 || l==9)) {
1702 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1704 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1706 color->r = r; color->g = g; color->b = b; color->a = a;
1709 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1710 if(!strcmp(str, colors[t].name)) {
1715 color->r = r; color->g = g; color->b = b; color->a = a;
1721 RGBA parseColor(char*str)
1724 if(!parseColor2(str, &c))
1725 syntaxerror("Expression '%s' is not a color", str);
1729 typedef struct _muladd {
1734 MULADD parseMulAdd(char*str)
1737 char* str2 = (char*)malloc(strlen(str)+5);
1744 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1745 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1746 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1747 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1748 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1749 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1750 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1751 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1752 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1753 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1755 syntaxerror("'%s' is not a valid color transform expression", str);
1757 m.add = (int)(add*256);
1758 m.mul = (int)(mul*256);
1763 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1765 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1766 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1768 if(a<-32768) a=-32768;
1769 if(a>32767) a=32767;
1770 if(m<-32768) m=-32768;
1771 if(m>32767) m=32767;
1777 float parsePercent(char*str)
1779 int l = strlen(str);
1783 return atoi(str)/100.0;
1785 syntaxerror("Expression '%s' is not a percentage", str);
1788 int isPercent(char*str)
1790 return str[strlen(str)-1]=='%';
1792 int parseNewSize(char*str, int size)
1795 return parsePercent(str)*size;
1797 return (int)(atof(str)*20);
1800 int isColor(char*str)
1803 return parseColor2(str, &c);
1806 static char* lu(map_t* args, char*name)
1808 char* value = map_lookup(args, name);
1810 map_dump(args, stdout, "");
1811 syntaxerror("internal error 2: value %s should be set", name);
1816 static int c_flash(map_t*args)
1818 char* name = lu(args, "name");
1819 char* compressstr = lu(args, "compress");
1820 SRECT bbox = parseBox(lu(args, "bbox"));
1821 int version = parseInt(lu(args, "version"));
1822 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1824 RGBA color = parseColor(lu(args, "background"));
1825 if(!strcmp(name, "!default!") || override_outputname)
1828 if(!strcmp(compressstr, "default"))
1829 compress = version==6;
1830 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1832 else if(!strcmp(compressstr, "no"))
1834 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1836 s_swf(name, bbox, version, fps, compress, color);
1839 int isRelative(char*str)
1841 return !strncmp(str, "<plus>", 6) ||
1842 !strncmp(str, "<minus>", 7);
1844 char* getOffset(char*str)
1846 if(!strncmp(str, "<plus>", 6))
1848 if(!strncmp(str, "<minus>", 7))
1850 syntaxerror("internal error (347)");
1853 int getSign(char*str)
1855 if(!strncmp(str, "<plus>", 6))
1857 if(!strncmp(str, "<minus>", 7))
1859 syntaxerror("internal error (348)");
1862 static dictionary_t points;
1863 static mem_t mpoints;
1864 int points_initialized = 0;
1866 SPOINT getPoint(SRECT r, char*name)
1869 if(!strcmp(name, "center")) {
1871 p.x = (r.xmin + r.xmax)/2;
1872 p.y = (r.ymin + r.ymax)/2;
1876 if(points_initialized)
1877 l = (int)dictionary_lookup(&points, name);
1879 syntaxerror("Invalid point: \"%s\".", name);
1882 return *(SPOINT*)&mpoints.buffer[l];
1884 static int c_gradient(map_t*args)
1886 char*name = lu(args, "name");
1887 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1888 int rotate = parseInt(lu(args, "rotate"));
1892 syntaxerror("colon (:) expected");
1894 s_gradient(name, text, radial,rotate);
1897 static int c_point(map_t*args)
1899 char*name = lu(args, "name");
1903 if(!points_initialized) {
1904 dictionary_init(&points);
1906 points_initialized = 1;
1908 p.x = parseTwip(lu(args, "x"));
1909 p.y = parseTwip(lu(args, "y"));
1910 pos = mem_put(&mpoints, &p, sizeof(p));
1911 string_set(&s1, name);
1913 dictionary_put(&points, s1, (void*)pos);
1916 static int c_play(map_t*args)
1918 char*name = lu(args, "name");
1919 char*loop = lu(args, "loop");
1920 char*nomultiple = lu(args, "nomultiple");
1922 if(!strcmp(nomultiple, "nomultiple"))
1925 nm = parseInt(nomultiple);
1927 if(s_playsound(name, parseInt(loop), nm, 0)) {
1929 } else if(s_swf3action(name, "play")) {
1935 static int c_stop(map_t*args)
1937 char*name = map_lookup(args, "name");
1939 if(s_playsound(name, 0,0,1)) {
1941 } else if(s_swf3action(name, "stop")) {
1944 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
1948 static int c_nextframe(map_t*args)
1950 char*name = lu(args, "name");
1952 if(s_swf3action(name, "nextframe")) {
1955 syntaxerror("I don't know anything about movie \"%s\"", name);
1959 static int c_previousframe(map_t*args)
1961 char*name = lu(args, "name");
1963 if(s_swf3action(name, "previousframe")) {
1966 syntaxerror("I don't know anything about movie \"%s\"", name);
1970 static int c_placement(map_t*args, int type)
1972 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1975 char* luminancestr = lu(args, "luminance");
1976 char* scalestr = lu(args, "scale");
1977 char* scalexstr = lu(args, "scalex");
1978 char* scaleystr = lu(args, "scaley");
1979 char* rotatestr = lu(args, "rotate");
1980 char* shearstr = lu(args, "shear");
1981 char* xstr="", *pivotstr="";
1982 char* ystr="", *anglestr="";
1983 char*above = lu(args, "above"); /*FIXME*/
1984 char*below = lu(args, "below");
1985 char* rstr = lu(args, "red");
1986 char* gstr = lu(args, "green");
1987 char* bstr = lu(args, "blue");
1988 char* astr = lu(args, "alpha");
1989 char* pinstr = lu(args, "pin");
1990 char* as = map_lookup(args, "as");
1998 if(type==9) { // (?) .rotate or .arcchange
1999 pivotstr = lu(args, "pivot");
2000 anglestr = lu(args, "angle");
2002 xstr = lu(args, "x");
2003 ystr = lu(args, "y");
2006 luminance = parseMulAdd(luminancestr);
2009 luminance.mul = 256;
2013 if(scalexstr[0]||scaleystr[0])
2014 syntaxerror("scalex/scaley and scale cannot both be set");
2015 scalexstr = scaleystr = scalestr;
2018 if(type == 0 || type == 4) {
2020 character = lu(args, "character");
2021 parameters_clear(&p);
2022 } else if (type == 5) {
2023 character = lu(args, "name");
2024 parameters_clear(&p);
2027 p = s_getParameters(instance);
2032 if(isRelative(xstr)) {
2033 if(type == 0 || type == 4)
2034 syntaxerror("relative x values not allowed for initial put or startclip");
2035 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2037 p.x = parseTwip(xstr);
2041 if(isRelative(ystr)) {
2042 if(type == 0 || type == 4)
2043 syntaxerror("relative y values not allowed for initial put or startclip");
2044 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2046 p.y = parseTwip(ystr);
2050 /* scale, scalex, scaley */
2052 oldbbox = s_getCharBBox(character);
2054 oldbbox = s_getInstanceBBox(instance);
2056 oldwidth = oldbbox.xmax - oldbbox.xmin;
2057 oldheight = oldbbox.ymax - oldbbox.ymin;
2059 if(oldwidth==0) p.scalex = 1.0;
2062 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2066 if(oldheight==0) p.scaley = 1.0;
2069 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2075 if(isRelative(rotatestr)) {
2076 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2078 p.rotate = parseFloat(rotatestr);
2084 if(isRelative(shearstr)) {
2085 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2087 p.shear = parseFloat(shearstr);
2092 if(isPoint(pivotstr))
2093 p.pivot = parsePoint(pivotstr);
2095 p.pivot = getPoint(oldbbox, pivotstr);
2099 p.pin = parsePoint(pinstr);
2101 p.pin = getPoint(oldbbox, pinstr);
2104 /* color transform */
2106 if(rstr[0] || luminancestr[0]) {
2109 r = parseMulAdd(rstr);
2111 r.add = p.cxform.r0;
2112 r.mul = p.cxform.r1;
2114 r = mergeMulAdd(r, luminance);
2115 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2117 if(gstr[0] || luminancestr[0]) {
2120 g = parseMulAdd(gstr);
2122 g.add = p.cxform.g0;
2123 g.mul = p.cxform.g1;
2125 g = mergeMulAdd(g, luminance);
2126 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2128 if(bstr[0] || luminancestr[0]) {
2131 b = parseMulAdd(bstr);
2133 b.add = p.cxform.b0;
2134 b.mul = p.cxform.b1;
2136 b = mergeMulAdd(b, luminance);
2137 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2140 MULADD a = parseMulAdd(astr);
2141 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2145 s_put(instance, character, p);
2147 s_change(instance, p);
2149 s_qchange(instance, p);
2151 s_jump(instance, p);
2153 s_startclip(instance, character, p);
2154 else if(type == 5) {
2156 s_buttonput(character, as, p);
2158 s_buttonput(character, "shape", p);
2163 static int c_put(map_t*args)
2165 c_placement(args, 0);
2168 static int c_change(map_t*args)
2170 c_placement(args, 1);
2173 static int c_qchange(map_t*args)
2175 c_placement(args, 2);
2178 static int c_arcchange(map_t*args)
2180 c_placement(args, 2);
2183 static int c_jump(map_t*args)
2185 c_placement(args, 3);
2188 static int c_startclip(map_t*args)
2190 c_placement(args, 4);
2193 static int c_show(map_t*args)
2195 c_placement(args, 5);
2198 static int c_del(map_t*args)
2200 char*instance = lu(args, "name");
2201 s_delinstance(instance);
2204 static int c_end(map_t*args)
2209 static int c_sprite(map_t*args)
2211 char* name = lu(args, "name");
2215 static int c_frame(map_t*args)
2217 char*framestr = lu(args, "n");
2218 char*cutstr = lu(args, "cut");
2219 char*name = lu(args, "name");
2222 if(strcmp(cutstr, "no"))
2224 if(isRelative(framestr)) {
2225 frame = s_getframe();
2226 if(getSign(framestr)<0)
2227 syntaxerror("relative frame expressions must be positive");
2228 frame += parseInt(getOffset(framestr));
2231 frame = parseInt(framestr);
2232 if(s_getframe() >= frame
2233 && !(frame==0 && s_getframe()==frame)) // equality is o.k. for frame 0
2234 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2236 s_frame(frame, cut, name);
2239 static int c_primitive(map_t*args)
2241 char*name = lu(args, "name");
2242 char*command = lu(args, "commandname");
2243 int width=0, height=0, r=0;
2244 int linewidth = parseTwip(lu(args, "line"));
2245 char*colorstr = lu(args, "color");
2246 RGBA color = parseColor(colorstr);
2247 char*fillstr = lu(args, "fill");
2254 if(!strcmp(command, "circle"))
2256 else if(!strcmp(command, "filled"))
2260 width = parseTwip(lu(args, "width"));
2261 height = parseTwip(lu(args, "height"));
2262 } else if (type==1) {
2263 r = parseTwip(lu(args, "r"));
2264 } else if (type==2) {
2265 outline = lu(args, "outline");
2268 if(!strcmp(fillstr, "fill"))
2270 if(!strcmp(fillstr, "none"))
2272 if(width<0 || height<0 || linewidth<0 || r<0)
2273 syntaxerror("values width, height, line, r must be positive");
2275 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2276 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2277 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2281 static int c_textshape(map_t*args)
2283 char*name = lu(args, "name");
2284 char*text = lu(args, "text");
2285 char*font = lu(args, "font");
2286 float size = parsePercent(lu(args, "size"));
2288 s_textshape(name, font, size, text);
2292 static int c_swf(map_t*args)
2294 char*name = lu(args, "name");
2295 char*filename = lu(args, "filename");
2296 char*command = lu(args, "commandname");
2297 if(!strcmp(command, "shape"))
2298 warning("Please use .swf instead of .shape");
2299 s_includeswf(name, filename);
2303 static int c_font(map_t*args)
2305 char*name = lu(args, "name");
2306 char*filename = lu(args, "filename");
2307 s_font(name, filename);
2311 static int c_sound(map_t*args)
2313 char*name = lu(args, "name");
2314 char*filename = lu(args, "filename");
2315 s_sound(name, filename);
2319 static int c_text(map_t*args)
2321 char*name = lu(args, "name");
2322 char*text = lu(args, "text");
2323 char*font = lu(args, "font");
2324 float size = parsePercent(lu(args, "size"));
2325 RGBA color = parseColor(lu(args, "color"));
2326 s_text(name, font, text, (int)(size*100), color);
2330 static int c_soundtrack(map_t*args)
2335 static int c_quicktime(map_t*args)
2337 char*name = lu(args, "name");
2338 char*url = lu(args, "url");
2339 s_quicktime(name, url);
2343 static int c_image(map_t*args)
2345 char*command = lu(args, "commandname");
2346 char*name = lu(args, "name");
2347 char*filename = lu(args, "filename");
2348 if(!strcmp(command,"jpeg")) {
2349 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2350 s_image(name, "jpeg", filename, quality);
2352 s_image(name, "png", filename, 0);
2357 static int c_outline(map_t*args)
2359 char*name = lu(args, "name");
2360 char*format = lu(args, "format");
2364 syntaxerror("colon (:) expected");
2366 s_outline(name, format, text);
2370 int fakechar(map_t*args)
2372 char*name = lu(args, "name");
2373 s_box(name, 0, 0, black, 20, 0);
2377 static int c_egon(map_t*args) {return fakechar(args);}
2378 static int c_button(map_t*args) {
2379 char*name = lu(args, "name");
2383 static int current_button_flags = 0;
2384 static int c_on_press(map_t*args)
2386 char*position = lu(args, "position");
2388 if(!strcmp(position, "inside")) {
2389 current_button_flags |= BC_OVERUP_OVERDOWN;
2390 } else if(!strcmp(position, "outside")) {
2391 //current_button_flags |= BC_IDLE_OUTDOWN;
2392 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2393 } else if(!strcmp(position, "anywhere")) {
2394 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2397 if(type == RAWDATA) {
2399 s_buttonaction(current_button_flags, action);
2400 current_button_flags = 0;
2406 static int c_on_release(map_t*args)
2408 char*position = lu(args, "position");
2410 if(!strcmp(position, "inside")) {
2411 current_button_flags |= BC_OVERDOWN_OVERUP;
2412 } else if(!strcmp(position, "outside")) {
2413 current_button_flags |= BC_OUTDOWN_IDLE;
2414 } else if(!strcmp(position, "anywhere")) {
2415 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2418 if(type == RAWDATA) {
2420 s_buttonaction(current_button_flags, action);
2421 current_button_flags = 0;
2427 static int c_on_move_in(map_t*args)
2429 char*position = lu(args, "state");
2431 if(!strcmp(position, "pressed")) {
2432 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2433 } else if(!strcmp(position, "not_pressed")) {
2434 current_button_flags |= BC_IDLE_OVERUP;
2435 } else if(!strcmp(position, "any")) {
2436 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2439 if(type == RAWDATA) {
2441 s_buttonaction(current_button_flags, action);
2442 current_button_flags = 0;
2448 static int c_on_move_out(map_t*args)
2450 char*position = lu(args, "state");
2452 if(!strcmp(position, "pressed")) {
2453 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2454 } else if(!strcmp(position, "not_pressed")) {
2455 current_button_flags |= BC_OVERUP_IDLE;
2456 } else if(!strcmp(position, "any")) {
2457 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2460 if(type == RAWDATA) {
2462 s_buttonaction(current_button_flags, action);
2463 current_button_flags = 0;
2469 static int c_on_key(map_t*args)
2471 char*key = lu(args, "key");
2473 if(strlen(key)==1) {
2476 current_button_flags |= 0x4000 + (key[0]*0x200);
2478 syntaxerror("invalid character: %c"+key[0]);
2483 <ctrl-x> = 0x200*(x-'a')
2487 syntaxerror("invalid key: %s",key);
2490 if(type == RAWDATA) {
2492 s_buttonaction(current_button_flags, action);
2493 current_button_flags = 0;
2500 static int c_edittext(map_t*args)
2502 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
2503 char*name = lu(args, "name");
2504 char*font = lu(args, "font");
2505 int size = (int)(1024*parsePercent(lu(args, "size")));
2506 int width = parseTwip(lu(args, "width"));
2507 int height = parseTwip(lu(args, "height"));
2508 char*text = lu(args, "text");
2509 RGBA color = parseColor(lu(args, "color"));
2510 int maxlength = parseInt(lu(args, "maxlength"));
2511 char*variable = lu(args, "variable");
2512 char*passwordstr = lu(args, "password");
2513 char*wordwrapstr = lu(args, "wordwrap");
2514 char*multilinestr = lu(args, "multiline");
2515 char*htmlstr = lu(args, "html");
2516 char*noselectstr = lu(args, "noselect");
2517 char*readonlystr = lu(args, "readonly");
2518 char*borderstr = lu(args, "border");
2521 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2522 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2523 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2524 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2525 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2526 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2527 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2529 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags);
2533 static int c_morphshape(map_t*args) {return fakechar(args);}
2534 static int c_movie(map_t*args) {return fakechar(args);}
2536 static int c_texture(map_t*args) {return 0;}
2538 static int c_action(map_t*args)
2541 if(type != RAWDATA) {
2542 syntaxerror("colon (:) expected");
2552 command_func_t* func;
2555 {{"flash", c_flash, "bbox=autocrop background=black version=5 fps=50 name=!default! @compress=default"},
2556 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2557 // "import" type stuff
2558 {"swf", c_swf, "name filename"},
2559 {"shape", c_swf, "name filename"},
2560 {"jpeg", c_image, "name filename quality=80%"},
2561 {"png", c_image, "name filename"},
2562 {"movie", c_movie, "name filename"},
2563 {"sound", c_sound, "name filename"},
2564 {"font", c_font, "name filename"},
2565 {"soundtrack", c_soundtrack, "filename"},
2566 {"quicktime", c_quicktime, "url"},
2568 // generators of primitives
2570 {"point", c_point, "name x=0 y=0"},
2571 {"gradient", c_gradient, "name @radial=0 rotate=0"},
2572 {"outline", c_outline, "name format=simple"},
2573 {"textshape", c_textshape, "name font size=100% text"},
2575 // character generators
2576 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2577 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2578 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2580 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2581 {"text", c_text, "name text font size=100% color=white"},
2582 {"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"},
2583 {"morphshape", c_morphshape, "name start end"},
2584 {"button", c_button, "name"},
2585 {"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="},
2586 {"on_press", c_on_press, "position=inside"},
2587 {"on_release", c_on_release, "position=anywhere"},
2588 {"on_move_in", c_on_move_in, "state=not_pressed"},
2589 {"on_move_out", c_on_move_out, "state=not_pressed"},
2590 {"on_key", c_on_key, "key=any"},
2593 {"play", c_play, "name loop=0 @nomultiple=0"},
2594 {"stop", c_stop, "name= "},
2595 {"nextframe", c_nextframe, "name"},
2596 {"previousframe", c_previousframe, "name"},
2598 // object placement tags
2599 {"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="},
2600 {"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="},
2601 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2602 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2603 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2604 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2605 {"del", c_del, "name"},
2606 // virtual object placement
2607 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2609 // commands which start a block
2610 //startclip (see above)
2611 {"sprite", c_sprite, "name"},
2612 {"action", c_action, ""},
2618 static map_t parseArguments(char*command, char*pattern)
2634 string_set(&t1, "commandname");
2635 string_set(&t2, command);
2636 map_put(&result, t1, t2);
2638 if(!pattern || !*pattern)
2645 if(!strncmp("<i> ", x, 3)) {
2647 if(type == COMMAND || type == RAWDATA) {
2649 syntaxerror("character name expected");
2651 name[pos].str = "instance";
2653 value[pos].str = text;
2654 value[pos].len = strlen(text);
2658 if(type == ASSIGNMENT)
2661 name[pos].str = "character";
2663 value[pos].str = text;
2664 value[pos].len = strlen(text);
2672 isboolean[pos] = (x[0] =='@');
2685 name[pos].len = d-x;
2690 name[pos].len = e-x;
2691 value[pos].str = e+1;
2692 value[pos].len = d-e-1;
2700 /* for(t=0;t<len;t++) {
2701 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2702 isboolean[t]?"(boolean)":"");
2707 if(type == RAWDATA || type == COMMAND) {
2712 // first, search for boolean arguments
2713 for(pos=0;pos<len;pos++)
2715 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2717 if(type == ASSIGNMENT)
2719 value[pos].str = text;
2720 value[pos].len = strlen(text);
2721 /*printf("setting boolean parameter %s (to %s)\n",
2722 strdup_n(name[pos], namelen[pos]),
2723 strdup_n(value[pos], valuelen[pos]));*/
2728 // second, search for normal arguments
2730 for(pos=0;pos<len;pos++)
2732 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2733 (type != ASSIGNMENT && !set[pos])) {
2735 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2737 if(type == ASSIGNMENT)
2740 value[pos].str = text;
2741 value[pos].len = strlen(text);
2743 printf("setting parameter %s (to %s)\n",
2744 strdup_n(name[pos].str, name[pos].len),
2745 strdup_n(value[pos].str, value[pos].len));
2751 syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
2755 for(t=0;t<len;t++) {
2756 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2759 for(t=0;t<len;t++) {
2760 if(value[t].str && value[t].str[0] == '*') {
2761 //relative default- take value from some other parameter
2763 for(s=0;s<len;s++) {
2764 if(value[s].len == value[t].len-1 &&
2765 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2766 value[t].str = value[s].str;
2769 if(value[t].str == 0) {
2771 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2775 /* ok, now construct the dictionary from the parameters */
2779 map_put(&result, name[t], value[t]);
2783 static void parseArgumentsForCommand(char*command)
2788 msg("<verbose> parse Command: %s (line %d)", command, line);
2790 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2791 if(!strcmp(arguments[t].command, command)) {
2793 /* ugly hack- will be removed soon (once documentation and .sc generating
2794 utilities have been changed) */
2795 if(!strcmp(command, "swf") && !stackpos) {
2796 warning("Please use .flash instead of .swf- this will be mandatory soon");
2801 args = parseArguments(command, arguments[t].arguments);
2807 syntaxerror("command %s not known", command);
2809 // catch missing .flash directives at the beginning of a file
2810 if(strcmp(command, "flash") && !stackpos)
2812 syntaxerror("No movie defined- use .flash first");
2816 printf(".%s\n", command);fflush(stdout);
2817 map_dump(&args, stdout, "\t");fflush(stdout);
2820 (*arguments[nr].func)(&args);
2822 /*if(!strcmp(command, "button") ||
2823 !strcmp(command, "action")) {
2826 if(type == COMMAND) {
2827 if(!strcmp(text, "end"))
2841 int main (int argc,char ** argv)
2844 processargs(argc, argv);
2845 initLog(0,-1,0,0,-1,verbose);
2848 args_callback_usage(argv[0]);
2852 file = generateTokens(filename);
2854 printf("parser returned error.\n");
2860 while(!noMoreTokens()) {
2863 syntaxerror("command expected");
2864 parseArgumentsForCommand(text);