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_SHOWFRAME);
622 tag = swf_InsertTag(tag, ST_END);
624 tag = stack[stackpos].tag;
627 syntaxerror("internal error(7)");
629 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
630 free(stack[stackpos].name);
633 static void s_endSWF()
639 if(stack[stackpos].cut)
640 tag = removeFromTo(stack[stackpos].cut, tag);
644 swf = stack[stackpos].swf;
645 filename = stack[stackpos].filename;
647 //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
648 // tag = swf_InsertTag(tag, ST_SHOWFRAME);
649 tag = swf_InsertTag(tag, ST_SHOWFRAME);
651 tag = swf_InsertTag(tag, ST_END);
653 swf_OptimizeTagOrder(swf);
659 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
660 swf->movieSize = currentrect; /* "autocrop" */
663 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
664 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
665 swf->movieSize.ymax += 20;
666 warning("Empty bounding box for movie");
669 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
671 syntaxerror("couldn't create output file %s", filename);
674 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
676 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
680 dictionary_clear(&instances);
681 dictionary_clear(&characters);
682 dictionary_clear(&images);
683 dictionary_clear(&outlines);
684 dictionary_clear(&gradients);
685 dictionary_clear(&fonts);
686 dictionary_clear(&sounds);
696 if(stack[stackpos-1].type == 0)
697 syntaxerror("End of file encountered in .flash block");
698 if(stack[stackpos-1].type == 1)
699 syntaxerror("End of file encountered in .sprite block");
700 if(stack[stackpos-1].type == 2)
701 syntaxerror("End of file encountered in .clip block");
707 return currentframe+1;
710 void s_frame(int nr, int cut, char*name)
716 syntaxerror("Illegal frame number");
717 nr--; // internally, frame 1 is frame 0
719 for(t=currentframe;t<nr;t++) {
720 tag = swf_InsertTag(tag, ST_SHOWFRAME);
721 if(t==nr-1 && name && *name) {
722 tag = swf_InsertTag(tag, ST_FRAMELABEL);
723 swf_SetString(tag, name);
726 if(nr == 0 && currentframe == 0 && name) {
727 tag = swf_InsertTag(tag, ST_FRAMELABEL);
728 swf_SetString(tag, name);
733 syntaxerror("Can't cut, frame empty");
735 stack[stackpos].cut = tag;
741 int parseColor2(char*str, RGBA*color);
743 int addFillStyle(SHAPE*s, SRECT*r, char*texture)
748 if(texture[0] == '#') {
749 parseColor2(texture, &color);
750 return swf_ShapeAddSolidFillStyle(s, &color);
751 } else if((image = dictionary_lookup(&images, texture))) {
753 swf_GetMatrix(0, &m);
754 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
755 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
758 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
759 } /*else if ((texture = dictionary_lookup(&textures, texture))) {
760 } */ else if ((gradient = dictionary_lookup(&gradients, texture))) {
764 swf_GetMatrix(0, &rot);
765 ccos = cos(-gradient->rotate*2*3.14159265358979/360);
766 csin = sin(-gradient->rotate*2*3.14159265358979/360);
768 rot.r1 = -csin*65536;
771 r2 = swf_TurnRect(*r, &rot);
772 swf_GetMatrix(0, &m);
773 m.sx = (r2.xmax - r2.xmin)*2*ccos;
774 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
775 m.r0 = (r2.ymax - r2.ymin)*2*csin;
776 m.sy = (r2.ymax - r2.ymin)*2*ccos;
777 m.tx = r->xmin + (r->xmax - r->xmin)/2;
778 m.ty = r->ymin + (r->ymax - r->ymin)/2;
779 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
780 } else if (parseColor2(texture, &color)) {
781 return swf_ShapeAddSolidFillStyle(s, &color);
783 syntaxerror("not a color/fillstyle: %s", texture);
788 RGBA black={r:0,g:0,b:0,a:0};
789 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
798 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
801 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
803 fs1 = addFillStyle(s, &r2, texture);
806 r.xmin = r2.xmin-linewidth-linewidth/2;
807 r.ymin = r2.ymin-linewidth-linewidth/2;
808 r.xmax = r2.xmax+linewidth+linewidth/2;
809 r.ymax = r2.ymax+linewidth+linewidth/2;
811 swf_SetShapeHeader(tag,s);
812 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
813 swf_ShapeSetLine(tag,s,width,0);
814 swf_ShapeSetLine(tag,s,0,height);
815 swf_ShapeSetLine(tag,s,-width,0);
816 swf_ShapeSetLine(tag,s,0,-height);
817 swf_ShapeSetEnd(tag);
820 s_addcharacter(name, id, tag, r);
824 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
830 outline = dictionary_lookup(&outlines, outlinename);
832 syntaxerror("outline %s not defined", outlinename);
836 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
839 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
841 fs1 = addFillStyle(s, &r2, texture);
844 rect.xmin = r2.xmin-linewidth-linewidth/2;
845 rect.ymin = r2.ymin-linewidth-linewidth/2;
846 rect.xmax = r2.xmax+linewidth+linewidth/2;
847 rect.ymax = r2.ymax+linewidth+linewidth/2;
849 swf_SetRect(tag,&rect);
850 swf_SetShapeStyles(tag, s);
851 swf_ShapeCountBits(s,0,0);
852 swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, 1, 1,
853 &s->data, &s->bitlen, s->bits.fill, s->bits.line);
854 swf_SetShapeBits(tag, s);
855 swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
858 s_addcharacter(name, id, tag, rect);
862 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
867 r2.xmin = r2.ymin = 0;
871 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
874 ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
876 fs1 = addFillStyle(s, &r2, texture);
878 rect.xmin = r2.xmin-linewidth-linewidth/2;
879 rect.ymin = r2.ymin-linewidth-linewidth/2;
880 rect.xmax = r2.xmax+linewidth+linewidth/2;
881 rect.ymax = r2.ymax+linewidth+linewidth/2;
883 swf_SetRect(tag,&rect);
884 swf_SetShapeHeader(tag,s);
885 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
886 swf_ShapeSetCircle(tag, s, r,r,r,r);
887 swf_ShapeSetEnd(tag);
890 s_addcharacter(name, id, tag, rect);
894 void s_textshape(char*name, char*fontname, float size, char*_text)
897 U8*text = (U8*)_text;
901 font = dictionary_lookup(&fonts, fontname);
903 syntaxerror("font \"%s\" not known!", fontname);
905 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
906 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
907 s_box(name, 0, 0, black, 20, 0);
910 g = font->ascii2glyph[text[0]];
912 outline = malloc(sizeof(outline_t));
913 memset(outline, 0, sizeof(outline_t));
914 outline->shape = font->glyph[g].shape;
915 outline->bbox = font->layout->bounds[g];
919 swf_Shape11DrawerInit(&draw, 0);
920 swf_DrawText(&draw, font, (int)(size*100), _text);
922 outline->shape = swf_ShapeDrawerToShape(&draw);
923 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
927 if(dictionary_lookup(&outlines, name))
928 syntaxerror("outline %s defined twice", name);
929 dictionary_put2(&outlines, name, outline);
932 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
937 font = dictionary_lookup(&fonts, fontname);
939 syntaxerror("font \"%s\" not known!", fontname);
941 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
943 if(!font->numchars) {
944 s_box(name, 0, 0, black, 20, 0);
947 r = swf_SetDefineText(tag, font, &color, text, size);
949 s_addcharacter(name, id, tag, r);
953 void s_quicktime(char*name, char*url)
958 memset(&r, 0, sizeof(r));
960 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
962 swf_SetString(tag, url);
964 s_addcharacter(name, id, tag, r);
968 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags)
971 EditTextLayout layout;
974 font = dictionary_lookup(&fonts, fontname);
976 syntaxerror("font \"%s\" not known!", fontname);
977 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
980 layout.leftmargin = 0;
981 layout.rightmargin = 0;
988 swf_SetEditText(tag, flags|ET_USEOUTLINES, r, text, color, maxlength, font->id, size, &layout, variable);
990 s_addcharacter(name, id, tag, r);
994 /* type: either "jpeg" or "png"
996 void s_image(char*name, char*type, char*filename, int quality)
998 /* an image is actually two folded: 1st bitmap, 2nd character.
999 Both of them can be used separately */
1001 /* step 1: the bitmap */
1006 warning("image type \"png\" not supported yet!");
1007 s_box(name, 0, 0, black, 20, 0);
1011 #ifndef HAVE_LIBJPEG
1012 warning("no jpeg support compiled in");
1013 s_box(name, 0, 0, black, 20, 0);
1016 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1017 swf_SetU16(tag, imageID);
1019 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1020 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1023 swf_GetJPEGSize(filename, &width, &height);
1030 s_addimage(name, id, tag, r);
1035 /* step 2: the character */
1036 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1037 swf_SetU16(tag, id);
1038 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1040 s_addcharacter(name, id, tag, r);
1044 void dumpSWF(SWF*swf)
1046 TAG* tag = swf->firstTag;
1047 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1049 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1052 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1055 void s_font(char*name, char*filename)
1058 font = swf_LoadFont(filename);
1061 warning("Couldn't open font file \"%s\"", filename);
1062 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1063 memset(font, 0, sizeof(SWFFONT));
1064 dictionary_put2(&fonts, name, font);
1070 /* fix the layout. Only needed for old fonts */
1072 for(t=0;t<font->numchars;t++) {
1073 font->glyph[t].advance = 0;
1076 swf_FontCreateLayout(font);
1078 /* just in case this thing is used in .edittext later on */
1079 swf_FontPrepareForEditText(font);
1082 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1083 swf_FontSetDefine2(tag, font);
1086 if(dictionary_lookup(&fonts, name))
1087 syntaxerror("font %s defined twice", name);
1088 dictionary_put2(&fonts, name, font);
1093 typedef struct _sound_t
1099 void s_sound(char*name, char*filename)
1101 struct WAV wav, wav2;
1106 if(!readWAV(filename, &wav)) {
1107 warning("Couldn't read wav file \"%s\"", filename);
1111 convertWAV2mono(&wav, &wav2, 44100);
1112 samples = (U16*)wav2.data;
1113 numsamples = wav2.size/2;
1115 #ifdef WORDS_BIGENDIAN
1117 for(t=0;t<numsamples;t++) {
1118 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1123 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1124 swf_SetU16(tag, id); //id
1125 swf_SetSoundDefine(tag, samples, numsamples);
1127 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1131 if(dictionary_lookup(&sounds, name))
1132 syntaxerror("sound %s defined twice", name);
1133 dictionary_put2(&sounds, name, sound);
1141 static char* gradient_getToken(const char**p)
1145 while(**p && strchr(" \t\n\r", **p)) {
1149 while(**p && !strchr(" \t\n\r", **p)) {
1152 result = malloc((*p)-start+1);
1153 memcpy(result,start,(*p)-start+1);
1154 result[(*p)-start] = 0;
1158 float parsePercent(char*str);
1159 RGBA parseColor(char*str);
1161 GRADIENT parseGradient(const char*str)
1164 const char* p = str;
1165 memset(&gradient, 0, sizeof(GRADIENT));
1167 char*posstr,*colorstr;
1170 posstr = gradient_getToken(&p);
1173 pos = parsePercent(posstr);
1174 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1175 colorstr = gradient_getToken(&p);
1176 color = parseColor(colorstr);
1177 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1178 warning("gradient record too big- max size is 8, rest ignored");
1181 gradient.ratios[gradient.num] = (int)(pos*255.0);
1182 gradient.rgba[gradient.num] = color;
1190 void s_gradient(char*name, const char*text, int radial, int rotate)
1192 gradient_t* gradient;
1193 gradient = malloc(sizeof(gradient_t));
1194 memset(gradient, 0, sizeof(gradient_t));
1195 gradient->gradient = parseGradient(text);
1196 gradient->radial = radial;
1197 gradient->rotate = rotate;
1199 if(dictionary_lookup(&gradients, name))
1200 syntaxerror("gradient %s defined twice", name);
1201 dictionary_put2(&gradients, name, gradient);
1204 void s_action(const char*text)
1207 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1209 syntaxerror("Couldn't compile ActionScript");
1212 tag = swf_InsertTag(tag, ST_DOACTION);
1214 swf_ActionSet(tag, a);
1219 int s_swf3action(char*name, char*action)
1222 instance_t* object = 0;
1224 dictionary_lookup(&instances, name);
1225 if(!object && name && *name) {
1226 /* we have a name, but couldn't find it. Abort. */
1229 a = action_SetTarget(0, name);
1230 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1231 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1232 else if(!strcmp(action, "stop")) a = action_Stop(a);
1233 else if(!strcmp(action, "play")) a = action_Play(a);
1234 a = action_SetTarget(a, "");
1237 tag = swf_InsertTag(tag, ST_DOACTION);
1238 swf_ActionSet(tag, a);
1243 void s_outline(char*name, char*format, char*source)
1252 swf_Shape11DrawerInit(&draw, 0);
1253 draw_string(&draw, source);
1255 shape = swf_ShapeDrawerToShape(&draw);
1256 bounds = swf_ShapeDrawerGetBBox(&draw);
1257 draw.dealloc(&draw);
1259 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1260 outline->shape = shape;
1261 outline->bbox = bounds;
1263 if(dictionary_lookup(&outlines, name))
1264 syntaxerror("outline %s defined twice", name);
1265 dictionary_put2(&outlines, name, outline);
1268 int s_playsound(char*name, int loops, int nomultiple, int stop)
1273 sound = dictionary_lookup(&sounds, name);
1278 tag = swf_InsertTag(tag, ST_STARTSOUND);
1279 swf_SetU16(tag, sound->id); //id
1280 memset(&info, 0, sizeof(info));
1283 info.nomultiple = nomultiple;
1284 swf_SetSoundInfo(tag, &info);
1288 void s_includeswf(char*name, char*filename)
1296 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1297 f = open(filename,O_RDONLY|O_BINARY);
1299 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1300 s_box(name, 0, 0, black, 20, 0);
1303 if (swf_ReadSWF(f,&swf)<0) {
1304 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1305 s_box(name, 0, 0, black, 20, 0);
1310 /* FIXME: The following sets the bounding Box for the character.
1311 It is wrong for two reasons:
1312 a) It may be too small (in case objects in the movie clip at the borders)
1313 b) it may be too big (because the poor movie never got autocropped)
1317 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1318 swf_SetU16(tag, id);
1321 swf_Relocate(&swf, idmap);
1323 ftag = swf.firstTag;
1327 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1328 if(cutout[t] == ftag->id) {
1332 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1334 if(ftag->id == ST_END)
1338 /* We simply dump all tags right after the sprite
1339 header, relying on the fact that swf_OptimizeTagOrder() will
1340 sort things out for us later.
1341 We also rely on the fact that the imported SWF is well-formed.
1343 tag = swf_InsertTag(tag, ftag->id);
1344 swf_SetBlock(tag, ftag->data, ftag->len);
1348 syntaxerror("Included file %s contains errors", filename);
1349 tag = swf_InsertTag(tag, ST_END);
1353 s_addcharacter(name, id, tag, r);
1356 SRECT s_getCharBBox(char*name)
1358 character_t* c = dictionary_lookup(&characters, name);
1359 if(!c) syntaxerror("character '%s' unknown(2)", name);
1362 SRECT s_getInstanceBBox(char*name)
1364 instance_t * i = dictionary_lookup(&instances, name);
1366 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1368 if(!c) syntaxerror("internal error(5)");
1371 parameters_t s_getParameters(char*name)
1373 instance_t * i = dictionary_lookup(&instances, name);
1374 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1375 return i->parameters;
1377 void s_startclip(char*instance, char*character, parameters_t p)
1379 character_t* c = dictionary_lookup(&characters, character);
1383 syntaxerror("character %s not known", character);
1385 i = s_addinstance(instance, c, currentdepth);
1387 m = s_instancepos(i->character->size, &p);
1389 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1390 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1391 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1393 i->lastFrame= currentframe;
1395 stack[stackpos].tag = tag;
1396 stack[stackpos].type = 2;
1405 swf_SetTagPos(stack[stackpos].tag, 0);
1406 swf_GetPlaceObject(stack[stackpos].tag, &p);
1407 p.clipdepth = currentdepth;
1409 swf_ClearTag(stack[stackpos].tag);
1410 swf_SetPlaceObject(stack[stackpos].tag, &p);
1414 void s_put(char*instance, char*character, parameters_t p)
1416 character_t* c = dictionary_lookup(&characters, character);
1420 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1423 i = s_addinstance(instance, c, currentdepth);
1425 m = s_instancepos(i->character->size, &p);
1427 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1428 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1430 i->lastFrame = currentframe;
1434 void s_jump(char*instance, parameters_t p)
1436 instance_t* i = dictionary_lookup(&instances, instance);
1439 syntaxerror("instance %s not known", instance);
1443 m = s_instancepos(i->character->size, &p);
1445 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1446 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1448 i->lastFrame = currentframe;
1451 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1455 if(num==0 || num==1)
1457 ratio = (float)pos/(float)num;
1459 p.x = (p2->x-p1->x)*ratio + p1->x;
1460 p.y = (p2->y-p1->y)*ratio + p1->y;
1461 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1462 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1463 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1464 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1466 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1467 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1468 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1469 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1471 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1472 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1473 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1474 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1476 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1477 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1478 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1479 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1483 void s_change(char*instance, parameters_t p2)
1485 instance_t* i = dictionary_lookup(&instances, instance);
1489 int frame, allframes;
1491 syntaxerror("instance %s not known", instance);
1495 allframes = currentframe - i->lastFrame - 1;
1497 warning(".change ignored. can only .put/.change an object once per frame.");
1501 m = s_instancepos(i->character->size, &p2);
1502 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1503 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1506 /* o.k., we got the start and end point set. Now iterate though all the
1507 tags in between, inserting object changes after each new frame */
1510 if(!t) syntaxerror("internal error(6)");
1512 while(frame < allframes) {
1513 if(t->id == ST_SHOWFRAME) {
1518 p = s_interpolate(&p1, &p2, frame, allframes);
1519 m = s_instancepos(i->character->size, &p); //needed?
1520 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1521 i->lastFrame = currentframe;
1522 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1524 if(frame == allframes)
1529 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1533 void s_delinstance(char*instance)
1535 instance_t* i = dictionary_lookup(&instances, instance);
1537 syntaxerror("instance %s not known", instance);
1539 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1540 swf_SetU16(tag, i->depth);
1541 dictionary_del(&instances, instance);
1544 void s_qchange(char*instance, parameters_t p)
1551 syntaxerror(".end unexpected");
1552 if(stack[stackpos-1].type == 0)
1554 else if(stack[stackpos-1].type == 1)
1556 else if(stack[stackpos-1].type == 2)
1558 else if(stack[stackpos-1].type == 3)
1560 else syntaxerror("internal error 1");
1563 // ------------------------------------------------------------------------
1565 typedef int command_func_t(map_t*args);
1567 SRECT parseBox(char*str)
1570 float xmin, xmax, ymin, ymax;
1571 char*x = strchr(str, 'x');
1573 if(!strcmp(str, "autocrop")) {
1574 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1578 d1 = strchr(x+1, ':');
1580 d2 = strchr(d1+1, ':');
1582 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1586 else if(d1 && !d2) {
1587 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1593 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1598 r.xmin = (SCOORD)(xmin*20);
1599 r.ymin = (SCOORD)(ymin*20);
1600 r.xmax = (SCOORD)(xmax*20);
1601 r.ymax = (SCOORD)(ymax*20);
1604 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1607 float parseFloat(char*str)
1611 int parseInt(char*str)
1616 if(str[0]=='+' || str[0]=='-')
1620 if(str[t]<'0' || str[t]>'9')
1621 syntaxerror("Not an Integer: \"%s\"", str);
1624 int parseTwip(char*str)
1628 if(str[0]=='+' || str[0]=='-') {
1633 dot = strchr(str, '.');
1637 return sign*parseInt(str)*20;
1639 int l=strlen(++dot);
1641 for(s=str;s<dot-1;s++)
1642 if(*s<'0' || *s>'9')
1643 syntaxerror("Not a coordinate: \"%s\"", str);
1645 if(*s<'0' || *s>'9')
1646 syntaxerror("Not a coordinate: \"%s\"", str);
1648 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
1649 warning("precision loss: %s converted to twip: %s", str, dot);
1654 return sign*atoi(str)*20;
1656 return sign*atoi(str)*20+atoi(dot)*2;
1658 return sign*atoi(str)*20+atoi(dot)/5;
1663 int isPoint(char*str)
1665 if(strchr(str, '('))
1671 SPOINT parsePoint(char*str)
1675 int l = strlen(str);
1676 char*comma = strchr(str, ',');
1677 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1678 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1679 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1680 p.x = parseTwip(tmp);
1681 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1682 p.y = parseTwip(tmp);
1686 int parseColor2(char*str, RGBA*color)
1688 int l = strlen(str);
1692 struct {unsigned char r,g,b;char*name;} colors[] =
1693 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1694 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1695 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1696 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1697 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1698 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1699 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1700 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1701 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1702 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1703 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1704 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1708 if(str[0]=='#' && (l==7 || l==9)) {
1709 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1711 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1713 color->r = r; color->g = g; color->b = b; color->a = a;
1716 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1717 if(!strcmp(str, colors[t].name)) {
1722 color->r = r; color->g = g; color->b = b; color->a = a;
1728 RGBA parseColor(char*str)
1731 if(!parseColor2(str, &c))
1732 syntaxerror("Expression '%s' is not a color", str);
1736 typedef struct _muladd {
1741 MULADD parseMulAdd(char*str)
1744 char* str2 = (char*)malloc(strlen(str)+5);
1751 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1752 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1753 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1754 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1755 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1756 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1757 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1758 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1759 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1760 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1762 syntaxerror("'%s' is not a valid color transform expression", str);
1764 m.add = (int)(add*256);
1765 m.mul = (int)(mul*256);
1770 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1772 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1773 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1775 if(a<-32768) a=-32768;
1776 if(a>32767) a=32767;
1777 if(m<-32768) m=-32768;
1778 if(m>32767) m=32767;
1784 float parsePercent(char*str)
1786 int l = strlen(str);
1790 return atoi(str)/100.0;
1792 syntaxerror("Expression '%s' is not a percentage", str);
1795 int isPercent(char*str)
1797 return str[strlen(str)-1]=='%';
1799 int parseNewSize(char*str, int size)
1802 return parsePercent(str)*size;
1804 return (int)(atof(str)*20);
1807 int isColor(char*str)
1810 return parseColor2(str, &c);
1813 static char* lu(map_t* args, char*name)
1815 char* value = map_lookup(args, name);
1817 map_dump(args, stdout, "");
1818 syntaxerror("internal error 2: value %s should be set", name);
1823 static int c_flash(map_t*args)
1825 char* filename = map_lookup(args, "filename");
1826 char* compressstr = lu(args, "compress");
1827 SRECT bbox = parseBox(lu(args, "bbox"));
1828 int version = parseInt(lu(args, "version"));
1829 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1831 RGBA color = parseColor(lu(args, "background"));
1833 if(!filename || !*filename) {
1834 /* for compatibility */
1835 filename = map_lookup(args, "name");
1836 if(!filename || !*filename) {
1839 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
1840 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
1844 if(!filename || override_outputname)
1845 filename = outputname;
1847 if(!strcmp(compressstr, "default"))
1848 compress = version==6;
1849 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1851 else if(!strcmp(compressstr, "no"))
1853 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1855 s_swf(filename, bbox, version, fps, compress, color);
1858 int isRelative(char*str)
1860 return !strncmp(str, "<plus>", 6) ||
1861 !strncmp(str, "<minus>", 7);
1863 char* getOffset(char*str)
1865 if(!strncmp(str, "<plus>", 6))
1867 if(!strncmp(str, "<minus>", 7))
1869 syntaxerror("internal error (347)");
1872 int getSign(char*str)
1874 if(!strncmp(str, "<plus>", 6))
1876 if(!strncmp(str, "<minus>", 7))
1878 syntaxerror("internal error (348)");
1881 static dictionary_t points;
1882 static mem_t mpoints;
1883 int points_initialized = 0;
1885 SPOINT getPoint(SRECT r, char*name)
1888 if(!strcmp(name, "center")) {
1890 p.x = (r.xmin + r.xmax)/2;
1891 p.y = (r.ymin + r.ymax)/2;
1895 if(points_initialized)
1896 l = (int)dictionary_lookup(&points, name);
1898 syntaxerror("Invalid point: \"%s\".", name);
1901 return *(SPOINT*)&mpoints.buffer[l];
1903 static int c_gradient(map_t*args)
1905 char*name = lu(args, "name");
1906 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1907 int rotate = parseInt(lu(args, "rotate"));
1911 syntaxerror("colon (:) expected");
1913 s_gradient(name, text, radial,rotate);
1916 static int c_point(map_t*args)
1918 char*name = lu(args, "name");
1922 if(!points_initialized) {
1923 dictionary_init(&points);
1925 points_initialized = 1;
1927 p.x = parseTwip(lu(args, "x"));
1928 p.y = parseTwip(lu(args, "y"));
1929 pos = mem_put(&mpoints, &p, sizeof(p));
1930 string_set(&s1, name);
1932 dictionary_put(&points, s1, (void*)pos);
1935 static int c_play(map_t*args)
1937 char*name = lu(args, "name");
1938 char*loop = lu(args, "loop");
1939 char*nomultiple = lu(args, "nomultiple");
1941 if(!strcmp(nomultiple, "nomultiple"))
1944 nm = parseInt(nomultiple);
1946 if(s_playsound(name, parseInt(loop), nm, 0)) {
1948 } else if(s_swf3action(name, "play")) {
1954 static int c_stop(map_t*args)
1956 char*name = map_lookup(args, "name");
1958 if(s_playsound(name, 0,0,1)) {
1960 } else if(s_swf3action(name, "stop")) {
1963 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
1967 static int c_nextframe(map_t*args)
1969 char*name = lu(args, "name");
1971 if(s_swf3action(name, "nextframe")) {
1974 syntaxerror("I don't know anything about movie \"%s\"", name);
1978 static int c_previousframe(map_t*args)
1980 char*name = lu(args, "name");
1982 if(s_swf3action(name, "previousframe")) {
1985 syntaxerror("I don't know anything about movie \"%s\"", name);
1989 static int c_placement(map_t*args, int type)
1991 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1994 char* luminancestr = lu(args, "luminance");
1995 char* scalestr = lu(args, "scale");
1996 char* scalexstr = lu(args, "scalex");
1997 char* scaleystr = lu(args, "scaley");
1998 char* rotatestr = lu(args, "rotate");
1999 char* shearstr = lu(args, "shear");
2000 char* xstr="", *pivotstr="";
2001 char* ystr="", *anglestr="";
2002 char*above = lu(args, "above"); /*FIXME*/
2003 char*below = lu(args, "below");
2004 char* rstr = lu(args, "red");
2005 char* gstr = lu(args, "green");
2006 char* bstr = lu(args, "blue");
2007 char* astr = lu(args, "alpha");
2008 char* pinstr = lu(args, "pin");
2009 char* as = map_lookup(args, "as");
2017 if(type==9) { // (?) .rotate or .arcchange
2018 pivotstr = lu(args, "pivot");
2019 anglestr = lu(args, "angle");
2021 xstr = lu(args, "x");
2022 ystr = lu(args, "y");
2025 luminance = parseMulAdd(luminancestr);
2028 luminance.mul = 256;
2032 if(scalexstr[0]||scaleystr[0])
2033 syntaxerror("scalex/scaley and scale cannot both be set");
2034 scalexstr = scaleystr = scalestr;
2037 if(type == 0 || type == 4) {
2039 character = lu(args, "character");
2040 parameters_clear(&p);
2041 } else if (type == 5) {
2042 character = lu(args, "name");
2043 parameters_clear(&p);
2046 p = s_getParameters(instance);
2051 if(isRelative(xstr)) {
2052 if(type == 0 || type == 4)
2053 syntaxerror("relative x values not allowed for initial put or startclip");
2054 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2056 p.x = parseTwip(xstr);
2060 if(isRelative(ystr)) {
2061 if(type == 0 || type == 4)
2062 syntaxerror("relative y values not allowed for initial put or startclip");
2063 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2065 p.y = parseTwip(ystr);
2069 /* scale, scalex, scaley */
2071 oldbbox = s_getCharBBox(character);
2073 oldbbox = s_getInstanceBBox(instance);
2075 oldwidth = oldbbox.xmax - oldbbox.xmin;
2076 oldheight = oldbbox.ymax - oldbbox.ymin;
2078 if(oldwidth==0) p.scalex = 1.0;
2081 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2085 if(oldheight==0) p.scaley = 1.0;
2088 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2094 if(isRelative(rotatestr)) {
2095 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2097 p.rotate = parseFloat(rotatestr);
2103 if(isRelative(shearstr)) {
2104 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2106 p.shear = parseFloat(shearstr);
2111 if(isPoint(pivotstr))
2112 p.pivot = parsePoint(pivotstr);
2114 p.pivot = getPoint(oldbbox, pivotstr);
2118 p.pin = parsePoint(pinstr);
2120 p.pin = getPoint(oldbbox, pinstr);
2123 /* color transform */
2125 if(rstr[0] || luminancestr[0]) {
2128 r = parseMulAdd(rstr);
2130 r.add = p.cxform.r0;
2131 r.mul = p.cxform.r1;
2133 r = mergeMulAdd(r, luminance);
2134 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2136 if(gstr[0] || luminancestr[0]) {
2139 g = parseMulAdd(gstr);
2141 g.add = p.cxform.g0;
2142 g.mul = p.cxform.g1;
2144 g = mergeMulAdd(g, luminance);
2145 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2147 if(bstr[0] || luminancestr[0]) {
2150 b = parseMulAdd(bstr);
2152 b.add = p.cxform.b0;
2153 b.mul = p.cxform.b1;
2155 b = mergeMulAdd(b, luminance);
2156 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2159 MULADD a = parseMulAdd(astr);
2160 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2164 s_put(instance, character, p);
2166 s_change(instance, p);
2168 s_qchange(instance, p);
2170 s_jump(instance, p);
2172 s_startclip(instance, character, p);
2173 else if(type == 5) {
2175 s_buttonput(character, as, p);
2177 s_buttonput(character, "shape", p);
2182 static int c_put(map_t*args)
2184 c_placement(args, 0);
2187 static int c_change(map_t*args)
2189 c_placement(args, 1);
2192 static int c_qchange(map_t*args)
2194 c_placement(args, 2);
2197 static int c_arcchange(map_t*args)
2199 c_placement(args, 2);
2202 static int c_jump(map_t*args)
2204 c_placement(args, 3);
2207 static int c_startclip(map_t*args)
2209 c_placement(args, 4);
2212 static int c_show(map_t*args)
2214 c_placement(args, 5);
2217 static int c_del(map_t*args)
2219 char*instance = lu(args, "name");
2220 s_delinstance(instance);
2223 static int c_end(map_t*args)
2228 static int c_sprite(map_t*args)
2230 char* name = lu(args, "name");
2234 static int c_frame(map_t*args)
2236 char*framestr = lu(args, "n");
2237 char*cutstr = lu(args, "cut");
2238 char*name = lu(args, "name");
2241 if(strcmp(cutstr, "no"))
2243 if(isRelative(framestr)) {
2244 frame = s_getframe();
2245 if(getSign(framestr)<0)
2246 syntaxerror("relative frame expressions must be positive");
2247 frame += parseInt(getOffset(framestr));
2250 frame = parseInt(framestr);
2251 if(s_getframe() >= frame
2252 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2253 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2255 s_frame(frame, cut, name);
2258 static int c_primitive(map_t*args)
2260 char*name = lu(args, "name");
2261 char*command = lu(args, "commandname");
2262 int width=0, height=0, r=0;
2263 int linewidth = parseTwip(lu(args, "line"));
2264 char*colorstr = lu(args, "color");
2265 RGBA color = parseColor(colorstr);
2266 char*fillstr = lu(args, "fill");
2273 if(!strcmp(command, "circle"))
2275 else if(!strcmp(command, "filled"))
2279 width = parseTwip(lu(args, "width"));
2280 height = parseTwip(lu(args, "height"));
2281 } else if (type==1) {
2282 r = parseTwip(lu(args, "r"));
2283 } else if (type==2) {
2284 outline = lu(args, "outline");
2287 if(!strcmp(fillstr, "fill"))
2289 if(!strcmp(fillstr, "none"))
2291 if(width<0 || height<0 || linewidth<0 || r<0)
2292 syntaxerror("values width, height, line, r must be positive");
2294 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2295 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2296 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2300 static int c_textshape(map_t*args)
2302 char*name = lu(args, "name");
2303 char*text = lu(args, "text");
2304 char*font = lu(args, "font");
2305 float size = parsePercent(lu(args, "size"));
2307 s_textshape(name, font, size, text);
2311 static int c_swf(map_t*args)
2313 char*name = lu(args, "name");
2314 char*filename = lu(args, "filename");
2315 char*command = lu(args, "commandname");
2316 if(!strcmp(command, "shape"))
2317 warning("Please use .swf instead of .shape");
2318 s_includeswf(name, filename);
2322 static int c_font(map_t*args)
2324 char*name = lu(args, "name");
2325 char*filename = lu(args, "filename");
2326 s_font(name, filename);
2330 static int c_sound(map_t*args)
2332 char*name = lu(args, "name");
2333 char*filename = lu(args, "filename");
2334 s_sound(name, filename);
2338 static int c_text(map_t*args)
2340 char*name = lu(args, "name");
2341 char*text = lu(args, "text");
2342 char*font = lu(args, "font");
2343 float size = parsePercent(lu(args, "size"));
2344 RGBA color = parseColor(lu(args, "color"));
2345 s_text(name, font, text, (int)(size*100), color);
2349 static int c_soundtrack(map_t*args)
2354 static int c_quicktime(map_t*args)
2356 char*name = lu(args, "name");
2357 char*url = lu(args, "url");
2358 s_quicktime(name, url);
2362 static int c_image(map_t*args)
2364 char*command = lu(args, "commandname");
2365 char*name = lu(args, "name");
2366 char*filename = lu(args, "filename");
2367 if(!strcmp(command,"jpeg")) {
2368 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2369 s_image(name, "jpeg", filename, quality);
2371 s_image(name, "png", filename, 0);
2376 static int c_outline(map_t*args)
2378 char*name = lu(args, "name");
2379 char*format = lu(args, "format");
2383 syntaxerror("colon (:) expected");
2385 s_outline(name, format, text);
2389 int fakechar(map_t*args)
2391 char*name = lu(args, "name");
2392 s_box(name, 0, 0, black, 20, 0);
2396 static int c_egon(map_t*args) {return fakechar(args);}
2397 static int c_button(map_t*args) {
2398 char*name = lu(args, "name");
2402 static int current_button_flags = 0;
2403 static int c_on_press(map_t*args)
2405 char*position = lu(args, "position");
2407 if(!strcmp(position, "inside")) {
2408 current_button_flags |= BC_OVERUP_OVERDOWN;
2409 } else if(!strcmp(position, "outside")) {
2410 //current_button_flags |= BC_IDLE_OUTDOWN;
2411 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2412 } else if(!strcmp(position, "anywhere")) {
2413 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2416 if(type == RAWDATA) {
2418 s_buttonaction(current_button_flags, action);
2419 current_button_flags = 0;
2425 static int c_on_release(map_t*args)
2427 char*position = lu(args, "position");
2429 if(!strcmp(position, "inside")) {
2430 current_button_flags |= BC_OVERDOWN_OVERUP;
2431 } else if(!strcmp(position, "outside")) {
2432 current_button_flags |= BC_OUTDOWN_IDLE;
2433 } else if(!strcmp(position, "anywhere")) {
2434 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2437 if(type == RAWDATA) {
2439 s_buttonaction(current_button_flags, action);
2440 current_button_flags = 0;
2446 static int c_on_move_in(map_t*args)
2448 char*position = lu(args, "state");
2450 if(!strcmp(position, "pressed")) {
2451 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2452 } else if(!strcmp(position, "not_pressed")) {
2453 current_button_flags |= BC_IDLE_OVERUP;
2454 } else if(!strcmp(position, "any")) {
2455 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2458 if(type == RAWDATA) {
2460 s_buttonaction(current_button_flags, action);
2461 current_button_flags = 0;
2467 static int c_on_move_out(map_t*args)
2469 char*position = lu(args, "state");
2471 if(!strcmp(position, "pressed")) {
2472 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2473 } else if(!strcmp(position, "not_pressed")) {
2474 current_button_flags |= BC_OVERUP_IDLE;
2475 } else if(!strcmp(position, "any")) {
2476 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2479 if(type == RAWDATA) {
2481 s_buttonaction(current_button_flags, action);
2482 current_button_flags = 0;
2488 static int c_on_key(map_t*args)
2490 char*key = lu(args, "key");
2492 if(strlen(key)==1) {
2495 current_button_flags |= 0x4000 + (key[0]*0x200);
2497 syntaxerror("invalid character: %c"+key[0]);
2502 <ctrl-x> = 0x200*(x-'a')
2506 syntaxerror("invalid key: %s",key);
2509 if(type == RAWDATA) {
2511 s_buttonaction(current_button_flags, action);
2512 current_button_flags = 0;
2519 static int c_edittext(map_t*args)
2521 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
2522 char*name = lu(args, "name");
2523 char*font = lu(args, "font");
2524 int size = (int)(1024*parsePercent(lu(args, "size")));
2525 int width = parseTwip(lu(args, "width"));
2526 int height = parseTwip(lu(args, "height"));
2527 char*text = lu(args, "text");
2528 RGBA color = parseColor(lu(args, "color"));
2529 int maxlength = parseInt(lu(args, "maxlength"));
2530 char*variable = lu(args, "variable");
2531 char*passwordstr = lu(args, "password");
2532 char*wordwrapstr = lu(args, "wordwrap");
2533 char*multilinestr = lu(args, "multiline");
2534 char*htmlstr = lu(args, "html");
2535 char*noselectstr = lu(args, "noselect");
2536 char*readonlystr = lu(args, "readonly");
2537 char*borderstr = lu(args, "border");
2540 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2541 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2542 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2543 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2544 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2545 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2546 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2548 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags);
2552 static int c_morphshape(map_t*args) {return fakechar(args);}
2553 static int c_movie(map_t*args) {return fakechar(args);}
2555 static int c_texture(map_t*args) {return 0;}
2557 static int c_action(map_t*args)
2559 char* filename = map_lookup(args, "filename");
2560 if(!filename ||!*filename) {
2562 if(type != RAWDATA) {
2563 syntaxerror("colon (:) expected");
2567 FILE*fi = fopen(filename, "rb");
2569 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
2572 fseek(fi, 0, SEEK_END);
2574 fseek(fi, 0, SEEK_SET);
2575 text = rfx_alloc(l+1);
2576 fread(text, l, 1, fi);
2588 command_func_t* func;
2591 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
2592 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2593 // "import" type stuff
2594 {"swf", c_swf, "name filename"},
2595 {"shape", c_swf, "name filename"},
2596 {"jpeg", c_image, "name filename quality=80%"},
2597 {"png", c_image, "name filename"},
2598 {"movie", c_movie, "name filename"},
2599 {"sound", c_sound, "name filename"},
2600 {"font", c_font, "name filename"},
2601 {"soundtrack", c_soundtrack, "filename"},
2602 {"quicktime", c_quicktime, "url"},
2604 // generators of primitives
2606 {"point", c_point, "name x=0 y=0"},
2607 {"gradient", c_gradient, "name @radial=0 rotate=0"},
2608 {"outline", c_outline, "name format=simple"},
2609 {"textshape", c_textshape, "name font size=100% text"},
2611 // character generators
2612 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2613 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2614 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2616 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2617 {"text", c_text, "name text font size=100% color=white"},
2618 {"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"},
2619 {"morphshape", c_morphshape, "name start end"},
2620 {"button", c_button, "name"},
2621 {"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="},
2622 {"on_press", c_on_press, "position=inside"},
2623 {"on_release", c_on_release, "position=anywhere"},
2624 {"on_move_in", c_on_move_in, "state=not_pressed"},
2625 {"on_move_out", c_on_move_out, "state=not_pressed"},
2626 {"on_key", c_on_key, "key=any"},
2629 {"play", c_play, "name loop=0 @nomultiple=0"},
2630 {"stop", c_stop, "name= "},
2631 {"nextframe", c_nextframe, "name"},
2632 {"previousframe", c_previousframe, "name"},
2634 // object placement tags
2635 {"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="},
2636 {"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="},
2637 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2638 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2639 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2640 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2641 {"del", c_del, "name"},
2642 // virtual object placement
2643 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2645 // commands which start a block
2646 //startclip (see above)
2647 {"sprite", c_sprite, "name"},
2648 {"action", c_action, "filename="},
2654 static map_t parseArguments(char*command, char*pattern)
2670 string_set(&t1, "commandname");
2671 string_set(&t2, command);
2672 map_put(&result, t1, t2);
2674 if(!pattern || !*pattern)
2681 if(!strncmp("<i> ", x, 3)) {
2683 if(type == COMMAND || type == RAWDATA) {
2685 syntaxerror("character name expected");
2687 name[pos].str = "instance";
2689 value[pos].str = text;
2690 value[pos].len = strlen(text);
2694 if(type == ASSIGNMENT)
2697 name[pos].str = "character";
2699 value[pos].str = text;
2700 value[pos].len = strlen(text);
2708 isboolean[pos] = (x[0] =='@');
2721 name[pos].len = d-x;
2726 name[pos].len = e-x;
2727 value[pos].str = e+1;
2728 value[pos].len = d-e-1;
2736 /* for(t=0;t<len;t++) {
2737 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2738 isboolean[t]?"(boolean)":"");
2743 if(type == RAWDATA || type == COMMAND) {
2748 // first, search for boolean arguments
2749 for(pos=0;pos<len;pos++)
2751 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2753 if(type == ASSIGNMENT)
2755 value[pos].str = text;
2756 value[pos].len = strlen(text);
2757 /*printf("setting boolean parameter %s (to %s)\n",
2758 strdup_n(name[pos], namelen[pos]),
2759 strdup_n(value[pos], valuelen[pos]));*/
2764 // second, search for normal arguments
2766 for(pos=0;pos<len;pos++)
2768 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2769 (type != ASSIGNMENT && !set[pos])) {
2771 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2773 if(type == ASSIGNMENT)
2776 value[pos].str = text;
2777 value[pos].len = strlen(text);
2779 printf("setting parameter %s (to %s)\n",
2780 strdup_n(name[pos].str, name[pos].len),
2781 strdup_n(value[pos].str, value[pos].len));
2787 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
2791 for(t=0;t<len;t++) {
2792 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2795 for(t=0;t<len;t++) {
2796 if(value[t].str && value[t].str[0] == '*') {
2797 //relative default- take value from some other parameter
2799 for(s=0;s<len;s++) {
2800 if(value[s].len == value[t].len-1 &&
2801 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2802 value[t].str = value[s].str;
2805 if(value[t].str == 0) {
2807 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2811 /* ok, now construct the dictionary from the parameters */
2815 map_put(&result, name[t], value[t]);
2819 static void parseArgumentsForCommand(char*command)
2824 msg("<verbose> parse Command: %s (line %d)", command, line);
2826 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2827 if(!strcmp(arguments[t].command, command)) {
2829 /* ugly hack- will be removed soon (once documentation and .sc generating
2830 utilities have been changed) */
2831 if(!strcmp(command, "swf") && !stackpos) {
2832 warning("Please use .flash instead of .swf- this will be mandatory soon");
2837 args = parseArguments(command, arguments[t].arguments);
2843 syntaxerror("command %s not known", command);
2845 // catch missing .flash directives at the beginning of a file
2846 if(strcmp(command, "flash") && !stackpos)
2848 syntaxerror("No movie defined- use .flash first");
2852 printf(".%s\n", command);fflush(stdout);
2853 map_dump(&args, stdout, "\t");fflush(stdout);
2856 (*arguments[nr].func)(&args);
2858 /*if(!strcmp(command, "button") ||
2859 !strcmp(command, "action")) {
2862 if(type == COMMAND) {
2863 if(!strcmp(text, "end"))
2877 int main (int argc,char ** argv)
2880 processargs(argc, argv);
2881 initLog(0,-1,0,0,-1,verbose);
2884 args_callback_usage(argv[0]);
2888 file = generateTokens(filename);
2890 printf("parser returned error.\n");
2896 while(!noMoreTokens()) {
2899 syntaxerror("command expected");
2900 parseArgumentsForCommand(text);