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 if(fontname && *fontname) {
975 flags |= ET_USEOUTLINES;
976 font = dictionary_lookup(&fonts, fontname);
978 syntaxerror("font \"%s\" not known!", fontname);
980 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
983 layout.leftmargin = 0;
984 layout.rightmargin = 0;
992 swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
994 s_addcharacter(name, id, tag, r);
998 /* type: either "jpeg" or "png"
1000 void s_image(char*name, char*type, char*filename, int quality)
1002 /* an image is actually two folded: 1st bitmap, 2nd character.
1003 Both of them can be used separately */
1005 /* step 1: the bitmap */
1010 warning("image type \"png\" not supported yet!");
1011 s_box(name, 0, 0, black, 20, 0);
1015 #ifndef HAVE_LIBJPEG
1016 warning("no jpeg support compiled in");
1017 s_box(name, 0, 0, black, 20, 0);
1020 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
1021 swf_SetU16(tag, imageID);
1023 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
1024 syntaxerror("Image \"%s\" not found, or contains errors", filename);
1027 swf_GetJPEGSize(filename, &width, &height);
1034 s_addimage(name, id, tag, r);
1039 /* step 2: the character */
1040 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1041 swf_SetU16(tag, id);
1042 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1044 s_addcharacter(name, id, tag, r);
1048 void dumpSWF(SWF*swf)
1050 TAG* tag = swf->firstTag;
1051 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1053 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1056 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1059 void s_font(char*name, char*filename)
1062 font = swf_LoadFont(filename);
1065 warning("Couldn't open font file \"%s\"", filename);
1066 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1067 memset(font, 0, sizeof(SWFFONT));
1068 dictionary_put2(&fonts, name, font);
1074 /* fix the layout. Only needed for old fonts */
1076 for(t=0;t<font->numchars;t++) {
1077 font->glyph[t].advance = 0;
1080 swf_FontCreateLayout(font);
1082 /* just in case this thing is used in .edittext later on */
1083 swf_FontPrepareForEditText(font);
1086 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1087 swf_FontSetDefine2(tag, font);
1090 if(dictionary_lookup(&fonts, name))
1091 syntaxerror("font %s defined twice", name);
1092 dictionary_put2(&fonts, name, font);
1097 typedef struct _sound_t
1103 void s_sound(char*name, char*filename)
1105 struct WAV wav, wav2;
1111 if(!readWAV(filename, &wav)) {
1112 warning("Couldn't read wav file \"%s\"", filename);
1116 convertWAV2mono(&wav, &wav2, 44100);
1117 samples = (U16*)wav2.data;
1118 numsamples = wav2.size/2;
1120 #ifdef WORDS_BIGENDIAN
1122 for(t=0;t<numsamples;t++) {
1123 samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
1128 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1129 swf_SetU16(tag, id); //id
1130 swf_SetSoundDefine(tag, samples, numsamples);
1132 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1136 if(dictionary_lookup(&sounds, name))
1137 syntaxerror("sound %s defined twice", name);
1138 dictionary_put2(&sounds, name, sound);
1146 static char* gradient_getToken(const char**p)
1150 while(**p && strchr(" \t\n\r", **p)) {
1154 while(**p && !strchr(" \t\n\r", **p)) {
1157 result = malloc((*p)-start+1);
1158 memcpy(result,start,(*p)-start+1);
1159 result[(*p)-start] = 0;
1163 float parsePercent(char*str);
1164 RGBA parseColor(char*str);
1166 GRADIENT parseGradient(const char*str)
1169 const char* p = str;
1170 memset(&gradient, 0, sizeof(GRADIENT));
1172 char*posstr,*colorstr;
1175 posstr = gradient_getToken(&p);
1178 pos = parsePercent(posstr);
1179 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1180 colorstr = gradient_getToken(&p);
1181 color = parseColor(colorstr);
1182 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1183 warning("gradient record too big- max size is 8, rest ignored");
1186 gradient.ratios[gradient.num] = (int)(pos*255.0);
1187 gradient.rgba[gradient.num] = color;
1195 void s_gradient(char*name, const char*text, int radial, int rotate)
1197 gradient_t* gradient;
1198 gradient = malloc(sizeof(gradient_t));
1199 memset(gradient, 0, sizeof(gradient_t));
1200 gradient->gradient = parseGradient(text);
1201 gradient->radial = radial;
1202 gradient->rotate = rotate;
1204 if(dictionary_lookup(&gradients, name))
1205 syntaxerror("gradient %s defined twice", name);
1206 dictionary_put2(&gradients, name, gradient);
1209 void s_action(const char*text)
1212 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1214 syntaxerror("Couldn't compile ActionScript");
1217 tag = swf_InsertTag(tag, ST_DOACTION);
1219 swf_ActionSet(tag, a);
1224 int s_swf3action(char*name, char*action)
1227 instance_t* object = 0;
1229 dictionary_lookup(&instances, name);
1230 if(!object && name && *name) {
1231 /* we have a name, but couldn't find it. Abort. */
1234 a = action_SetTarget(0, name);
1235 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1236 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1237 else if(!strcmp(action, "stop")) a = action_Stop(a);
1238 else if(!strcmp(action, "play")) a = action_Play(a);
1239 a = action_SetTarget(a, "");
1242 tag = swf_InsertTag(tag, ST_DOACTION);
1243 swf_ActionSet(tag, a);
1248 void s_outline(char*name, char*format, char*source)
1257 swf_Shape11DrawerInit(&draw, 0);
1258 draw_string(&draw, source);
1260 shape = swf_ShapeDrawerToShape(&draw);
1261 bounds = swf_ShapeDrawerGetBBox(&draw);
1262 draw.dealloc(&draw);
1264 outline = (outline_t*)rfx_calloc(sizeof(outline_t));
1265 outline->shape = shape;
1266 outline->bbox = bounds;
1268 if(dictionary_lookup(&outlines, name))
1269 syntaxerror("outline %s defined twice", name);
1270 dictionary_put2(&outlines, name, outline);
1273 int s_playsound(char*name, int loops, int nomultiple, int stop)
1279 sound = dictionary_lookup(&sounds, name);
1283 tag = swf_InsertTag(tag, ST_STARTSOUND);
1284 swf_SetU16(tag, sound->id); //id
1285 memset(&info, 0, sizeof(info));
1288 info.nomultiple = nomultiple;
1289 swf_SetSoundInfo(tag, &info);
1293 void s_includeswf(char*name, char*filename)
1301 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1302 f = open(filename,O_RDONLY|O_BINARY);
1304 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1305 s_box(name, 0, 0, black, 20, 0);
1308 if (swf_ReadSWF(f,&swf)<0) {
1309 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1310 s_box(name, 0, 0, black, 20, 0);
1315 /* FIXME: The following sets the bounding Box for the character.
1316 It is wrong for two reasons:
1317 a) It may be too small (in case objects in the movie clip at the borders)
1318 b) it may be too big (because the poor movie never got autocropped)
1322 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1323 swf_SetU16(tag, id);
1324 swf_SetU16(tag, swf.frameCount);
1326 swf_Relocate(&swf, idmap);
1328 ftag = swf.firstTag;
1332 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1333 if(cutout[t] == ftag->id) {
1337 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1339 if(ftag->id == ST_END)
1343 /* We simply dump all tags right after the sprite
1344 header, relying on the fact that swf_OptimizeTagOrder() will
1345 sort things out for us later.
1346 We also rely on the fact that the imported SWF is well-formed.
1348 tag = swf_InsertTag(tag, ftag->id);
1349 swf_SetBlock(tag, ftag->data, ftag->len);
1353 syntaxerror("Included file %s contains errors", filename);
1354 tag = swf_InsertTag(tag, ST_END);
1358 s_addcharacter(name, id, tag, r);
1361 SRECT s_getCharBBox(char*name)
1363 character_t* c = dictionary_lookup(&characters, name);
1364 if(!c) syntaxerror("character '%s' unknown(2)", name);
1367 SRECT s_getInstanceBBox(char*name)
1369 instance_t * i = dictionary_lookup(&instances, name);
1371 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1373 if(!c) syntaxerror("internal error(5)");
1376 parameters_t s_getParameters(char*name)
1378 instance_t * i = dictionary_lookup(&instances, name);
1379 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1380 return i->parameters;
1382 void s_startclip(char*instance, char*character, parameters_t p)
1384 character_t* c = dictionary_lookup(&characters, character);
1388 syntaxerror("character %s not known", character);
1390 i = s_addinstance(instance, c, currentdepth);
1392 m = s_instancepos(i->character->size, &p);
1394 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1395 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1396 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1398 i->lastFrame= currentframe;
1400 stack[stackpos].tag = tag;
1401 stack[stackpos].type = 2;
1410 swf_SetTagPos(stack[stackpos].tag, 0);
1411 swf_GetPlaceObject(stack[stackpos].tag, &p);
1412 p.clipdepth = currentdepth;
1414 swf_ClearTag(stack[stackpos].tag);
1415 swf_SetPlaceObject(stack[stackpos].tag, &p);
1419 void s_put(char*instance, char*character, parameters_t p)
1421 character_t* c = dictionary_lookup(&characters, character);
1425 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1428 i = s_addinstance(instance, c, currentdepth);
1430 m = s_instancepos(i->character->size, &p);
1432 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1433 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1435 i->lastFrame = currentframe;
1439 void s_jump(char*instance, parameters_t p)
1441 instance_t* i = dictionary_lookup(&instances, instance);
1444 syntaxerror("instance %s not known", instance);
1448 m = s_instancepos(i->character->size, &p);
1450 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1451 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1453 i->lastFrame = currentframe;
1456 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1460 if(num==0 || num==1)
1462 ratio = (float)pos/(float)num;
1464 p.x = (p2->x-p1->x)*ratio + p1->x;
1465 p.y = (p2->y-p1->y)*ratio + p1->y;
1466 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1467 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1468 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1469 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1471 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1472 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1473 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1474 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1476 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1477 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1478 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1479 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1481 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1482 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1483 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1484 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1488 void s_change(char*instance, parameters_t p2)
1490 instance_t* i = dictionary_lookup(&instances, instance);
1494 int frame, allframes;
1496 syntaxerror("instance %s not known", instance);
1500 allframes = currentframe - i->lastFrame - 1;
1502 warning(".change ignored. can only .put/.change an object once per frame.");
1506 m = s_instancepos(i->character->size, &p2);
1507 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1508 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1511 /* o.k., we got the start and end point set. Now iterate though all the
1512 tags in between, inserting object changes after each new frame */
1515 if(!t) syntaxerror("internal error(6)");
1517 while(frame < allframes) {
1518 if(t->id == ST_SHOWFRAME) {
1523 p = s_interpolate(&p1, &p2, frame, allframes);
1524 m = s_instancepos(i->character->size, &p); //needed?
1525 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1526 i->lastFrame = currentframe;
1527 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1529 if(frame == allframes)
1534 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1538 void s_delinstance(char*instance)
1540 instance_t* i = dictionary_lookup(&instances, instance);
1542 syntaxerror("instance %s not known", instance);
1544 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1545 swf_SetU16(tag, i->depth);
1546 dictionary_del(&instances, instance);
1549 void s_qchange(char*instance, parameters_t p)
1556 syntaxerror(".end unexpected");
1557 if(stack[stackpos-1].type == 0)
1559 else if(stack[stackpos-1].type == 1)
1561 else if(stack[stackpos-1].type == 2)
1563 else if(stack[stackpos-1].type == 3)
1565 else syntaxerror("internal error 1");
1568 // ------------------------------------------------------------------------
1570 typedef int command_func_t(map_t*args);
1572 SRECT parseBox(char*str)
1575 float xmin, xmax, ymin, ymax;
1576 char*x = strchr(str, 'x');
1578 if(!strcmp(str, "autocrop")) {
1579 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1583 d1 = strchr(x+1, ':');
1585 d2 = strchr(d1+1, ':');
1587 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1591 else if(d1 && !d2) {
1592 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1598 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1603 r.xmin = (SCOORD)(xmin*20);
1604 r.ymin = (SCOORD)(ymin*20);
1605 r.xmax = (SCOORD)(xmax*20);
1606 r.ymax = (SCOORD)(ymax*20);
1609 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1612 float parseFloat(char*str)
1616 int parseInt(char*str)
1621 if(str[0]=='+' || str[0]=='-')
1625 if(str[t]<'0' || str[t]>'9')
1626 syntaxerror("Not an Integer: \"%s\"", str);
1629 int parseTwip(char*str)
1633 if(str[0]=='+' || str[0]=='-') {
1638 dot = strchr(str, '.');
1642 return sign*parseInt(str)*20;
1644 int l=strlen(++dot);
1646 for(s=str;s<dot-1;s++)
1647 if(*s<'0' || *s>'9')
1648 syntaxerror("Not a coordinate: \"%s\"", str);
1650 if(*s<'0' || *s>'9')
1651 syntaxerror("Not a coordinate: \"%s\"", str);
1653 if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
1654 warning("precision loss: %s converted to twip: %s", str, dot);
1659 return sign*atoi(str)*20;
1661 return sign*atoi(str)*20+atoi(dot)*2;
1663 return sign*atoi(str)*20+atoi(dot)/5;
1668 int isPoint(char*str)
1670 if(strchr(str, '('))
1676 SPOINT parsePoint(char*str)
1680 int l = strlen(str);
1681 char*comma = strchr(str, ',');
1682 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1683 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1684 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1685 p.x = parseTwip(tmp);
1686 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1687 p.y = parseTwip(tmp);
1691 int parseColor2(char*str, RGBA*color)
1693 int l = strlen(str);
1697 struct {unsigned char r,g,b;char*name;} colors[] =
1698 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1699 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1700 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1701 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1702 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1703 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1704 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1705 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1706 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1707 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1708 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1709 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1713 if(str[0]=='#' && (l==7 || l==9)) {
1714 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1716 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1718 color->r = r; color->g = g; color->b = b; color->a = a;
1721 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1722 if(!strcmp(str, colors[t].name)) {
1727 color->r = r; color->g = g; color->b = b; color->a = a;
1733 RGBA parseColor(char*str)
1736 if(!parseColor2(str, &c))
1737 syntaxerror("Expression '%s' is not a color", str);
1741 typedef struct _muladd {
1746 MULADD parseMulAdd(char*str)
1749 char* str2 = (char*)malloc(strlen(str)+5);
1756 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1757 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1758 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1759 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1760 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1761 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1762 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1763 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1764 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1765 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1767 syntaxerror("'%s' is not a valid color transform expression", str);
1769 m.add = (int)(add*256);
1770 m.mul = (int)(mul*256);
1775 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1777 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1778 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1780 if(a<-32768) a=-32768;
1781 if(a>32767) a=32767;
1782 if(m<-32768) m=-32768;
1783 if(m>32767) m=32767;
1789 float parsePercent(char*str)
1791 int l = strlen(str);
1795 return atoi(str)/100.0;
1797 syntaxerror("Expression '%s' is not a percentage", str);
1800 int isPercent(char*str)
1802 return str[strlen(str)-1]=='%';
1804 int parseNewSize(char*str, int size)
1807 return parsePercent(str)*size;
1809 return (int)(atof(str)*20);
1812 int isColor(char*str)
1815 return parseColor2(str, &c);
1818 static char* lu(map_t* args, char*name)
1820 char* value = map_lookup(args, name);
1822 map_dump(args, stdout, "");
1823 syntaxerror("internal error 2: value %s should be set", name);
1828 static int c_flash(map_t*args)
1830 char* filename = map_lookup(args, "filename");
1831 char* compressstr = lu(args, "compress");
1832 SRECT bbox = parseBox(lu(args, "bbox"));
1833 int version = parseInt(lu(args, "version"));
1834 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1836 RGBA color = parseColor(lu(args, "background"));
1838 if(!filename || !*filename) {
1839 /* for compatibility */
1840 filename = map_lookup(args, "name");
1841 if(!filename || !*filename) {
1844 //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
1845 msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
1849 if(!filename || override_outputname)
1850 filename = outputname;
1852 if(!strcmp(compressstr, "default"))
1853 compress = version==6;
1854 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1856 else if(!strcmp(compressstr, "no"))
1858 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1860 s_swf(filename, bbox, version, fps, compress, color);
1863 int isRelative(char*str)
1865 return !strncmp(str, "<plus>", 6) ||
1866 !strncmp(str, "<minus>", 7);
1868 char* getOffset(char*str)
1870 if(!strncmp(str, "<plus>", 6))
1872 if(!strncmp(str, "<minus>", 7))
1874 syntaxerror("internal error (347)");
1877 int getSign(char*str)
1879 if(!strncmp(str, "<plus>", 6))
1881 if(!strncmp(str, "<minus>", 7))
1883 syntaxerror("internal error (348)");
1886 static dictionary_t points;
1887 static mem_t mpoints;
1888 int points_initialized = 0;
1890 SPOINT getPoint(SRECT r, char*name)
1893 if(!strcmp(name, "center")) {
1895 p.x = (r.xmin + r.xmax)/2;
1896 p.y = (r.ymin + r.ymax)/2;
1900 if(points_initialized)
1901 l = (int)dictionary_lookup(&points, name);
1903 syntaxerror("Invalid point: \"%s\".", name);
1906 return *(SPOINT*)&mpoints.buffer[l];
1908 static int c_gradient(map_t*args)
1910 char*name = lu(args, "name");
1911 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1912 int rotate = parseInt(lu(args, "rotate"));
1916 syntaxerror("colon (:) expected");
1918 s_gradient(name, text, radial,rotate);
1921 static int c_point(map_t*args)
1923 char*name = lu(args, "name");
1927 if(!points_initialized) {
1928 dictionary_init(&points);
1930 points_initialized = 1;
1932 p.x = parseTwip(lu(args, "x"));
1933 p.y = parseTwip(lu(args, "y"));
1934 pos = mem_put(&mpoints, &p, sizeof(p));
1935 string_set(&s1, name);
1937 dictionary_put(&points, s1, (void*)pos);
1940 static int c_play(map_t*args)
1942 char*name = lu(args, "name");
1943 char*loop = lu(args, "loop");
1944 char*nomultiple = lu(args, "nomultiple");
1946 if(!strcmp(nomultiple, "nomultiple"))
1949 nm = parseInt(nomultiple);
1951 if(s_playsound(name, parseInt(loop), nm, 0)) {
1953 } else if(s_swf3action(name, "play")) {
1959 static int c_stop(map_t*args)
1961 char*name = map_lookup(args, "name");
1963 if(s_playsound(name, 0,0,1)) {
1965 } else if(s_swf3action(name, "stop")) {
1968 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
1972 static int c_nextframe(map_t*args)
1974 char*name = lu(args, "name");
1976 if(s_swf3action(name, "nextframe")) {
1979 syntaxerror("I don't know anything about movie \"%s\"", name);
1983 static int c_previousframe(map_t*args)
1985 char*name = lu(args, "name");
1987 if(s_swf3action(name, "previousframe")) {
1990 syntaxerror("I don't know anything about movie \"%s\"", name);
1994 static int c_placement(map_t*args, int type)
1996 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1999 char* luminancestr = lu(args, "luminance");
2000 char* scalestr = lu(args, "scale");
2001 char* scalexstr = lu(args, "scalex");
2002 char* scaleystr = lu(args, "scaley");
2003 char* rotatestr = lu(args, "rotate");
2004 char* shearstr = lu(args, "shear");
2005 char* xstr="", *pivotstr="";
2006 char* ystr="", *anglestr="";
2007 char*above = lu(args, "above"); /*FIXME*/
2008 char*below = lu(args, "below");
2009 char* rstr = lu(args, "red");
2010 char* gstr = lu(args, "green");
2011 char* bstr = lu(args, "blue");
2012 char* astr = lu(args, "alpha");
2013 char* pinstr = lu(args, "pin");
2014 char* as = map_lookup(args, "as");
2022 if(type==9) { // (?) .rotate or .arcchange
2023 pivotstr = lu(args, "pivot");
2024 anglestr = lu(args, "angle");
2026 xstr = lu(args, "x");
2027 ystr = lu(args, "y");
2030 luminance = parseMulAdd(luminancestr);
2033 luminance.mul = 256;
2037 if(scalexstr[0]||scaleystr[0])
2038 syntaxerror("scalex/scaley and scale cannot both be set");
2039 scalexstr = scaleystr = scalestr;
2042 if(type == 0 || type == 4) {
2044 character = lu(args, "character");
2045 parameters_clear(&p);
2046 } else if (type == 5) {
2047 character = lu(args, "name");
2048 parameters_clear(&p);
2051 p = s_getParameters(instance);
2056 if(isRelative(xstr)) {
2057 if(type == 0 || type == 4)
2058 syntaxerror("relative x values not allowed for initial put or startclip");
2059 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2061 p.x = parseTwip(xstr);
2065 if(isRelative(ystr)) {
2066 if(type == 0 || type == 4)
2067 syntaxerror("relative y values not allowed for initial put or startclip");
2068 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2070 p.y = parseTwip(ystr);
2074 /* scale, scalex, scaley */
2076 oldbbox = s_getCharBBox(character);
2078 oldbbox = s_getInstanceBBox(instance);
2080 oldwidth = oldbbox.xmax - oldbbox.xmin;
2081 oldheight = oldbbox.ymax - oldbbox.ymin;
2083 if(oldwidth==0) p.scalex = 1.0;
2086 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2090 if(oldheight==0) p.scaley = 1.0;
2093 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2099 if(isRelative(rotatestr)) {
2100 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2102 p.rotate = parseFloat(rotatestr);
2108 if(isRelative(shearstr)) {
2109 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2111 p.shear = parseFloat(shearstr);
2116 if(isPoint(pivotstr))
2117 p.pivot = parsePoint(pivotstr);
2119 p.pivot = getPoint(oldbbox, pivotstr);
2123 p.pin = parsePoint(pinstr);
2125 p.pin = getPoint(oldbbox, pinstr);
2128 /* color transform */
2130 if(rstr[0] || luminancestr[0]) {
2133 r = parseMulAdd(rstr);
2135 r.add = p.cxform.r0;
2136 r.mul = p.cxform.r1;
2138 r = mergeMulAdd(r, luminance);
2139 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2141 if(gstr[0] || luminancestr[0]) {
2144 g = parseMulAdd(gstr);
2146 g.add = p.cxform.g0;
2147 g.mul = p.cxform.g1;
2149 g = mergeMulAdd(g, luminance);
2150 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2152 if(bstr[0] || luminancestr[0]) {
2155 b = parseMulAdd(bstr);
2157 b.add = p.cxform.b0;
2158 b.mul = p.cxform.b1;
2160 b = mergeMulAdd(b, luminance);
2161 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2164 MULADD a = parseMulAdd(astr);
2165 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2169 s_put(instance, character, p);
2171 s_change(instance, p);
2173 s_qchange(instance, p);
2175 s_jump(instance, p);
2177 s_startclip(instance, character, p);
2178 else if(type == 5) {
2180 s_buttonput(character, as, p);
2182 s_buttonput(character, "shape", p);
2187 static int c_put(map_t*args)
2189 c_placement(args, 0);
2192 static int c_change(map_t*args)
2194 c_placement(args, 1);
2197 static int c_qchange(map_t*args)
2199 c_placement(args, 2);
2202 static int c_arcchange(map_t*args)
2204 c_placement(args, 2);
2207 static int c_jump(map_t*args)
2209 c_placement(args, 3);
2212 static int c_startclip(map_t*args)
2214 c_placement(args, 4);
2217 static int c_show(map_t*args)
2219 c_placement(args, 5);
2222 static int c_del(map_t*args)
2224 char*instance = lu(args, "name");
2225 s_delinstance(instance);
2228 static int c_end(map_t*args)
2233 static int c_sprite(map_t*args)
2235 char* name = lu(args, "name");
2239 static int c_frame(map_t*args)
2241 char*framestr = lu(args, "n");
2242 char*cutstr = lu(args, "cut");
2243 char*name = lu(args, "name");
2246 if(strcmp(cutstr, "no"))
2248 if(isRelative(framestr)) {
2249 frame = s_getframe();
2250 if(getSign(framestr)<0)
2251 syntaxerror("relative frame expressions must be positive");
2252 frame += parseInt(getOffset(framestr));
2255 frame = parseInt(framestr);
2256 if(s_getframe() >= frame
2257 && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
2258 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2260 s_frame(frame, cut, name);
2263 static int c_primitive(map_t*args)
2265 char*name = lu(args, "name");
2266 char*command = lu(args, "commandname");
2267 int width=0, height=0, r=0;
2268 int linewidth = parseTwip(lu(args, "line"));
2269 char*colorstr = lu(args, "color");
2270 RGBA color = parseColor(colorstr);
2271 char*fillstr = lu(args, "fill");
2278 if(!strcmp(command, "circle"))
2280 else if(!strcmp(command, "filled"))
2284 width = parseTwip(lu(args, "width"));
2285 height = parseTwip(lu(args, "height"));
2286 } else if (type==1) {
2287 r = parseTwip(lu(args, "r"));
2288 } else if (type==2) {
2289 outline = lu(args, "outline");
2292 if(!strcmp(fillstr, "fill"))
2294 if(!strcmp(fillstr, "none"))
2296 if(width<0 || height<0 || linewidth<0 || r<0)
2297 syntaxerror("values width, height, line, r must be positive");
2299 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2300 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2301 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2305 static int c_textshape(map_t*args)
2307 char*name = lu(args, "name");
2308 char*text = lu(args, "text");
2309 char*font = lu(args, "font");
2310 float size = parsePercent(lu(args, "size"));
2312 s_textshape(name, font, size, text);
2316 static int c_swf(map_t*args)
2318 char*name = lu(args, "name");
2319 char*filename = lu(args, "filename");
2320 char*command = lu(args, "commandname");
2321 if(!strcmp(command, "shape"))
2322 warning("Please use .swf instead of .shape");
2323 s_includeswf(name, filename);
2327 static int c_font(map_t*args)
2329 char*name = lu(args, "name");
2330 char*filename = lu(args, "filename");
2331 s_font(name, filename);
2335 static int c_sound(map_t*args)
2337 char*name = lu(args, "name");
2338 char*filename = lu(args, "filename");
2339 s_sound(name, filename);
2343 static int c_text(map_t*args)
2345 char*name = lu(args, "name");
2346 char*text = lu(args, "text");
2347 char*font = lu(args, "font");
2348 float size = parsePercent(lu(args, "size"));
2349 RGBA color = parseColor(lu(args, "color"));
2350 s_text(name, font, text, (int)(size*100), color);
2354 static int c_soundtrack(map_t*args)
2359 static int c_quicktime(map_t*args)
2361 char*name = lu(args, "name");
2362 char*url = lu(args, "url");
2363 s_quicktime(name, url);
2367 static int c_image(map_t*args)
2369 char*command = lu(args, "commandname");
2370 char*name = lu(args, "name");
2371 char*filename = lu(args, "filename");
2372 if(!strcmp(command,"jpeg")) {
2373 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2374 s_image(name, "jpeg", filename, quality);
2376 s_image(name, "png", filename, 0);
2381 static int c_outline(map_t*args)
2383 char*name = lu(args, "name");
2384 char*format = lu(args, "format");
2388 syntaxerror("colon (:) expected");
2390 s_outline(name, format, text);
2394 int fakechar(map_t*args)
2396 char*name = lu(args, "name");
2397 s_box(name, 0, 0, black, 20, 0);
2401 static int c_egon(map_t*args) {return fakechar(args);}
2402 static int c_button(map_t*args) {
2403 char*name = lu(args, "name");
2407 static int current_button_flags = 0;
2408 static int c_on_press(map_t*args)
2410 char*position = lu(args, "position");
2412 if(!strcmp(position, "inside")) {
2413 current_button_flags |= BC_OVERUP_OVERDOWN;
2414 } else if(!strcmp(position, "outside")) {
2415 //current_button_flags |= BC_IDLE_OUTDOWN;
2416 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2417 } else if(!strcmp(position, "anywhere")) {
2418 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2421 if(type == RAWDATA) {
2423 s_buttonaction(current_button_flags, action);
2424 current_button_flags = 0;
2430 static int c_on_release(map_t*args)
2432 char*position = lu(args, "position");
2434 if(!strcmp(position, "inside")) {
2435 current_button_flags |= BC_OVERDOWN_OVERUP;
2436 } else if(!strcmp(position, "outside")) {
2437 current_button_flags |= BC_OUTDOWN_IDLE;
2438 } else if(!strcmp(position, "anywhere")) {
2439 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2442 if(type == RAWDATA) {
2444 s_buttonaction(current_button_flags, action);
2445 current_button_flags = 0;
2451 static int c_on_move_in(map_t*args)
2453 char*position = lu(args, "state");
2455 if(!strcmp(position, "pressed")) {
2456 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2457 } else if(!strcmp(position, "not_pressed")) {
2458 current_button_flags |= BC_IDLE_OVERUP;
2459 } else if(!strcmp(position, "any")) {
2460 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2463 if(type == RAWDATA) {
2465 s_buttonaction(current_button_flags, action);
2466 current_button_flags = 0;
2472 static int c_on_move_out(map_t*args)
2474 char*position = lu(args, "state");
2476 if(!strcmp(position, "pressed")) {
2477 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2478 } else if(!strcmp(position, "not_pressed")) {
2479 current_button_flags |= BC_OVERUP_IDLE;
2480 } else if(!strcmp(position, "any")) {
2481 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2484 if(type == RAWDATA) {
2486 s_buttonaction(current_button_flags, action);
2487 current_button_flags = 0;
2493 static int c_on_key(map_t*args)
2495 char*key = lu(args, "key");
2497 if(strlen(key)==1) {
2500 current_button_flags |= 0x4000 + (key[0]*0x200);
2502 syntaxerror("invalid character: %c"+key[0]);
2507 <ctrl-x> = 0x200*(x-'a')
2511 syntaxerror("invalid key: %s",key);
2514 if(type == RAWDATA) {
2516 s_buttonaction(current_button_flags, action);
2517 current_button_flags = 0;
2524 static int c_edittext(map_t*args)
2526 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
2527 char*name = lu(args, "name");
2528 char*font = lu(args, "font");
2529 int size = (int)(1024*parsePercent(lu(args, "size")));
2530 int width = parseTwip(lu(args, "width"));
2531 int height = parseTwip(lu(args, "height"));
2532 char*text = lu(args, "text");
2533 RGBA color = parseColor(lu(args, "color"));
2534 int maxlength = parseInt(lu(args, "maxlength"));
2535 char*variable = lu(args, "variable");
2536 char*passwordstr = lu(args, "password");
2537 char*wordwrapstr = lu(args, "wordwrap");
2538 char*multilinestr = lu(args, "multiline");
2539 char*htmlstr = lu(args, "html");
2540 char*noselectstr = lu(args, "noselect");
2541 char*readonlystr = lu(args, "readonly");
2542 char*borderstr = lu(args, "border");
2545 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2546 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2547 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2548 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2549 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2550 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2551 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2553 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags);
2557 static int c_morphshape(map_t*args) {return fakechar(args);}
2558 static int c_movie(map_t*args) {return fakechar(args);}
2560 static int c_texture(map_t*args) {return 0;}
2562 static int c_action(map_t*args)
2564 char* filename = map_lookup(args, "filename");
2565 if(!filename ||!*filename) {
2567 if(type != RAWDATA) {
2568 syntaxerror("colon (:) expected");
2572 FILE*fi = fopen(filename, "rb");
2576 syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
2577 fseek(fi, 0, SEEK_END);
2579 fseek(fi, 0, SEEK_SET);
2580 text = rfx_alloc(l+1);
2581 fread(text, l, 1, fi);
2593 command_func_t* func;
2596 {{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
2597 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2598 // "import" type stuff
2599 {"swf", c_swf, "name filename"},
2600 {"shape", c_swf, "name filename"},
2601 {"jpeg", c_image, "name filename quality=80%"},
2602 {"png", c_image, "name filename"},
2603 {"movie", c_movie, "name filename"},
2604 {"sound", c_sound, "name filename"},
2605 {"font", c_font, "name filename"},
2606 {"soundtrack", c_soundtrack, "filename"},
2607 {"quicktime", c_quicktime, "url"},
2609 // generators of primitives
2611 {"point", c_point, "name x=0 y=0"},
2612 {"gradient", c_gradient, "name @radial=0 rotate=0"},
2613 {"outline", c_outline, "name format=simple"},
2614 {"textshape", c_textshape, "name font size=100% text"},
2616 // character generators
2617 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2618 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2619 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2621 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2622 {"text", c_text, "name text font size=100% color=white"},
2623 {"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"},
2624 {"morphshape", c_morphshape, "name start end"},
2625 {"button", c_button, "name"},
2626 {"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="},
2627 {"on_press", c_on_press, "position=inside"},
2628 {"on_release", c_on_release, "position=anywhere"},
2629 {"on_move_in", c_on_move_in, "state=not_pressed"},
2630 {"on_move_out", c_on_move_out, "state=not_pressed"},
2631 {"on_key", c_on_key, "key=any"},
2634 {"play", c_play, "name loop=0 @nomultiple=0"},
2635 {"stop", c_stop, "name= "},
2636 {"nextframe", c_nextframe, "name"},
2637 {"previousframe", c_previousframe, "name"},
2639 // object placement tags
2640 {"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="},
2641 {"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="},
2642 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2643 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2644 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2645 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2646 {"del", c_del, "name"},
2647 // virtual object placement
2648 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2650 // commands which start a block
2651 //startclip (see above)
2652 {"sprite", c_sprite, "name"},
2653 {"action", c_action, "filename="},
2659 static map_t parseArguments(char*command, char*pattern)
2675 string_set(&t1, "commandname");
2676 string_set(&t2, command);
2677 map_put(&result, t1, t2);
2679 if(!pattern || !*pattern)
2686 if(!strncmp("<i> ", x, 3)) {
2688 if(type == COMMAND || type == RAWDATA) {
2690 syntaxerror("character name expected");
2692 name[pos].str = "instance";
2694 value[pos].str = text;
2695 value[pos].len = strlen(text);
2699 if(type == ASSIGNMENT)
2702 name[pos].str = "character";
2704 value[pos].str = text;
2705 value[pos].len = strlen(text);
2713 isboolean[pos] = (x[0] =='@');
2726 name[pos].len = d-x;
2731 name[pos].len = e-x;
2732 value[pos].str = e+1;
2733 value[pos].len = d-e-1;
2741 /* for(t=0;t<len;t++) {
2742 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2743 isboolean[t]?"(boolean)":"");
2748 if(type == RAWDATA || type == COMMAND) {
2753 // first, search for boolean arguments
2754 for(pos=0;pos<len;pos++)
2756 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2758 if(type == ASSIGNMENT)
2760 value[pos].str = text;
2761 value[pos].len = strlen(text);
2762 /*printf("setting boolean parameter %s (to %s)\n",
2763 strdup_n(name[pos], namelen[pos]),
2764 strdup_n(value[pos], valuelen[pos]));*/
2769 // second, search for normal arguments
2771 for(pos=0;pos<len;pos++)
2773 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2774 (type != ASSIGNMENT && !set[pos])) {
2776 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2778 if(type == ASSIGNMENT)
2781 value[pos].str = text;
2782 value[pos].len = strlen(text);
2784 printf("setting parameter %s (to %s)\n",
2785 strdup_n(name[pos].str, name[pos].len),
2786 strdup_n(value[pos].str, value[pos].len));
2792 syntaxerror("Illegal argument \"%s\" to .%s", text, command);
2796 for(t=0;t<len;t++) {
2797 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2800 for(t=0;t<len;t++) {
2801 if(value[t].str && value[t].str[0] == '*') {
2802 //relative default- take value from some other parameter
2804 for(s=0;s<len;s++) {
2805 if(value[s].len == value[t].len-1 &&
2806 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2807 value[t].str = value[s].str;
2810 if(value[t].str == 0) {
2812 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2816 /* ok, now construct the dictionary from the parameters */
2820 map_put(&result, name[t], value[t]);
2824 static void parseArgumentsForCommand(char*command)
2829 msg("<verbose> parse Command: %s (line %d)", command, line);
2831 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2832 if(!strcmp(arguments[t].command, command)) {
2834 /* ugly hack- will be removed soon (once documentation and .sc generating
2835 utilities have been changed) */
2836 if(!strcmp(command, "swf") && !stackpos) {
2837 warning("Please use .flash instead of .swf- this will be mandatory soon");
2842 args = parseArguments(command, arguments[t].arguments);
2848 syntaxerror("command %s not known", command);
2850 // catch missing .flash directives at the beginning of a file
2851 if(strcmp(command, "flash") && !stackpos)
2853 syntaxerror("No movie defined- use .flash first");
2857 printf(".%s\n", command);fflush(stdout);
2858 map_dump(&args, stdout, "\t");fflush(stdout);
2861 (*arguments[nr].func)(&args);
2863 /*if(!strcmp(command, "button") ||
2864 !strcmp(command, "action")) {
2867 if(type == COMMAND) {
2868 if(!strcmp(text, "end"))
2882 int main (int argc,char ** argv)
2885 processargs(argc, argv);
2886 initLog(0,-1,0,0,-1,verbose);
2889 args_callback_usage(argv[0]);
2893 file = generateTokens(filename);
2895 printf("parser returned error.\n");
2901 while(!noMoreTokens()) {
2904 syntaxerror("command expected");
2905 parseArgumentsForCommand(text);