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 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
647 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
648 tag = swf_InsertTag(tag, ST_SHOWFRAME);
650 tag = swf_InsertTag(tag, ST_END);
652 swf_OptimizeTagOrder(swf);
658 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
659 swf->movieSize = currentrect; /* "autocrop" */
662 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
663 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
664 swf->movieSize.ymax += 20;
667 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
669 syntaxerror("couldn't create output file %s", filename);
672 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
674 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
678 dictionary_clear(&instances);
679 dictionary_clear(&characters);
680 dictionary_clear(&images);
681 dictionary_clear(&outlines);
682 dictionary_clear(&gradients);
683 dictionary_clear(&fonts);
684 dictionary_clear(&sounds);
694 if(stack[stackpos-1].type == 0)
695 syntaxerror("End of file encountered in .flash block");
696 if(stack[stackpos-1].type == 1)
697 syntaxerror("End of file encountered in .sprite block");
698 if(stack[stackpos-1].type == 2)
699 syntaxerror("End of file encountered in .clip block");
705 return currentframe+1;
708 void s_frame(int nr, int cut, char*name)
714 syntaxerror("Illegal frame number");
715 nr--; // internally, frame 1 is frame 0
717 for(t=currentframe;t<nr;t++) {
718 tag = swf_InsertTag(tag, ST_SHOWFRAME);
719 if(t==nr-1 && name && *name) {
720 tag = swf_InsertTag(tag, ST_FRAMELABEL);
721 swf_SetString(tag, name);
724 if(nr == 0 && currentframe == 0 && name) {
725 tag = swf_InsertTag(tag, ST_FRAMELABEL);
726 swf_SetString(tag, name);
731 syntaxerror("Can't cut, frame empty");
733 stack[stackpos].cut = tag;
739 int parseColor2(char*str, RGBA*color);
741 int addFillStyle(SHAPE*s, SRECT*r, char*texture)
746 if(texture[0] == '#') {
747 parseColor2(texture, &color);
748 return swf_ShapeAddSolidFillStyle(s, &color);
749 } else if((image = dictionary_lookup(&images, texture))) {
751 swf_GetMatrix(0, &m);
752 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
753 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
756 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
757 } /*else if ((texture = dictionary_lookup(&textures, texture))) {
758 } */ else if ((gradient = dictionary_lookup(&gradients, texture))) {
762 swf_GetMatrix(0, &rot);
763 ccos = cos(-gradient->rotate*2*3.14159265358979/360);
764 csin = sin(-gradient->rotate*2*3.14159265358979/360);
766 rot.r1 = -csin*65536;
769 r2 = swf_TurnRect(*r, &rot);
770 swf_GetMatrix(0, &m);
771 m.sx = (r2.xmax - r2.xmin)*2*ccos;
772 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
773 m.r0 = (r2.ymax - r2.ymin)*2*csin;
774 m.sy = (r2.ymax - r2.ymin)*2*ccos;
775 m.tx = r->xmin + (r->xmax - r->xmin)/2;
776 m.ty = r->ymin + (r->ymax - r->ymin)/2;
777 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
778 } else if (parseColor2(texture, &color)) {
779 return swf_ShapeAddSolidFillStyle(s, &color);
781 syntaxerror("not a color/fillstyle: %s", texture);
786 RGBA black={r:0,g:0,b:0,a:0};
787 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
796 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
799 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
801 fs1 = addFillStyle(s, &r2, texture);
804 r.xmin = r2.xmin-linewidth-linewidth/2;
805 r.ymin = r2.ymin-linewidth-linewidth/2;
806 r.xmax = r2.xmax+linewidth+linewidth/2;
807 r.ymax = r2.ymax+linewidth+linewidth/2;
809 swf_SetShapeHeader(tag,s);
810 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
811 swf_ShapeSetLine(tag,s,width,0);
812 swf_ShapeSetLine(tag,s,0,height);
813 swf_ShapeSetLine(tag,s,-width,0);
814 swf_ShapeSetLine(tag,s,0,-height);
815 swf_ShapeSetEnd(tag);
818 s_addcharacter(name, id, tag, r);
822 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
828 outline = dictionary_lookup(&outlines, outlinename);
830 syntaxerror("outline %s not defined", outlinename);
834 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
837 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
839 fs1 = addFillStyle(s, &r2, texture);
842 rect.xmin = r2.xmin-linewidth-linewidth/2;
843 rect.ymin = r2.ymin-linewidth-linewidth/2;
844 rect.xmax = r2.xmax+linewidth+linewidth/2;
845 rect.ymax = r2.ymax+linewidth+linewidth/2;
847 swf_SetRect(tag,&rect);
848 swf_SetShapeStyles(tag, s);
849 swf_ShapeCountBits(s,0,0);
850 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, 1, 1,
851 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
852 swf_SetShapeBits(tag, s);
853 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
856 s_addcharacter(name, id, tag, rect);
860 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
865 r2.xmin = r2.ymin = 0;
869 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
872 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
874 fs1 = addFillStyle(s, &r2, texture);
876 rect.xmin = r2.xmin-linewidth-linewidth/2;
877 rect.ymin = r2.ymin-linewidth-linewidth/2;
878 rect.xmax = r2.xmax+linewidth+linewidth/2;
879 rect.ymax = r2.ymax+linewidth+linewidth/2;
881 swf_SetRect(tag,&rect);
882 swf_SetShapeHeader(tag,s);
883 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
884 swf_ShapeSetCircle(tag, s, r,r,r,r);
885 swf_ShapeSetEnd(tag);
888 s_addcharacter(name, id, tag, rect);
892 void s_textshape(char*name, char*fontname, float size, char*_text)
895 U8*text = (U8*)_text;
899 font = dictionary_lookup(&fonts, fontname);
901 syntaxerror("font \"%s\" not known!", fontname);
903 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
904 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
905 s_box(name, 0, 0, black, 20, 0);
908 g = font->ascii2glyph[text[0]];
910 outline = malloc(sizeof(outline_t));
911 memset(outline, 0, sizeof(outline_t));
912 outline->shape = font->glyph[g].shape;
913 outline->bbox = font->layout->bounds[g];
917 swf_Shape11DrawerInit(&draw, 0);
918 swf_DrawText(&draw, font, (int)(size*100), _text);
920 outline->shape = swf_ShapeDrawerToShape(&draw);
921 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
925 if(dictionary_lookup(&outlines, name))
926 syntaxerror("outline %s defined twice", name);
927 dictionary_put2(&outlines, name, outline);
930 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
935 font = dictionary_lookup(&fonts, fontname);
937 syntaxerror("font \"%s\" not known!", fontname);
939 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
941 if(!font->numchars) {
942 s_box(name, 0, 0, black, 20, 0);
945 r = swf_SetDefineText(tag, font, &color, text, size);
947 s_addcharacter(name, id, tag, r);
951 void s_quicktime(char*name, char*url)
956 memset(&r, 0, sizeof(r));
958 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
960 swf_SetString(tag, url);
962 s_addcharacter(name, id, tag, r);
966 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags)
969 EditTextLayout layout;
972 font = dictionary_lookup(&fonts, fontname);
974 syntaxerror("font \"%s\" not known!", fontname);
975 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
978 layout.leftmargin = 0;
979 layout.rightmargin = 0;
986 swf_SetEditText(tag, flags|ET_USEOUTLINES, r, text, color, maxlength, font->id, size, &layout, variable);
988 s_addcharacter(name, id, tag, r);
992 /* type: either "jpeg" or "png"
994 void s_image(char*name, char*type, char*filename, int quality)
996 /* an image is actually two folded: 1st bitmap, 2nd character.
997 Both of them can be used separately */
999 /* step 1: the bitmap */
1004 warning("image type \"png\" not supported yet!");
1005 s_box(name, 0, 0, black, 20, 0);
1009 #ifndef HAVE_LIBJPEG
1010 warning("no jpeg support compiled in");
1011 s_box(name, 0, 0, black, 20, 0);
1014 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1015 swf_SetU16(tag, imageID);
1017 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1018 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1021 swf_GetJPEGSize(filename, &width, &height);
1028 s_addimage(name, id, tag, r);
1033 /* step 2: the character */
1034 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1035 swf_SetU16(tag, id);
1036 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1038 s_addcharacter(name, id, tag, r);
1042 void dumpSWF(SWF*swf)
1044 TAG* tag = swf->firstTag;
1045 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1047 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1050 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1053 void s_font(char*name, char*filename)
1056 font = swf_LoadFont(filename);
1059 warning("Couldn't open font file \"%s\"", filename);
1060 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1061 memset(font, 0, sizeof(SWFFONT));
1062 dictionary_put2(&fonts, name, font);
1068 /* fix the layout. Only needed for old fonts */
1070 for(t=0;t<font->numchars;t++) {
1071 font->glyph[t].advance = 0;
1074 swf_FontCreateLayout(font);
1076 /* just in case this thing is used in .edittext later on */
1077 swf_FontPrepareForEditText(font);
1080 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1081 swf_FontSetDefine2(tag, font);
1084 if(dictionary_lookup(&fonts, name))
1085 syntaxerror("font %s defined twice", name);
1086 dictionary_put2(&fonts, name, font);
1091 typedef struct _sound_t
1097 void s_sound(char*name, char*filename)
1099 struct WAV wav, wav2;
1104 if(!readWAV(filename, &wav)) {
1105 warning("Couldn't read wav file \"%s\"", filename);
1109 convertWAV2mono(&wav, &wav2, 44100);
1110 samples = (U16*)wav2.data;
1111 numsamples = wav2.size/2;
1115 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1116 swf_SetU16(tag, id); //id
1117 swf_SetSoundDefine(tag, samples, numsamples);
1119 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1123 if(dictionary_lookup(&sounds, name))
1124 syntaxerror("sound %s defined twice", name);
1125 dictionary_put2(&sounds, name, sound);
1133 static char* gradient_getToken(const char**p)
1137 while(**p && strchr(" \t\n\r", **p)) {
1141 while(**p && !strchr(" \t\n\r", **p)) {
1144 result = malloc((*p)-start+1);
1145 memcpy(result,start,(*p)-start+1);
1146 result[(*p)-start] = 0;
1150 float parsePercent(char*str);
1151 RGBA parseColor(char*str);
1153 GRADIENT parseGradient(const char*str)
1156 const char* p = str;
1157 memset(&gradient, 0, sizeof(GRADIENT));
1159 char*posstr,*colorstr;
1162 posstr = gradient_getToken(&p);
1165 pos = parsePercent(posstr);
1166 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1167 colorstr = gradient_getToken(&p);
1168 color = parseColor(colorstr);
1169 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1170 warning("gradient record too big- max size is 8, rest ignored");
1173 gradient.ratios[gradient.num] = (int)(pos*255.0);
1174 gradient.rgba[gradient.num] = color;
1182 void s_gradient(char*name, const char*text, int radial, int rotate)
1184 gradient_t* gradient;
1185 gradient = malloc(sizeof(gradient_t));
1186 memset(gradient, 0, sizeof(gradient_t));
1187 gradient->gradient = parseGradient(text);
1188 gradient->radial = radial;
1189 gradient->rotate = rotate;
1191 if(dictionary_lookup(&gradients, name))
1192 syntaxerror("gradient %s defined twice", name);
1193 dictionary_put2(&gradients, name, gradient);
1196 void s_action(const char*text)
1199 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1201 syntaxerror("Couldn't compile ActionScript");
1204 tag = swf_InsertTag(tag, ST_DOACTION);
1206 swf_ActionSet(tag, a);
1211 int s_swf3action(char*name, char*action)
1214 instance_t* object = 0;
1216 dictionary_lookup(&instances, name);
1217 if(!object && name && *name) {
1218 /* we have a name, but couldn't find it. Abort. */
1221 a = action_SetTarget(0, name);
1222 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1223 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1224 else if(!strcmp(action, "stop")) a = action_Stop(a);
1225 else if(!strcmp(action, "play")) a = action_Play(a);
1226 a = action_SetTarget(a, "");
1229 tag = swf_InsertTag(tag, ST_DOACTION);
1230 swf_ActionSet(tag, a);
1235 void s_outline(char*name, char*format, char*source)
1244 swf_Shape11DrawerInit(&draw, 0);
1245 draw_string(&draw, source);
1247 shape = swf_ShapeDrawerToShape(&draw);
1248 bounds = swf_ShapeDrawerGetBBox(&draw);
1249 draw.dealloc(&draw);
1251 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1252 outline->shape = shape;
1253 outline->bbox = bounds;
1255 if(dictionary_lookup(&outlines, name))
1256 syntaxerror("outline %s defined twice", name);
1257 dictionary_put2(&outlines, name, outline);
1260 int s_playsound(char*name, int loops, int nomultiple, int stop)
1265 sound = dictionary_lookup(&sounds, name);
1270 tag = swf_InsertTag(tag, ST_STARTSOUND);
1271 swf_SetU16(tag, sound->id); //id
1272 memset(&info, 0, sizeof(info));
1275 info.nomultiple = nomultiple;
1276 swf_SetSoundInfo(tag, &info);
1280 void s_includeswf(char*name, char*filename)
1288 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1289 f = open(filename,O_RDONLY|O_BINARY);
1291 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1292 s_box(name, 0, 0, black, 20, 0);
1295 if (swf_ReadSWF(f,&swf)<0) {
1296 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1297 s_box(name, 0, 0, black, 20, 0);
1302 /* FIXME: The following sets the bounding Box for the character.
1303 It is wrong for two reasons:
1304 a) It may be too small (in case objects in the movie clip at the borders)
1305 b) it may be too big (because the poor movie never got autocropped)
1309 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1310 swf_SetU16(tag, id);
1313 swf_Relocate(&swf, idmap);
1315 ftag = swf.firstTag;
1319 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1320 if(cutout[t] == ftag->id) {
1324 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1326 if(ftag->id == ST_END)
1330 /* We simply dump all tags right after the sprite
1331 header, relying on the fact that swf_OptimizeTagOrder() will
1332 sort things out for us later.
1333 We also rely on the fact that the imported SWF is well-formed.
1335 tag = swf_InsertTag(tag, ftag->id);
1336 swf_SetBlock(tag, ftag->data, ftag->len);
1340 syntaxerror("Included file %s contains errors", filename);
1341 tag = swf_InsertTag(tag, ST_END);
1345 s_addcharacter(name, id, tag, r);
1348 SRECT s_getCharBBox(char*name)
1350 character_t* c = dictionary_lookup(&characters, name);
1351 if(!c) syntaxerror("character '%s' unknown(2)", name);
1354 SRECT s_getInstanceBBox(char*name)
1356 instance_t * i = dictionary_lookup(&instances, name);
1358 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1360 if(!c) syntaxerror("internal error(5)");
1363 parameters_t s_getParameters(char*name)
1365 instance_t * i = dictionary_lookup(&instances, name);
1366 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1367 return i->parameters;
1369 void s_startclip(char*instance, char*character, parameters_t p)
1371 character_t* c = dictionary_lookup(&characters, character);
1375 syntaxerror("character %s not known", character);
1377 i = s_addinstance(instance, c, currentdepth);
1379 m = s_instancepos(i->character->size, &p);
1381 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1382 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1383 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1385 i->lastFrame= currentframe;
1387 stack[stackpos].tag = tag;
1388 stack[stackpos].type = 2;
1397 swf_SetTagPos(stack[stackpos].tag, 0);
1398 swf_GetPlaceObject(stack[stackpos].tag, &p);
1399 p.clipdepth = currentdepth;
1401 swf_ClearTag(stack[stackpos].tag);
1402 swf_SetPlaceObject(stack[stackpos].tag, &p);
1406 void s_put(char*instance, char*character, parameters_t p)
1408 character_t* c = dictionary_lookup(&characters, character);
1412 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1415 i = s_addinstance(instance, c, currentdepth);
1417 m = s_instancepos(i->character->size, &p);
1419 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1420 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1422 i->lastFrame = currentframe;
1426 void s_jump(char*instance, parameters_t p)
1428 instance_t* i = dictionary_lookup(&instances, instance);
1431 syntaxerror("instance %s not known", instance);
1435 m = s_instancepos(i->character->size, &p);
1437 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1438 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1440 i->lastFrame = currentframe;
1443 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1447 if(num==0 || num==1)
1449 ratio = (float)pos/(float)num;
1451 p.x = (p2->x-p1->x)*ratio + p1->x;
1452 p.y = (p2->y-p1->y)*ratio + p1->y;
1453 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1454 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1455 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1456 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1458 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1459 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1460 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1461 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1463 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1464 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1465 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1466 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1468 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1469 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1470 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1471 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1475 void s_change(char*instance, parameters_t p2)
1477 instance_t* i = dictionary_lookup(&instances, instance);
1481 int frame, allframes;
1483 syntaxerror("instance %s not known", instance);
1487 allframes = currentframe - i->lastFrame - 1;
1489 warning(".change ignored. can only .put/.change an object once per frame.");
1493 m = s_instancepos(i->character->size, &p2);
1494 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1495 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1498 /* o.k., we got the start and end point set. Now iterate though all the
1499 tags in between, inserting object changes after each new frame */
1502 if(!t) syntaxerror("internal error(6)");
1504 while(frame < allframes) {
1505 if(t->id == ST_SHOWFRAME) {
1510 p = s_interpolate(&p1, &p2, frame, allframes);
1511 m = s_instancepos(i->character->size, &p); //needed?
1512 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1513 i->lastFrame = currentframe;
1514 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1516 if(frame == allframes)
1521 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1525 void s_delinstance(char*instance)
1527 instance_t* i = dictionary_lookup(&instances, instance);
1529 syntaxerror("instance %s not known", instance);
1531 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1532 swf_SetU16(tag, i->depth);
1533 dictionary_del(&instances, instance);
1536 void s_qchange(char*instance, parameters_t p)
1543 syntaxerror(".end unexpected");
1544 if(stack[stackpos-1].type == 0)
1546 else if(stack[stackpos-1].type == 1)
1548 else if(stack[stackpos-1].type == 2)
1550 else if(stack[stackpos-1].type == 3)
1552 else syntaxerror("internal error 1");
1555 // ------------------------------------------------------------------------
1557 typedef int command_func_t(map_t*args);
1559 SRECT parseBox(char*str)
1562 float xmin, xmax, ymin, ymax;
1563 char*x = strchr(str, 'x');
1565 if(!strcmp(str, "autocrop")) {
1566 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1570 d1 = strchr(x+1, ':');
1572 d2 = strchr(d1+1, ':');
1574 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1578 else if(d1 && !d2) {
1579 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1585 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1590 r.xmin = (SCOORD)(xmin*20);
1591 r.ymin = (SCOORD)(ymin*20);
1592 r.xmax = (SCOORD)(xmax*20);
1593 r.ymax = (SCOORD)(ymax*20);
1596 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1599 float parseFloat(char*str)
1603 int parseInt(char*str)
1608 if(str[0]=='+' || str[0]=='-')
1612 if(str[t]<'0' || str[t]>'9')
1613 syntaxerror("Not an Integer: \"%s\"", str);
1616 int parseTwip(char*str)
1620 if(str[0]=='+' || str[0]=='-') {
1625 dot = strchr(str, '.');
1629 return sign*parseInt(str)*20;
1631 int l=strlen(++dot);
1633 for(s=str;s<dot-1;s++)
1634 if(*s<'0' || *s>'9')
1635 syntaxerror("Not a coordinate: \"%s\"", str);
1637 if(*s<'0' || *s>'9')
1638 syntaxerror("Not a coordinate: \"%s\"", str);
1640 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
1641 warning("precision loss: %s converted to twip: %s", str, dot);
1646 return sign*atoi(str)*20;
1648 return sign*atoi(str)*20+atoi(dot)*2;
1650 return sign*atoi(str)*20+atoi(dot)/5;
1655 int isPoint(char*str)
1657 if(strchr(str, '('))
1663 SPOINT parsePoint(char*str)
1667 int l = strlen(str);
1668 char*comma = strchr(str, ',');
1669 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1670 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1671 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1672 p.x = parseTwip(tmp);
1673 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1674 p.y = parseTwip(tmp);
1678 int parseColor2(char*str, RGBA*color)
1680 int l = strlen(str);
1684 struct {unsigned char r,g,b;char*name;} colors[] =
1685 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1686 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1687 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1688 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1689 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1690 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1691 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1692 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1693 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1694 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1695 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1696 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1700 if(str[0]=='#' && (l==7 || l==9)) {
1701 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1703 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1705 color->r = r; color->g = g; color->b = b; color->a = a;
1708 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1709 if(!strcmp(str, colors[t].name)) {
1714 color->r = r; color->g = g; color->b = b; color->a = a;
1720 RGBA parseColor(char*str)
1723 if(!parseColor2(str, &c))
1724 syntaxerror("Expression '%s' is not a color", str);
1728 typedef struct _muladd {
1733 MULADD parseMulAdd(char*str)
1736 char* str2 = (char*)malloc(strlen(str)+5);
1743 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1744 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1745 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1746 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1747 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1748 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1749 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1750 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1751 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1752 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1754 syntaxerror("'%s' is not a valid color transform expression", str);
1756 m.add = (int)(add*256);
1757 m.mul = (int)(mul*256);
1762 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1764 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1765 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1767 if(a<-32768) a=-32768;
1768 if(a>32767) a=32767;
1769 if(m<-32768) m=-32768;
1770 if(m>32767) m=32767;
1776 float parsePercent(char*str)
1778 int l = strlen(str);
1782 return atoi(str)/100.0;
1784 syntaxerror("Expression '%s' is not a percentage", str);
1787 int isPercent(char*str)
1789 return str[strlen(str)-1]=='%';
1791 int parseNewSize(char*str, int size)
1794 return parsePercent(str)*size;
1796 return (int)(atof(str)*20);
1799 int isColor(char*str)
1802 return parseColor2(str, &c);
1805 static char* lu(map_t* args, char*name)
1807 char* value = map_lookup(args, name);
1809 map_dump(args, stdout, "");
1810 syntaxerror("internal error 2: value %s should be set", name);
1815 static int c_flash(map_t*args)
1817 char* name = lu(args, "name");
1818 char* compressstr = lu(args, "compress");
1819 SRECT bbox = parseBox(lu(args, "bbox"));
1820 int version = parseInt(lu(args, "version"));
1821 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1823 RGBA color = parseColor(lu(args, "background"));
1824 if(!strcmp(name, "!default!") || override_outputname)
1827 if(!strcmp(compressstr, "default"))
1828 compress = version==6;
1829 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1831 else if(!strcmp(compressstr, "no"))
1833 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1835 s_swf(name, bbox, version, fps, compress, color);
1838 int isRelative(char*str)
1840 return !strncmp(str, "<plus>", 6) ||
1841 !strncmp(str, "<minus>", 7);
1843 char* getOffset(char*str)
1845 if(!strncmp(str, "<plus>", 6))
1847 if(!strncmp(str, "<minus>", 7))
1849 syntaxerror("internal error (347)");
1852 int getSign(char*str)
1854 if(!strncmp(str, "<plus>", 6))
1856 if(!strncmp(str, "<minus>", 7))
1858 syntaxerror("internal error (348)");
1861 static dictionary_t points;
1862 static mem_t mpoints;
1863 int points_initialized = 0;
1865 SPOINT getPoint(SRECT r, char*name)
1868 if(!strcmp(name, "center")) {
1870 p.x = (r.xmin + r.xmax)/2;
1871 p.y = (r.ymin + r.ymax)/2;
1875 if(points_initialized)
1876 l = (int)dictionary_lookup(&points, name);
1878 syntaxerror("Invalid point: \"%s\".", name);
1881 return *(SPOINT*)&mpoints.buffer[l];
1883 static int c_gradient(map_t*args)
1885 char*name = lu(args, "name");
1886 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1887 int rotate = parseInt(lu(args, "rotate"));
1891 syntaxerror("colon (:) expected");
1893 s_gradient(name, text, radial,rotate);
1896 static int c_point(map_t*args)
1898 char*name = lu(args, "name");
1902 if(!points_initialized) {
1903 dictionary_init(&points);
1905 points_initialized = 1;
1907 p.x = parseTwip(lu(args, "x"));
1908 p.y = parseTwip(lu(args, "y"));
1909 pos = mem_put(&mpoints, &p, sizeof(p));
1910 string_set(&s1, name);
1912 dictionary_put(&points, s1, (void*)pos);
1915 static int c_play(map_t*args)
1917 char*name = lu(args, "name");
1918 char*loop = lu(args, "loop");
1919 char*nomultiple = lu(args, "nomultiple");
1921 if(!strcmp(nomultiple, "nomultiple"))
1924 nm = parseInt(nomultiple);
1926 if(s_playsound(name, parseInt(loop), nm, 0)) {
1928 } else if(s_swf3action(name, "play")) {
1934 static int c_stop(map_t*args)
1936 char*name = map_lookup(args, "name");
1938 if(s_playsound(name, 0,0,1)) {
1940 } else if(s_swf3action(name, "stop")) {
1943 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
1947 static int c_nextframe(map_t*args)
1949 char*name = lu(args, "name");
1951 if(s_swf3action(name, "nextframe")) {
1954 syntaxerror("I don't know anything about movie \"%s\"", name);
1958 static int c_previousframe(map_t*args)
1960 char*name = lu(args, "name");
1962 if(s_swf3action(name, "previousframe")) {
1965 syntaxerror("I don't know anything about movie \"%s\"", name);
1969 static int c_placement(map_t*args, int type)
1971 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1974 char* luminancestr = lu(args, "luminance");
1975 char* scalestr = lu(args, "scale");
1976 char* scalexstr = lu(args, "scalex");
1977 char* scaleystr = lu(args, "scaley");
1978 char* rotatestr = lu(args, "rotate");
1979 char* shearstr = lu(args, "shear");
1980 char* xstr="", *pivotstr="";
1981 char* ystr="", *anglestr="";
1982 char*above = lu(args, "above"); /*FIXME*/
1983 char*below = lu(args, "below");
1984 char* rstr = lu(args, "red");
1985 char* gstr = lu(args, "green");
1986 char* bstr = lu(args, "blue");
1987 char* astr = lu(args, "alpha");
1988 char* pinstr = lu(args, "pin");
1989 char* as = map_lookup(args, "as");
1997 if(type==9) { // (?) .rotate or .arcchange
1998 pivotstr = lu(args, "pivot");
1999 anglestr = lu(args, "angle");
2001 xstr = lu(args, "x");
2002 ystr = lu(args, "y");
2005 luminance = parseMulAdd(luminancestr);
2008 luminance.mul = 256;
2012 if(scalexstr[0]||scaleystr[0])
2013 syntaxerror("scalex/scaley and scale cannot both be set");
2014 scalexstr = scaleystr = scalestr;
2017 if(type == 0 || type == 4) {
2019 character = lu(args, "character");
2020 parameters_clear(&p);
2021 } else if (type == 5) {
2022 character = lu(args, "name");
2023 parameters_clear(&p);
2026 p = s_getParameters(instance);
2031 if(isRelative(xstr)) {
2032 if(type == 0 || type == 4)
2033 syntaxerror("relative x values not allowed for initial put or startclip");
2034 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2036 p.x = parseTwip(xstr);
2040 if(isRelative(ystr)) {
2041 if(type == 0 || type == 4)
2042 syntaxerror("relative y values not allowed for initial put or startclip");
2043 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2045 p.y = parseTwip(ystr);
2049 /* scale, scalex, scaley */
2051 oldbbox = s_getCharBBox(character);
2053 oldbbox = s_getInstanceBBox(instance);
2055 oldwidth = oldbbox.xmax - oldbbox.xmin;
2056 oldheight = oldbbox.ymax - oldbbox.ymin;
2058 if(oldwidth==0) p.scalex = 1.0;
2061 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2065 if(oldheight==0) p.scaley = 1.0;
2068 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2074 if(isRelative(rotatestr)) {
2075 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2077 p.rotate = parseFloat(rotatestr);
2083 if(isRelative(shearstr)) {
2084 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2086 p.shear = parseFloat(shearstr);
2091 if(isPoint(pivotstr))
2092 p.pivot = parsePoint(pivotstr);
2094 p.pivot = getPoint(oldbbox, pivotstr);
2098 p.pin = parsePoint(pinstr);
2100 p.pin = getPoint(oldbbox, pinstr);
2103 /* color transform */
2105 if(rstr[0] || luminancestr[0]) {
2108 r = parseMulAdd(rstr);
2110 r.add = p.cxform.r0;
2111 r.mul = p.cxform.r1;
2113 r = mergeMulAdd(r, luminance);
2114 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2116 if(gstr[0] || luminancestr[0]) {
2119 g = parseMulAdd(gstr);
2121 g.add = p.cxform.g0;
2122 g.mul = p.cxform.g1;
2124 g = mergeMulAdd(g, luminance);
2125 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2127 if(bstr[0] || luminancestr[0]) {
2130 b = parseMulAdd(bstr);
2132 b.add = p.cxform.b0;
2133 b.mul = p.cxform.b1;
2135 b = mergeMulAdd(b, luminance);
2136 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2139 MULADD a = parseMulAdd(astr);
2140 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2144 s_put(instance, character, p);
2146 s_change(instance, p);
2148 s_qchange(instance, p);
2150 s_jump(instance, p);
2152 s_startclip(instance, character, p);
2153 else if(type == 5) {
2155 s_buttonput(character, as, p);
2157 s_buttonput(character, "shape", p);
2162 static int c_put(map_t*args)
2164 c_placement(args, 0);
2167 static int c_change(map_t*args)
2169 c_placement(args, 1);
2172 static int c_qchange(map_t*args)
2174 c_placement(args, 2);
2177 static int c_arcchange(map_t*args)
2179 c_placement(args, 2);
2182 static int c_jump(map_t*args)
2184 c_placement(args, 3);
2187 static int c_startclip(map_t*args)
2189 c_placement(args, 4);
2192 static int c_show(map_t*args)
2194 c_placement(args, 5);
2197 static int c_del(map_t*args)
2199 char*instance = lu(args, "name");
2200 s_delinstance(instance);
2203 static int c_end(map_t*args)
2208 static int c_sprite(map_t*args)
2210 char* name = lu(args, "name");
2214 static int c_frame(map_t*args)
2216 char*framestr = lu(args, "n");
2217 char*cutstr = lu(args, "cut");
2218 char*name = lu(args, "name");
2221 if(strcmp(cutstr, "no"))
2223 if(isRelative(framestr)) {
2224 frame = s_getframe();
2225 if(getSign(framestr)<0)
2226 syntaxerror("relative frame expressions must be positive");
2227 frame += parseInt(getOffset(framestr));
2230 frame = parseInt(framestr);
2231 if(s_getframe() >= frame
2232 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2233 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2235 s_frame(frame, cut, name);
2238 static int c_primitive(map_t*args)
2240 char*name = lu(args, "name");
2241 char*command = lu(args, "commandname");
2242 int width=0, height=0, r=0;
2243 int linewidth = parseTwip(lu(args, "line"));
2244 char*colorstr = lu(args, "color");
2245 RGBA color = parseColor(colorstr);
2246 char*fillstr = lu(args, "fill");
2253 if(!strcmp(command, "circle"))
2255 else if(!strcmp(command, "filled"))
2259 width = parseTwip(lu(args, "width"));
2260 height = parseTwip(lu(args, "height"));
2261 } else if (type==1) {
2262 r = parseTwip(lu(args, "r"));
2263 } else if (type==2) {
2264 outline = lu(args, "outline");
2267 if(!strcmp(fillstr, "fill"))
2269 if(!strcmp(fillstr, "none"))
2271 if(width<0 || height<0 || linewidth<0 || r<0)
2272 syntaxerror("values width, height, line, r must be positive");
2274 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2275 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2276 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2280 static int c_textshape(map_t*args)
2282 char*name = lu(args, "name");
2283 char*text = lu(args, "text");
2284 char*font = lu(args, "font");
2285 float size = parsePercent(lu(args, "size"));
2287 s_textshape(name, font, size, text);
2291 static int c_swf(map_t*args)
2293 char*name = lu(args, "name");
2294 char*filename = lu(args, "filename");
2295 char*command = lu(args, "commandname");
2296 if(!strcmp(command, "shape"))
2297 warning("Please use .swf instead of .shape");
2298 s_includeswf(name, filename);
2302 static int c_font(map_t*args)
2304 char*name = lu(args, "name");
2305 char*filename = lu(args, "filename");
2306 s_font(name, filename);
2310 static int c_sound(map_t*args)
2312 char*name = lu(args, "name");
2313 char*filename = lu(args, "filename");
2314 s_sound(name, filename);
2318 static int c_text(map_t*args)
2320 char*name = lu(args, "name");
2321 char*text = lu(args, "text");
2322 char*font = lu(args, "font");
2323 float size = parsePercent(lu(args, "size"));
2324 RGBA color = parseColor(lu(args, "color"));
2325 s_text(name, font, text, (int)(size*100), color);
2329 static int c_soundtrack(map_t*args)
2334 static int c_quicktime(map_t*args)
2336 char*name = lu(args, "name");
2337 char*url = lu(args, "url");
2338 s_quicktime(name, url);
2342 static int c_image(map_t*args)
2344 char*command = lu(args, "commandname");
2345 char*name = lu(args, "name");
2346 char*filename = lu(args, "filename");
2347 if(!strcmp(command,"jpeg")) {
2348 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2349 s_image(name, "jpeg", filename, quality);
2351 s_image(name, "png", filename, 0);
2356 static int c_outline(map_t*args)
2358 char*name = lu(args, "name");
2359 char*format = lu(args, "format");
2363 syntaxerror("colon (:) expected");
2365 s_outline(name, format, text);
2369 int fakechar(map_t*args)
2371 char*name = lu(args, "name");
2372 s_box(name, 0, 0, black, 20, 0);
2376 static int c_egon(map_t*args) {return fakechar(args);}
2377 static int c_button(map_t*args) {
2378 char*name = lu(args, "name");
2382 static int current_button_flags = 0;
2383 static int c_on_press(map_t*args)
2385 char*position = lu(args, "position");
2387 if(!strcmp(position, "inside")) {
2388 current_button_flags |= BC_OVERUP_OVERDOWN;
2389 } else if(!strcmp(position, "outside")) {
2390 //current_button_flags |= BC_IDLE_OUTDOWN;
2391 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2392 } else if(!strcmp(position, "anywhere")) {
2393 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2396 if(type == RAWDATA) {
2398 s_buttonaction(current_button_flags, action);
2399 current_button_flags = 0;
2405 static int c_on_release(map_t*args)
2407 char*position = lu(args, "position");
2409 if(!strcmp(position, "inside")) {
2410 current_button_flags |= BC_OVERDOWN_OVERUP;
2411 } else if(!strcmp(position, "outside")) {
2412 current_button_flags |= BC_OUTDOWN_IDLE;
2413 } else if(!strcmp(position, "anywhere")) {
2414 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2417 if(type == RAWDATA) {
2419 s_buttonaction(current_button_flags, action);
2420 current_button_flags = 0;
2426 static int c_on_move_in(map_t*args)
2428 char*position = lu(args, "state");
2430 if(!strcmp(position, "pressed")) {
2431 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2432 } else if(!strcmp(position, "not_pressed")) {
2433 current_button_flags |= BC_IDLE_OVERUP;
2434 } else if(!strcmp(position, "any")) {
2435 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2438 if(type == RAWDATA) {
2440 s_buttonaction(current_button_flags, action);
2441 current_button_flags = 0;
2447 static int c_on_move_out(map_t*args)
2449 char*position = lu(args, "state");
2451 if(!strcmp(position, "pressed")) {
2452 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2453 } else if(!strcmp(position, "not_pressed")) {
2454 current_button_flags |= BC_OVERUP_IDLE;
2455 } else if(!strcmp(position, "any")) {
2456 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2459 if(type == RAWDATA) {
2461 s_buttonaction(current_button_flags, action);
2462 current_button_flags = 0;
2468 static int c_on_key(map_t*args)
2470 char*key = lu(args, "key");
2472 if(strlen(key)==1) {
2475 current_button_flags |= 0x4000 + (key[0]*0x200);
2477 syntaxerror("invalid character: %c"+key[0]);
2482 <ctrl-x> = 0x200*(x-'a')
2486 syntaxerror("invalid key: %s",key);
2489 if(type == RAWDATA) {
2491 s_buttonaction(current_button_flags, action);
2492 current_button_flags = 0;
2499 static int c_edittext(map_t*args)
2501 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
2502 char*name = lu(args, "name");
2503 char*font = lu(args, "font");
2504 int size = (int)(1024*parsePercent(lu(args, "size")));
2505 int width = parseTwip(lu(args, "width"));
2506 int height = parseTwip(lu(args, "height"));
2507 char*text = lu(args, "text");
2508 RGBA color = parseColor(lu(args, "color"));
2509 int maxlength = parseInt(lu(args, "maxlength"));
2510 char*variable = lu(args, "variable");
2511 char*passwordstr = lu(args, "password");
2512 char*wordwrapstr = lu(args, "wordwrap");
2513 char*multilinestr = lu(args, "multiline");
2514 char*htmlstr = lu(args, "html");
2515 char*noselectstr = lu(args, "noselect");
2516 char*readonlystr = lu(args, "readonly");
2517 char*borderstr = lu(args, "border");
2520 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2521 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2522 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2523 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2524 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2525 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2526 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2528 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags);
2532 static int c_morphshape(map_t*args) {return fakechar(args);}
2533 static int c_movie(map_t*args) {return fakechar(args);}
2535 static int c_texture(map_t*args) {return 0;}
2537 static int c_action(map_t*args)
2540 if(type != RAWDATA) {
2541 syntaxerror("colon (:) expected");
2551 command_func_t* func;
2554 {{"flash", c_flash, "bbox=autocrop background=black version=5 fps=50 name=!default! @compress=default"},
2555 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2556 // "import" type stuff
2557 {"swf", c_swf, "name filename"},
2558 {"shape", c_swf, "name filename"},
2559 {"jpeg", c_image, "name filename quality=80%"},
2560 {"png", c_image, "name filename"},
2561 {"movie", c_movie, "name filename"},
2562 {"sound", c_sound, "name filename"},
2563 {"font", c_font, "name filename"},
2564 {"soundtrack", c_soundtrack, "filename"},
2565 {"quicktime", c_quicktime, "url"},
2567 // generators of primitives
2569 {"point", c_point, "name x=0 y=0"},
2570 {"gradient", c_gradient, "name @radial=0 rotate=0"},
2571 {"outline", c_outline, "name format=simple"},
2572 {"textshape", c_textshape, "name font size=100% text"},
2574 // character generators
2575 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2576 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2577 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2579 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2580 {"text", c_text, "name text font size=100% color=white"},
2581 {"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"},
2582 {"morphshape", c_morphshape, "name start end"},
2583 {"button", c_button, "name"},
2584 {"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="},
2585 {"on_press", c_on_press, "position=inside"},
2586 {"on_release", c_on_release, "position=anywhere"},
2587 {"on_move_in", c_on_move_in, "state=not_pressed"},
2588 {"on_move_out", c_on_move_out, "state=not_pressed"},
2589 {"on_key", c_on_key, "key=any"},
2592 {"play", c_play, "name loop=0 @nomultiple=0"},
2593 {"stop", c_stop, "name= "},
2594 {"nextframe", c_nextframe, "name"},
2595 {"previousframe", c_previousframe, "name"},
2597 // object placement tags
2598 {"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="},
2599 {"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="},
2600 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2601 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2602 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2603 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2604 {"del", c_del, "name"},
2605 // virtual object placement
2606 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2608 // commands which start a block
2609 //startclip (see above)
2610 {"sprite", c_sprite, "name"},
2611 {"action", c_action, ""},
2617 static map_t parseArguments(char*command, char*pattern)
2633 string_set(&t1, "commandname");
2634 string_set(&t2, command);
2635 map_put(&result, t1, t2);
2637 if(!pattern || !*pattern)
2644 if(!strncmp("<i> ", x, 3)) {
2646 if(type == COMMAND || type == RAWDATA) {
2648 syntaxerror("character name expected");
2650 name[pos].str = "instance";
2652 value[pos].str = text;
2653 value[pos].len = strlen(text);
2657 if(type == ASSIGNMENT)
2660 name[pos].str = "character";
2662 value[pos].str = text;
2663 value[pos].len = strlen(text);
2671 isboolean[pos] = (x[0] =='@');
2684 name[pos].len = d-x;
2689 name[pos].len = e-x;
2690 value[pos].str = e+1;
2691 value[pos].len = d-e-1;
2699 /* for(t=0;t<len;t++) {
2700 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2701 isboolean[t]?"(boolean)":"");
2706 if(type == RAWDATA || type == COMMAND) {
2711 // first, search for boolean arguments
2712 for(pos=0;pos<len;pos++)
2714 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2716 if(type == ASSIGNMENT)
2718 value[pos].str = text;
2719 value[pos].len = strlen(text);
2720 /*printf("setting boolean parameter %s (to %s)\n",
2721 strdup_n(name[pos], namelen[pos]),
2722 strdup_n(value[pos], valuelen[pos]));*/
2727 // second, search for normal arguments
2729 for(pos=0;pos<len;pos++)
2731 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2732 (type != ASSIGNMENT && !set[pos])) {
2734 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2736 if(type == ASSIGNMENT)
2739 value[pos].str = text;
2740 value[pos].len = strlen(text);
2742 printf("setting parameter %s (to %s)\n",
2743 strdup_n(name[pos].str, name[pos].len),
2744 strdup_n(value[pos].str, value[pos].len));
2750 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
2754 for(t=0;t<len;t++) {
2755 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2758 for(t=0;t<len;t++) {
2759 if(value[t].str && value[t].str[0] == '*') {
2760 //relative default- take value from some other parameter
2762 for(s=0;s<len;s++) {
2763 if(value[s].len == value[t].len-1 &&
2764 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2765 value[t].str = value[s].str;
2768 if(value[t].str == 0) {
2770 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2774 /* ok, now construct the dictionary from the parameters */
2778 map_put(&result, name[t], value[t]);
2782 static void parseArgumentsForCommand(char*command)
2787 msg("<verbose> parse Command: %s (line %d)", command, line);
2789 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2790 if(!strcmp(arguments[t].command, command)) {
2792 /* ugly hack- will be removed soon (once documentation and .sc generating
2793 utilities have been changed) */
2794 if(!strcmp(command, "swf") && !stackpos) {
2795 warning("Please use .flash instead of .swf- this will be mandatory soon");
2800 args = parseArguments(command, arguments[t].arguments);
2806 syntaxerror("command %s not known", command);
2808 // catch missing .flash directives at the beginning of a file
2809 if(strcmp(command, "flash") && !stackpos)
2811 syntaxerror("No movie defined- use .flash first");
2815 printf(".%s\n", command);fflush(stdout);
2816 map_dump(&args, stdout, "\t");fflush(stdout);
2819 (*arguments[nr].func)(&args);
2821 /*if(!strcmp(command, "button") ||
2822 !strcmp(command, "action")) {
2825 if(type == COMMAND) {
2826 if(!strcmp(text, "end"))
2840 int main (int argc,char ** argv)
2843 processargs(argc, argv);
2844 initLog(0,-1,0,0,-1,verbose);
2847 args_callback_usage(argv[0]);
2851 file = generateTokens(filename);
2853 printf("parser returned error.\n");
2859 while(!noMoreTokens()) {
2862 syntaxerror("command expected");
2863 parseArgumentsForCommand(text);