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;
1107 if(!readWAV(filename, &wav)) {
1108 warning("Couldn't read wav file \"%s\"", filename);
1112 convertWAV2mono(&wav, &wav2, 44100);
1113 samples = (U16*)wav2.data;
1114 numsamples = wav2.size/2;
1116 #ifdef WORDS_BIGENDIAN
1118 for(t=0;t<numsamples;t++) {
1119 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1124 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1125 swf_SetU16(tag, id); //id
1126 swf_SetSoundDefine(tag, samples, numsamples);
1128 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1132 if(dictionary_lookup(&sounds, name))
1133 syntaxerror("sound %s defined twice", name);
1134 dictionary_put2(&sounds, name, sound);
1142 static char* gradient_getToken(const char**p)
1146 while(**p && strchr(" \t\n\r", **p)) {
1150 while(**p && !strchr(" \t\n\r", **p)) {
1153 result = malloc((*p)-start+1);
1154 memcpy(result,start,(*p)-start+1);
1155 result[(*p)-start] = 0;
1159 float parsePercent(char*str);
1160 RGBA parseColor(char*str);
1162 GRADIENT parseGradient(const char*str)
1165 const char* p = str;
1166 memset(&gradient, 0, sizeof(GRADIENT));
1168 char*posstr,*colorstr;
1171 posstr = gradient_getToken(&p);
1174 pos = parsePercent(posstr);
1175 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1176 colorstr = gradient_getToken(&p);
1177 color = parseColor(colorstr);
1178 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1179 warning("gradient record too big- max size is 8, rest ignored");
1182 gradient.ratios[gradient.num] = (int)(pos*255.0);
1183 gradient.rgba[gradient.num] = color;
1191 void s_gradient(char*name, const char*text, int radial, int rotate)
1193 gradient_t* gradient;
1194 gradient = malloc(sizeof(gradient_t));
1195 memset(gradient, 0, sizeof(gradient_t));
1196 gradient->gradient = parseGradient(text);
1197 gradient->radial = radial;
1198 gradient->rotate = rotate;
1200 if(dictionary_lookup(&gradients, name))
1201 syntaxerror("gradient %s defined twice", name);
1202 dictionary_put2(&gradients, name, gradient);
1205 void s_action(const char*text)
1208 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1210 syntaxerror("Couldn't compile ActionScript");
1213 tag = swf_InsertTag(tag, ST_DOACTION);
1215 swf_ActionSet(tag, a);
1220 int s_swf3action(char*name, char*action)
1223 instance_t* object = 0;
1225 dictionary_lookup(&instances, name);
1226 if(!object && name && *name) {
1227 /* we have a name, but couldn't find it. Abort. */
1230 a = action_SetTarget(0, name);
1231 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1232 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1233 else if(!strcmp(action, "stop")) a = action_Stop(a);
1234 else if(!strcmp(action, "play")) a = action_Play(a);
1235 a = action_SetTarget(a, "");
1238 tag = swf_InsertTag(tag, ST_DOACTION);
1239 swf_ActionSet(tag, a);
1244 void s_outline(char*name, char*format, char*source)
1253 swf_Shape11DrawerInit(&draw, 0);
1254 draw_string(&draw, source);
1256 shape = swf_ShapeDrawerToShape(&draw);
1257 bounds = swf_ShapeDrawerGetBBox(&draw);
1258 draw.dealloc(&draw);
1260 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1261 outline->shape = shape;
1262 outline->bbox = bounds;
1264 if(dictionary_lookup(&outlines, name))
1265 syntaxerror("outline %s defined twice", name);
1266 dictionary_put2(&outlines, name, outline);
1269 int s_playsound(char*name, int loops, int nomultiple, int stop)
1274 sound = dictionary_lookup(&sounds, name);
1279 tag = swf_InsertTag(tag, ST_STARTSOUND);
1280 swf_SetU16(tag, sound->id); //id
1281 memset(&info, 0, sizeof(info));
1284 info.nomultiple = nomultiple;
1285 swf_SetSoundInfo(tag, &info);
1289 void s_includeswf(char*name, char*filename)
1297 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1298 f = open(filename,O_RDONLY|O_BINARY);
1300 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1301 s_box(name, 0, 0, black, 20, 0);
1304 if (swf_ReadSWF(f,&swf)<0) {
1305 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1306 s_box(name, 0, 0, black, 20, 0);
1311 /* FIXME: The following sets the bounding Box for the character.
1312 It is wrong for two reasons:
1313 a) It may be too small (in case objects in the movie clip at the borders)
1314 b) it may be too big (because the poor movie never got autocropped)
1318 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1319 swf_SetU16(tag, id);
1320 swf_SetU16(tag, swf.frameCount);
1322 swf_Relocate(&swf, idmap);
1324 ftag = swf.firstTag;
1328 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1329 if(cutout[t] == ftag->id) {
1333 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1335 if(ftag->id == ST_END)
1339 /* We simply dump all tags right after the sprite
1340 header, relying on the fact that swf_OptimizeTagOrder() will
1341 sort things out for us later.
1342 We also rely on the fact that the imported SWF is well-formed.
1344 tag = swf_InsertTag(tag, ftag->id);
1345 swf_SetBlock(tag, ftag->data, ftag->len);
1349 syntaxerror("Included file %s contains errors", filename);
1350 tag = swf_InsertTag(tag, ST_END);
1354 s_addcharacter(name, id, tag, r);
1357 SRECT s_getCharBBox(char*name)
1359 character_t* c = dictionary_lookup(&characters, name);
1360 if(!c) syntaxerror("character '%s' unknown(2)", name);
1363 SRECT s_getInstanceBBox(char*name)
1365 instance_t * i = dictionary_lookup(&instances, name);
1367 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1369 if(!c) syntaxerror("internal error(5)");
1372 parameters_t s_getParameters(char*name)
1374 instance_t * i = dictionary_lookup(&instances, name);
1375 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1376 return i->parameters;
1378 void s_startclip(char*instance, char*character, parameters_t p)
1380 character_t* c = dictionary_lookup(&characters, character);
1384 syntaxerror("character %s not known", character);
1386 i = s_addinstance(instance, c, currentdepth);
1388 m = s_instancepos(i->character->size, &p);
1390 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1391 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1392 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1394 i->lastFrame= currentframe;
1396 stack[stackpos].tag = tag;
1397 stack[stackpos].type = 2;
1406 swf_SetTagPos(stack[stackpos].tag, 0);
1407 swf_GetPlaceObject(stack[stackpos].tag, &p);
1408 p.clipdepth = currentdepth;
1410 swf_ClearTag(stack[stackpos].tag);
1411 swf_SetPlaceObject(stack[stackpos].tag, &p);
1415 void s_put(char*instance, char*character, parameters_t p)
1417 character_t* c = dictionary_lookup(&characters, character);
1421 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1424 i = s_addinstance(instance, c, currentdepth);
1426 m = s_instancepos(i->character->size, &p);
1428 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1429 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1431 i->lastFrame = currentframe;
1435 void s_jump(char*instance, parameters_t p)
1437 instance_t* i = dictionary_lookup(&instances, instance);
1440 syntaxerror("instance %s not known", instance);
1444 m = s_instancepos(i->character->size, &p);
1446 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1447 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1449 i->lastFrame = currentframe;
1452 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1456 if(num==0 || num==1)
1458 ratio = (float)pos/(float)num;
1460 p.x = (p2->x-p1->x)*ratio + p1->x;
1461 p.y = (p2->y-p1->y)*ratio + p1->y;
1462 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1463 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1464 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1465 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1467 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1468 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1469 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1470 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1472 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1473 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1474 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1475 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1477 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1478 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1479 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1480 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1484 void s_change(char*instance, parameters_t p2)
1486 instance_t* i = dictionary_lookup(&instances, instance);
1490 int frame, allframes;
1492 syntaxerror("instance %s not known", instance);
1496 allframes = currentframe - i->lastFrame - 1;
1498 warning(".change ignored. can only .put/.change an object once per frame.");
1502 m = s_instancepos(i->character->size, &p2);
1503 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1504 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1507 /* o.k., we got the start and end point set. Now iterate though all the
1508 tags in between, inserting object changes after each new frame */
1511 if(!t) syntaxerror("internal error(6)");
1513 while(frame < allframes) {
1514 if(t->id == ST_SHOWFRAME) {
1519 p = s_interpolate(&p1, &p2, frame, allframes);
1520 m = s_instancepos(i->character->size, &p); //needed?
1521 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1522 i->lastFrame = currentframe;
1523 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1525 if(frame == allframes)
1530 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1534 void s_delinstance(char*instance)
1536 instance_t* i = dictionary_lookup(&instances, instance);
1538 syntaxerror("instance %s not known", instance);
1540 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1541 swf_SetU16(tag, i->depth);
1542 dictionary_del(&instances, instance);
1545 void s_qchange(char*instance, parameters_t p)
1552 syntaxerror(".end unexpected");
1553 if(stack[stackpos-1].type == 0)
1555 else if(stack[stackpos-1].type == 1)
1557 else if(stack[stackpos-1].type == 2)
1559 else if(stack[stackpos-1].type == 3)
1561 else syntaxerror("internal error 1");
1564 // ------------------------------------------------------------------------
1566 typedef int command_func_t(map_t*args);
1568 SRECT parseBox(char*str)
1571 float xmin, xmax, ymin, ymax;
1572 char*x = strchr(str, 'x');
1574 if(!strcmp(str, "autocrop")) {
1575 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1579 d1 = strchr(x+1, ':');
1581 d2 = strchr(d1+1, ':');
1583 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1587 else if(d1 && !d2) {
1588 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1594 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1599 r.xmin = (SCOORD)(xmin*20);
1600 r.ymin = (SCOORD)(ymin*20);
1601 r.xmax = (SCOORD)(xmax*20);
1602 r.ymax = (SCOORD)(ymax*20);
1605 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1608 float parseFloat(char*str)
1612 int parseInt(char*str)
1617 if(str[0]=='+' || str[0]=='-')
1621 if(str[t]<'0' || str[t]>'9')
1622 syntaxerror("Not an Integer: \"%s\"", str);
1625 int parseTwip(char*str)
1629 if(str[0]=='+' || str[0]=='-') {
1634 dot = strchr(str, '.');
1638 return sign*parseInt(str)*20;
1640 int l=strlen(++dot);
1642 for(s=str;s<dot-1;s++)
1643 if(*s<'0' || *s>'9')
1644 syntaxerror("Not a coordinate: \"%s\"", str);
1646 if(*s<'0' || *s>'9')
1647 syntaxerror("Not a coordinate: \"%s\"", str);
1649 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
1650 warning("precision loss: %s converted to twip: %s", str, dot);
1655 return sign*atoi(str)*20;
1657 return sign*atoi(str)*20+atoi(dot)*2;
1659 return sign*atoi(str)*20+atoi(dot)/5;
1664 int isPoint(char*str)
1666 if(strchr(str, '('))
1672 SPOINT parsePoint(char*str)
1676 int l = strlen(str);
1677 char*comma = strchr(str, ',');
1678 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1679 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1680 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1681 p.x = parseTwip(tmp);
1682 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1683 p.y = parseTwip(tmp);
1687 int parseColor2(char*str, RGBA*color)
1689 int l = strlen(str);
1693 struct {unsigned char r,g,b;char*name;} colors[] =
1694 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1695 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1696 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1697 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1698 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1699 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1700 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1701 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1702 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1703 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1704 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1705 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1709 if(str[0]=='#' && (l==7 || l==9)) {
1710 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1712 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1714 color->r = r; color->g = g; color->b = b; color->a = a;
1717 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1718 if(!strcmp(str, colors[t].name)) {
1723 color->r = r; color->g = g; color->b = b; color->a = a;
1729 RGBA parseColor(char*str)
1732 if(!parseColor2(str, &c))
1733 syntaxerror("Expression '%s' is not a color", str);
1737 typedef struct _muladd {
1742 MULADD parseMulAdd(char*str)
1745 char* str2 = (char*)malloc(strlen(str)+5);
1752 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1753 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1754 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1755 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1756 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1757 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1758 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1759 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1760 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1761 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1763 syntaxerror("'%s' is not a valid color transform expression", str);
1765 m.add = (int)(add*256);
1766 m.mul = (int)(mul*256);
1771 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1773 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1774 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1776 if(a<-32768) a=-32768;
1777 if(a>32767) a=32767;
1778 if(m<-32768) m=-32768;
1779 if(m>32767) m=32767;
1785 float parsePercent(char*str)
1787 int l = strlen(str);
1791 return atoi(str)/100.0;
1793 syntaxerror("Expression '%s' is not a percentage", str);
1796 int isPercent(char*str)
1798 return str[strlen(str)-1]=='%';
1800 int parseNewSize(char*str, int size)
1803 return parsePercent(str)*size;
1805 return (int)(atof(str)*20);
1808 int isColor(char*str)
1811 return parseColor2(str, &c);
1814 static char* lu(map_t* args, char*name)
1816 char* value = map_lookup(args, name);
1818 map_dump(args, stdout, "");
1819 syntaxerror("internal error 2: value %s should be set", name);
1824 static int c_flash(map_t*args)
1826 char* filename = map_lookup(args, "filename");
1827 char* compressstr = lu(args, "compress");
1828 SRECT bbox = parseBox(lu(args, "bbox"));
1829 int version = parseInt(lu(args, "version"));
1830 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1832 RGBA color = parseColor(lu(args, "background"));
1834 if(!filename || !*filename) {
1835 /* for compatibility */
1836 filename = map_lookup(args, "name");
1837 if(!filename || !*filename) {
1840 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
1841 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
1845 if(!filename || override_outputname)
1846 filename = outputname;
1848 if(!strcmp(compressstr, "default"))
1849 compress = version==6;
1850 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1852 else if(!strcmp(compressstr, "no"))
1854 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1856 s_swf(filename, bbox, version, fps, compress, color);
1859 int isRelative(char*str)
1861 return !strncmp(str, "<plus>", 6) ||
1862 !strncmp(str, "<minus>", 7);
1864 char* getOffset(char*str)
1866 if(!strncmp(str, "<plus>", 6))
1868 if(!strncmp(str, "<minus>", 7))
1870 syntaxerror("internal error (347)");
1873 int getSign(char*str)
1875 if(!strncmp(str, "<plus>", 6))
1877 if(!strncmp(str, "<minus>", 7))
1879 syntaxerror("internal error (348)");
1882 static dictionary_t points;
1883 static mem_t mpoints;
1884 int points_initialized = 0;
1886 SPOINT getPoint(SRECT r, char*name)
1889 if(!strcmp(name, "center")) {
1891 p.x = (r.xmin + r.xmax)/2;
1892 p.y = (r.ymin + r.ymax)/2;
1896 if(points_initialized)
1897 l = (int)dictionary_lookup(&points, name);
1899 syntaxerror("Invalid point: \"%s\".", name);
1902 return *(SPOINT*)&mpoints.buffer[l];
1904 static int c_gradient(map_t*args)
1906 char*name = lu(args, "name");
1907 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1908 int rotate = parseInt(lu(args, "rotate"));
1912 syntaxerror("colon (:) expected");
1914 s_gradient(name, text, radial,rotate);
1917 static int c_point(map_t*args)
1919 char*name = lu(args, "name");
1923 if(!points_initialized) {
1924 dictionary_init(&points);
1926 points_initialized = 1;
1928 p.x = parseTwip(lu(args, "x"));
1929 p.y = parseTwip(lu(args, "y"));
1930 pos = mem_put(&mpoints, &p, sizeof(p));
1931 string_set(&s1, name);
1933 dictionary_put(&points, s1, (void*)pos);
1936 static int c_play(map_t*args)
1938 char*name = lu(args, "name");
1939 char*loop = lu(args, "loop");
1940 char*nomultiple = lu(args, "nomultiple");
1942 if(!strcmp(nomultiple, "nomultiple"))
1945 nm = parseInt(nomultiple);
1947 if(s_playsound(name, parseInt(loop), nm, 0)) {
1949 } else if(s_swf3action(name, "play")) {
1955 static int c_stop(map_t*args)
1957 char*name = map_lookup(args, "name");
1959 if(s_playsound(name, 0,0,1)) {
1961 } else if(s_swf3action(name, "stop")) {
1964 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
1968 static int c_nextframe(map_t*args)
1970 char*name = lu(args, "name");
1972 if(s_swf3action(name, "nextframe")) {
1975 syntaxerror("I don't know anything about movie \"%s\"", name);
1979 static int c_previousframe(map_t*args)
1981 char*name = lu(args, "name");
1983 if(s_swf3action(name, "previousframe")) {
1986 syntaxerror("I don't know anything about movie \"%s\"", name);
1990 static int c_placement(map_t*args, int type)
1992 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1995 char* luminancestr = lu(args, "luminance");
1996 char* scalestr = lu(args, "scale");
1997 char* scalexstr = lu(args, "scalex");
1998 char* scaleystr = lu(args, "scaley");
1999 char* rotatestr = lu(args, "rotate");
2000 char* shearstr = lu(args, "shear");
2001 char* xstr="", *pivotstr="";
2002 char* ystr="", *anglestr="";
2003 char*above = lu(args, "above"); /*FIXME*/
2004 char*below = lu(args, "below");
2005 char* rstr = lu(args, "red");
2006 char* gstr = lu(args, "green");
2007 char* bstr = lu(args, "blue");
2008 char* astr = lu(args, "alpha");
2009 char* pinstr = lu(args, "pin");
2010 char* as = map_lookup(args, "as");
2018 if(type==9) { // (?) .rotate or .arcchange
2019 pivotstr = lu(args, "pivot");
2020 anglestr = lu(args, "angle");
2022 xstr = lu(args, "x");
2023 ystr = lu(args, "y");
2026 luminance = parseMulAdd(luminancestr);
2029 luminance.mul = 256;
2033 if(scalexstr[0]||scaleystr[0])
2034 syntaxerror("scalex/scaley and scale cannot both be set");
2035 scalexstr = scaleystr = scalestr;
2038 if(type == 0 || type == 4) {
2040 character = lu(args, "character");
2041 parameters_clear(&p);
2042 } else if (type == 5) {
2043 character = lu(args, "name");
2044 parameters_clear(&p);
2047 p = s_getParameters(instance);
2052 if(isRelative(xstr)) {
2053 if(type == 0 || type == 4)
2054 syntaxerror("relative x values not allowed for initial put or startclip");
2055 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2057 p.x = parseTwip(xstr);
2061 if(isRelative(ystr)) {
2062 if(type == 0 || type == 4)
2063 syntaxerror("relative y values not allowed for initial put or startclip");
2064 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2066 p.y = parseTwip(ystr);
2070 /* scale, scalex, scaley */
2072 oldbbox = s_getCharBBox(character);
2074 oldbbox = s_getInstanceBBox(instance);
2076 oldwidth = oldbbox.xmax - oldbbox.xmin;
2077 oldheight = oldbbox.ymax - oldbbox.ymin;
2079 if(oldwidth==0) p.scalex = 1.0;
2082 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2086 if(oldheight==0) p.scaley = 1.0;
2089 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2095 if(isRelative(rotatestr)) {
2096 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2098 p.rotate = parseFloat(rotatestr);
2104 if(isRelative(shearstr)) {
2105 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2107 p.shear = parseFloat(shearstr);
2112 if(isPoint(pivotstr))
2113 p.pivot = parsePoint(pivotstr);
2115 p.pivot = getPoint(oldbbox, pivotstr);
2119 p.pin = parsePoint(pinstr);
2121 p.pin = getPoint(oldbbox, pinstr);
2124 /* color transform */
2126 if(rstr[0] || luminancestr[0]) {
2129 r = parseMulAdd(rstr);
2131 r.add = p.cxform.r0;
2132 r.mul = p.cxform.r1;
2134 r = mergeMulAdd(r, luminance);
2135 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2137 if(gstr[0] || luminancestr[0]) {
2140 g = parseMulAdd(gstr);
2142 g.add = p.cxform.g0;
2143 g.mul = p.cxform.g1;
2145 g = mergeMulAdd(g, luminance);
2146 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2148 if(bstr[0] || luminancestr[0]) {
2151 b = parseMulAdd(bstr);
2153 b.add = p.cxform.b0;
2154 b.mul = p.cxform.b1;
2156 b = mergeMulAdd(b, luminance);
2157 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2160 MULADD a = parseMulAdd(astr);
2161 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2165 s_put(instance, character, p);
2167 s_change(instance, p);
2169 s_qchange(instance, p);
2171 s_jump(instance, p);
2173 s_startclip(instance, character, p);
2174 else if(type == 5) {
2176 s_buttonput(character, as, p);
2178 s_buttonput(character, "shape", p);
2183 static int c_put(map_t*args)
2185 c_placement(args, 0);
2188 static int c_change(map_t*args)
2190 c_placement(args, 1);
2193 static int c_qchange(map_t*args)
2195 c_placement(args, 2);
2198 static int c_arcchange(map_t*args)
2200 c_placement(args, 2);
2203 static int c_jump(map_t*args)
2205 c_placement(args, 3);
2208 static int c_startclip(map_t*args)
2210 c_placement(args, 4);
2213 static int c_show(map_t*args)
2215 c_placement(args, 5);
2218 static int c_del(map_t*args)
2220 char*instance = lu(args, "name");
2221 s_delinstance(instance);
2224 static int c_end(map_t*args)
2229 static int c_sprite(map_t*args)
2231 char* name = lu(args, "name");
2235 static int c_frame(map_t*args)
2237 char*framestr = lu(args, "n");
2238 char*cutstr = lu(args, "cut");
2239 char*name = lu(args, "name");
2242 if(strcmp(cutstr, "no"))
2244 if(isRelative(framestr)) {
2245 frame = s_getframe();
2246 if(getSign(framestr)<0)
2247 syntaxerror("relative frame expressions must be positive");
2248 frame += parseInt(getOffset(framestr));
2251 frame = parseInt(framestr);
2252 if(s_getframe() >= frame
2253 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2254 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2256 s_frame(frame, cut, name);
2259 static int c_primitive(map_t*args)
2261 char*name = lu(args, "name");
2262 char*command = lu(args, "commandname");
2263 int width=0, height=0, r=0;
2264 int linewidth = parseTwip(lu(args, "line"));
2265 char*colorstr = lu(args, "color");
2266 RGBA color = parseColor(colorstr);
2267 char*fillstr = lu(args, "fill");
2274 if(!strcmp(command, "circle"))
2276 else if(!strcmp(command, "filled"))
2280 width = parseTwip(lu(args, "width"));
2281 height = parseTwip(lu(args, "height"));
2282 } else if (type==1) {
2283 r = parseTwip(lu(args, "r"));
2284 } else if (type==2) {
2285 outline = lu(args, "outline");
2288 if(!strcmp(fillstr, "fill"))
2290 if(!strcmp(fillstr, "none"))
2292 if(width<0 || height<0 || linewidth<0 || r<0)
2293 syntaxerror("values width, height, line, r must be positive");
2295 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2296 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2297 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2301 static int c_textshape(map_t*args)
2303 char*name = lu(args, "name");
2304 char*text = lu(args, "text");
2305 char*font = lu(args, "font");
2306 float size = parsePercent(lu(args, "size"));
2308 s_textshape(name, font, size, text);
2312 static int c_swf(map_t*args)
2314 char*name = lu(args, "name");
2315 char*filename = lu(args, "filename");
2316 char*command = lu(args, "commandname");
2317 if(!strcmp(command, "shape"))
2318 warning("Please use .swf instead of .shape");
2319 s_includeswf(name, filename);
2323 static int c_font(map_t*args)
2325 char*name = lu(args, "name");
2326 char*filename = lu(args, "filename");
2327 s_font(name, filename);
2331 static int c_sound(map_t*args)
2333 char*name = lu(args, "name");
2334 char*filename = lu(args, "filename");
2335 s_sound(name, filename);
2339 static int c_text(map_t*args)
2341 char*name = lu(args, "name");
2342 char*text = lu(args, "text");
2343 char*font = lu(args, "font");
2344 float size = parsePercent(lu(args, "size"));
2345 RGBA color = parseColor(lu(args, "color"));
2346 s_text(name, font, text, (int)(size*100), color);
2350 static int c_soundtrack(map_t*args)
2355 static int c_quicktime(map_t*args)
2357 char*name = lu(args, "name");
2358 char*url = lu(args, "url");
2359 s_quicktime(name, url);
2363 static int c_image(map_t*args)
2365 char*command = lu(args, "commandname");
2366 char*name = lu(args, "name");
2367 char*filename = lu(args, "filename");
2368 if(!strcmp(command,"jpeg")) {
2369 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2370 s_image(name, "jpeg", filename, quality);
2372 s_image(name, "png", filename, 0);
2377 static int c_outline(map_t*args)
2379 char*name = lu(args, "name");
2380 char*format = lu(args, "format");
2384 syntaxerror("colon (:) expected");
2386 s_outline(name, format, text);
2390 int fakechar(map_t*args)
2392 char*name = lu(args, "name");
2393 s_box(name, 0, 0, black, 20, 0);
2397 static int c_egon(map_t*args) {return fakechar(args);}
2398 static int c_button(map_t*args) {
2399 char*name = lu(args, "name");
2403 static int current_button_flags = 0;
2404 static int c_on_press(map_t*args)
2406 char*position = lu(args, "position");
2408 if(!strcmp(position, "inside")) {
2409 current_button_flags |= BC_OVERUP_OVERDOWN;
2410 } else if(!strcmp(position, "outside")) {
2411 //current_button_flags |= BC_IDLE_OUTDOWN;
2412 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2413 } else if(!strcmp(position, "anywhere")) {
2414 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2417 if(type == RAWDATA) {
2419 s_buttonaction(current_button_flags, action);
2420 current_button_flags = 0;
2426 static int c_on_release(map_t*args)
2428 char*position = lu(args, "position");
2430 if(!strcmp(position, "inside")) {
2431 current_button_flags |= BC_OVERDOWN_OVERUP;
2432 } else if(!strcmp(position, "outside")) {
2433 current_button_flags |= BC_OUTDOWN_IDLE;
2434 } else if(!strcmp(position, "anywhere")) {
2435 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2438 if(type == RAWDATA) {
2440 s_buttonaction(current_button_flags, action);
2441 current_button_flags = 0;
2447 static int c_on_move_in(map_t*args)
2449 char*position = lu(args, "state");
2451 if(!strcmp(position, "pressed")) {
2452 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2453 } else if(!strcmp(position, "not_pressed")) {
2454 current_button_flags |= BC_IDLE_OVERUP;
2455 } else if(!strcmp(position, "any")) {
2456 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2459 if(type == RAWDATA) {
2461 s_buttonaction(current_button_flags, action);
2462 current_button_flags = 0;
2468 static int c_on_move_out(map_t*args)
2470 char*position = lu(args, "state");
2472 if(!strcmp(position, "pressed")) {
2473 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2474 } else if(!strcmp(position, "not_pressed")) {
2475 current_button_flags |= BC_OVERUP_IDLE;
2476 } else if(!strcmp(position, "any")) {
2477 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2480 if(type == RAWDATA) {
2482 s_buttonaction(current_button_flags, action);
2483 current_button_flags = 0;
2489 static int c_on_key(map_t*args)
2491 char*key = lu(args, "key");
2493 if(strlen(key)==1) {
2496 current_button_flags |= 0x4000 + (key[0]*0x200);
2498 syntaxerror("invalid character: %c"+key[0]);
2503 <ctrl-x> = 0x200*(x-'a')
2507 syntaxerror("invalid key: %s",key);
2510 if(type == RAWDATA) {
2512 s_buttonaction(current_button_flags, action);
2513 current_button_flags = 0;
2520 static int c_edittext(map_t*args)
2522 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
2523 char*name = lu(args, "name");
2524 char*font = lu(args, "font");
2525 int size = (int)(1024*parsePercent(lu(args, "size")));
2526 int width = parseTwip(lu(args, "width"));
2527 int height = parseTwip(lu(args, "height"));
2528 char*text = lu(args, "text");
2529 RGBA color = parseColor(lu(args, "color"));
2530 int maxlength = parseInt(lu(args, "maxlength"));
2531 char*variable = lu(args, "variable");
2532 char*passwordstr = lu(args, "password");
2533 char*wordwrapstr = lu(args, "wordwrap");
2534 char*multilinestr = lu(args, "multiline");
2535 char*htmlstr = lu(args, "html");
2536 char*noselectstr = lu(args, "noselect");
2537 char*readonlystr = lu(args, "readonly");
2538 char*borderstr = lu(args, "border");
2541 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2542 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2543 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2544 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2545 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2546 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2547 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2549 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags);
2553 static int c_morphshape(map_t*args) {return fakechar(args);}
2554 static int c_movie(map_t*args) {return fakechar(args);}
2556 static int c_texture(map_t*args) {return 0;}
2558 static int c_action(map_t*args)
2560 char* filename = map_lookup(args, "filename");
2561 if(!filename ||!*filename) {
2563 if(type != RAWDATA) {
2564 syntaxerror("colon (:) expected");
2568 FILE*fi = fopen(filename, "rb");
2570 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
2573 fseek(fi, 0, SEEK_END);
2575 fseek(fi, 0, SEEK_SET);
2576 text = rfx_alloc(l+1);
2577 fread(text, l, 1, fi);
2589 command_func_t* func;
2592 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
2593 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2594 // "import" type stuff
2595 {"swf", c_swf, "name filename"},
2596 {"shape", c_swf, "name filename"},
2597 {"jpeg", c_image, "name filename quality=80%"},
2598 {"png", c_image, "name filename"},
2599 {"movie", c_movie, "name filename"},
2600 {"sound", c_sound, "name filename"},
2601 {"font", c_font, "name filename"},
2602 {"soundtrack", c_soundtrack, "filename"},
2603 {"quicktime", c_quicktime, "url"},
2605 // generators of primitives
2607 {"point", c_point, "name x=0 y=0"},
2608 {"gradient", c_gradient, "name @radial=0 rotate=0"},
2609 {"outline", c_outline, "name format=simple"},
2610 {"textshape", c_textshape, "name font size=100% text"},
2612 // character generators
2613 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2614 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2615 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2617 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2618 {"text", c_text, "name text font size=100% color=white"},
2619 {"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"},
2620 {"morphshape", c_morphshape, "name start end"},
2621 {"button", c_button, "name"},
2622 {"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="},
2623 {"on_press", c_on_press, "position=inside"},
2624 {"on_release", c_on_release, "position=anywhere"},
2625 {"on_move_in", c_on_move_in, "state=not_pressed"},
2626 {"on_move_out", c_on_move_out, "state=not_pressed"},
2627 {"on_key", c_on_key, "key=any"},
2630 {"play", c_play, "name loop=0 @nomultiple=0"},
2631 {"stop", c_stop, "name= "},
2632 {"nextframe", c_nextframe, "name"},
2633 {"previousframe", c_previousframe, "name"},
2635 // object placement tags
2636 {"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="},
2637 {"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="},
2638 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2639 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2640 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2641 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2642 {"del", c_del, "name"},
2643 // virtual object placement
2644 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2646 // commands which start a block
2647 //startclip (see above)
2648 {"sprite", c_sprite, "name"},
2649 {"action", c_action, "filename="},
2655 static map_t parseArguments(char*command, char*pattern)
2671 string_set(&t1, "commandname");
2672 string_set(&t2, command);
2673 map_put(&result, t1, t2);
2675 if(!pattern || !*pattern)
2682 if(!strncmp("<i> ", x, 3)) {
2684 if(type == COMMAND || type == RAWDATA) {
2686 syntaxerror("character name expected");
2688 name[pos].str = "instance";
2690 value[pos].str = text;
2691 value[pos].len = strlen(text);
2695 if(type == ASSIGNMENT)
2698 name[pos].str = "character";
2700 value[pos].str = text;
2701 value[pos].len = strlen(text);
2709 isboolean[pos] = (x[0] =='@');
2722 name[pos].len = d-x;
2727 name[pos].len = e-x;
2728 value[pos].str = e+1;
2729 value[pos].len = d-e-1;
2737 /* for(t=0;t<len;t++) {
2738 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2739 isboolean[t]?"(boolean)":"");
2744 if(type == RAWDATA || type == COMMAND) {
2749 // first, search for boolean arguments
2750 for(pos=0;pos<len;pos++)
2752 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2754 if(type == ASSIGNMENT)
2756 value[pos].str = text;
2757 value[pos].len = strlen(text);
2758 /*printf("setting boolean parameter %s (to %s)\n",
2759 strdup_n(name[pos], namelen[pos]),
2760 strdup_n(value[pos], valuelen[pos]));*/
2765 // second, search for normal arguments
2767 for(pos=0;pos<len;pos++)
2769 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2770 (type != ASSIGNMENT && !set[pos])) {
2772 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2774 if(type == ASSIGNMENT)
2777 value[pos].str = text;
2778 value[pos].len = strlen(text);
2780 printf("setting parameter %s (to %s)\n",
2781 strdup_n(name[pos].str, name[pos].len),
2782 strdup_n(value[pos].str, value[pos].len));
2788 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
2792 for(t=0;t<len;t++) {
2793 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2796 for(t=0;t<len;t++) {
2797 if(value[t].str && value[t].str[0] == '*') {
2798 //relative default- take value from some other parameter
2800 for(s=0;s<len;s++) {
2801 if(value[s].len == value[t].len-1 &&
2802 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2803 value[t].str = value[s].str;
2806 if(value[t].str == 0) {
2808 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2812 /* ok, now construct the dictionary from the parameters */
2816 map_put(&result, name[t], value[t]);
2820 static void parseArgumentsForCommand(char*command)
2825 msg("<verbose> parse Command: %s (line %d)", command, line);
2827 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2828 if(!strcmp(arguments[t].command, command)) {
2830 /* ugly hack- will be removed soon (once documentation and .sc generating
2831 utilities have been changed) */
2832 if(!strcmp(command, "swf") && !stackpos) {
2833 warning("Please use .flash instead of .swf- this will be mandatory soon");
2838 args = parseArguments(command, arguments[t].arguments);
2844 syntaxerror("command %s not known", command);
2846 // catch missing .flash directives at the beginning of a file
2847 if(strcmp(command, "flash") && !stackpos)
2849 syntaxerror("No movie defined- use .flash first");
2853 printf(".%s\n", command);fflush(stdout);
2854 map_dump(&args, stdout, "\t");fflush(stdout);
2857 (*arguments[nr].func)(&args);
2859 /*if(!strcmp(command, "button") ||
2860 !strcmp(command, "action")) {
2863 if(type == COMMAND) {
2864 if(!strcmp(text, "end"))
2878 int main (int argc,char ** argv)
2881 processargs(argc, argv);
2882 initLog(0,-1,0,0,-1,verbose);
2885 args_callback_usage(argv[0]);
2889 file = generateTokens(filename);
2891 printf("parser returned error.\n");
2897 while(!noMoreTokens()) {
2900 syntaxerror("command expected");
2901 parseArgumentsForCommand(text);