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 override_outputname = 0;
45 static struct options_t options[] = {
53 int args_callback_option(char*name,char*val)
55 if(!strcmp(name, "V")) {
56 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
59 else if(!strcmp(name, "o")) {
61 override_outputname = 1;
64 else if(!strcmp(name, "v")) {
69 printf("Unknown option: -%s\n", name);
74 int args_callback_longoption(char*name,char*val)
76 return args_long2shortoption(options, name, val);
78 void args_callback_usage(char *name)
81 printf("Usage: %s [-o file.swf] file.sc\n", name);
83 printf("-h , --help Print short help message and exit\n");
84 printf("-V , --version Print version info and exit\n");
85 printf("-v , --verbose Increase verbosity. \n");
86 printf("-o , --output <filename> Set output file to <filename>.\n");
89 int args_callback_command(char*name,char*val)
92 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
99 static struct token_t* file;
108 static void syntaxerror(char*format, ...)
112 va_start(arglist, format);
113 vsprintf(buf, format, arglist);
115 printf("\"%s\", line %d column %d: error- %s\n", filename, line, column, buf);
119 static void warning(char*format, ...)
123 va_start(arglist, format);
124 vsprintf(buf, format, arglist);
126 printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
129 static void readToken()
131 type = file[pos].type;
133 syntaxerror("unexpected end of file");
135 text = file[pos].text;
136 textlen = strlen(text);
137 line = file[pos].line;
138 column = file[pos].column;
140 //printf("---> %d(%s) %s\n", type, type_names[type], text);
143 static void pushBack()
146 if(!pos) syntaxerror("internal error 3");
151 textlen = strlen(text);
154 column = file[p].column;
157 static int noMoreTokens()
159 if(file[pos].type == END)
164 // ------------------------------ swf routines ----------------------------
168 int type; //0=swf, 1=sprite, 2=clip, 3=button
174 /* for sprites (1): */
180 dictionary_t oldinstances;
185 static int stackpos = 0;
187 static dictionary_t characters;
188 static dictionary_t images;
189 static dictionary_t outlines;
190 static dictionary_t gradients;
191 static char idmap[65536];
192 static TAG*tag = 0; //current tag
194 static int id; //current character id
195 static int currentframe; //current frame in current level
196 static SRECT currentrect; //current bounding box in current level
197 static U16 currentdepth;
198 static dictionary_t instances;
199 static dictionary_t fonts;
200 static dictionary_t sounds;
202 typedef struct _parameters {
204 float scalex, scaley;
212 typedef struct _character {
218 typedef struct _instance {
219 character_t*character;
221 parameters_t parameters;
222 TAG* lastTag; //last tag which set the object
223 U16 lastFrame; //frame lastTag is in
226 typedef struct _outline {
231 typedef struct _gradient {
237 static void character_init(character_t*c)
239 memset(c, 0, sizeof(character_t));
241 static character_t* character_new()
244 c = (character_t*)malloc(sizeof(character_t));
248 static void instance_init(instance_t*i)
250 memset(i, 0, sizeof(instance_t));
252 static instance_t* instance_new()
255 c = (instance_t*)malloc(sizeof(instance_t));
260 static void incrementid()
264 syntaxerror("Out of character ids.");
269 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
271 character_t* c = character_new();
273 c->definingTag = ctag;
276 if(dictionary_lookup(&characters, name))
277 syntaxerror("character %s defined twice", name);
278 dictionary_put2(&characters, name, c);
280 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
282 swf_SetString(tag, name);
283 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
286 swf_SetString(tag, name);
288 static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
290 character_t* c = character_new();
291 c->definingTag = ctag;
295 if(dictionary_lookup(&images, name))
296 syntaxerror("image %s defined twice", name);
297 dictionary_put2(&images, name, c);
299 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
301 instance_t* i = instance_new();
304 //swf_GetMatrix(0, &i->matrix);
305 if(dictionary_lookup(&instances, name))
306 syntaxerror("object %s defined twice", name);
307 dictionary_put2(&instances, name, i);
311 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)
314 p->scalex = scalex; p->scaley = scaley;
315 p->pin = pin; p->pivot = pivot;
316 p->rotate = rotate; p->cxform = cxform;
320 static void parameters_clear(parameters_t*p)
323 p->scalex = 1.0; p->scaley = 1.0;
326 p->pivot.x = 0; p->pivot.y = 0;
329 swf_GetCXForm(0, &p->cxform, 1);
332 static void makeMatrix(MATRIX*m, parameters_t*p)
341 sx = p->scalex*cos(p->rotate/360*2*3.14159265358979);
342 r1 = -p->scalex*sin(p->rotate/360*2*3.14159265358979)+sx*p->shear;
343 r0 = p->scaley*sin(p->rotate/360*2*3.14159265358979);
344 sy = p->scaley*cos(p->rotate/360*2*3.14159265358979)+r0*p->shear;
346 m->sx = (int)(sx*65536+0.5);
347 m->r1 = (int)(r1*65536+0.5);
348 m->r0 = (int)(r0*65536+0.5);
349 m->sy = (int)(sy*65536+0.5);
353 h = swf_TurnPoint(p->pin, m);
358 static MATRIX s_instancepos(SRECT rect, parameters_t*p)
363 r = swf_TurnRect(rect, &m);
364 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
365 currentrect.xmax == 0 && currentrect.ymax == 0)
368 swf_ExpandRect2(¤trect, &r);
372 void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA background)
374 SWF*swf = (SWF*)malloc(sizeof(SWF));
377 syntaxerror(".swf blocks can't be nested");
379 memset(swf, 0, sizeof(swf));
380 swf->fileVersion = version;
382 swf->frameRate = fps;
383 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
384 swf->compressed = compress;
385 swf_SetRGB(tag,&background);
387 if(stackpos==sizeof(stack)/sizeof(stack[0]))
388 syntaxerror("too many levels of recursion");
390 dictionary_init(&characters);
391 dictionary_init(&images);
392 dictionary_init(&outlines);
393 dictionary_init(&gradients);
394 dictionary_init(&instances);
395 dictionary_init(&fonts);
396 dictionary_init(&sounds);
398 memset(&stack[stackpos], 0, sizeof(stack[0]));
399 stack[stackpos].type = 0;
400 stack[stackpos].filename = strdup(name);
401 stack[stackpos].swf = swf;
402 stack[stackpos].oldframe = -1;
407 memset(¤trect, 0, sizeof(currentrect));
410 memset(idmap, 0, sizeof(idmap));
414 void s_sprite(char*name)
416 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
417 swf_SetU16(tag, id); //id
418 swf_SetU16(tag, 0); //frames
420 memset(&stack[stackpos], 0, sizeof(stack[0]));
421 stack[stackpos].type = 1;
422 stack[stackpos].oldframe = currentframe;
423 stack[stackpos].olddepth = currentdepth;
424 stack[stackpos].oldrect = currentrect;
425 stack[stackpos].oldinstances = instances;
426 stack[stackpos].tag = tag;
427 stack[stackpos].id = id;
428 stack[stackpos].name = strdup(name);
430 /* FIXME: those four fields should be bundled together */
431 dictionary_init(&instances);
434 memset(¤trect, 0, sizeof(currentrect));
440 typedef struct _buttonrecord
448 typedef struct _button
452 buttonrecord_t records[4];
455 static button_t mybutton;
457 void s_button(char*name)
459 tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
460 swf_SetU16(tag, id); //id
461 swf_ButtonSetFlags(tag, 0); //menu=no
463 memset(&mybutton, 0, sizeof(mybutton));
465 memset(&stack[stackpos], 0, sizeof(stack[0]));
466 stack[stackpos].type = 3;
467 stack[stackpos].tag = tag;
468 stack[stackpos].id = id;
469 stack[stackpos].name = strdup(name);
470 stack[stackpos].oldrect = currentrect;
471 memset(¤trect, 0, sizeof(currentrect));
476 void s_buttonput(char*character, char*as, parameters_t p)
478 character_t* c = dictionary_lookup(&characters, character);
483 if(!stackpos || (stack[stackpos-1].type != 3)) {
484 syntaxerror(".show may only appear in .button");
487 syntaxerror("character %s not known (in .shape %s)", character, character);
489 if(mybutton.endofshapes) {
490 syntaxerror("a .do may not precede a .show", character, character);
493 m = s_instancepos(c->size, &p);
501 if(*s==',' || *s==0) {
502 if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
503 else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
504 else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
505 else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
506 else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
507 else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
514 static void setbuttonrecords(TAG*tag)
516 int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
517 if(!mybutton.endofshapes) {
520 if(!mybutton.records[3].set) {
521 memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
525 if(mybutton.records[t].set) {
526 swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
529 swf_SetU8(tag,0); // end of button records
530 mybutton.endofshapes = 1;
534 void s_buttonaction(int flags, char*action)
540 setbuttonrecords(stack[stackpos-1].tag);
542 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
544 syntaxerror("Couldn't compile ActionScript");
547 swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
548 swf_ActionSet(stack[stackpos-1].tag, a);
549 mybutton.nr_actions++;
554 static void setactionend(TAG*tag)
556 if(!mybutton.nr_actions) {
557 /* no actions means we didn't have an actionoffset,
558 which means we can't signal the end of the
559 buttonaction records, so, *sigh*, we have
560 to insert a dummy record */
561 swf_SetU16(tag, 0); //offset
562 swf_SetU16(tag, 0); //condition
563 swf_SetU8(tag, 0); //action
567 static void s_endButton()
570 setbuttonrecords(stack[stackpos-1].tag);
571 setactionend(stack[stackpos-1].tag);
574 swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
578 tag = stack[stackpos].tag;
579 currentrect = stack[stackpos].oldrect;
581 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
582 free(stack[stackpos].name);
585 TAG* removeFromTo(TAG*from, TAG*to)
587 TAG*save = from->prev;
589 TAG*next = from->next;
597 static void s_endSprite()
599 SRECT r = currentrect;
601 if(stack[stackpos].cut)
602 tag = removeFromTo(stack[stackpos].cut, tag);
606 /* TODO: before clearing, prepend "<spritename>." to names and
607 copy into old instances dict */
608 dictionary_clear(&instances);
610 currentframe = stack[stackpos].oldframe;
611 currentrect = stack[stackpos].oldrect;
612 currentdepth = stack[stackpos].olddepth;
613 instances = stack[stackpos].oldinstances;
615 tag = swf_InsertTag(tag, ST_END);
617 tag = stack[stackpos].tag;
620 syntaxerror("internal error(7)");
622 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
623 free(stack[stackpos].name);
626 static void s_endSWF()
632 if(stack[stackpos].cut)
633 tag = removeFromTo(stack[stackpos].cut, tag);
637 swf = stack[stackpos].swf;
638 filename = stack[stackpos].filename;
640 //tag = swf_InsertTag(tag, ST_SHOWFRAME); //?
642 tag = swf_InsertTag(tag, ST_END);
644 swf_OptimizeTagOrder(swf);
646 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
647 swf->movieSize = currentrect; /* "autocrop" */
650 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
651 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
652 swf->movieSize.ymax += 20;
655 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
657 syntaxerror("couldn't create output file %s", filename);
660 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
662 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
666 dictionary_clear(&instances);
667 dictionary_clear(&characters);
668 dictionary_clear(&images);
669 dictionary_clear(&outlines);
670 dictionary_clear(&gradients);
671 dictionary_clear(&fonts);
672 dictionary_clear(&sounds);
682 if(stack[stackpos-1].type == 0)
683 syntaxerror("End of file encountered in .flash block");
684 if(stack[stackpos-1].type == 1)
685 syntaxerror("End of file encountered in .sprite block");
686 if(stack[stackpos-1].type == 2)
687 syntaxerror("End of file encountered in .clip block");
696 void s_frame(int nr, int cut, char*name)
701 for(t=currentframe;t<nr;t++) {
702 tag = swf_InsertTag(tag, ST_SHOWFRAME);
703 if(t==nr-1 && name && *name) {
704 tag = swf_InsertTag(tag, ST_FRAMELABEL);
705 swf_SetString(tag, name);
711 syntaxerror("Can't cut, frame empty");
713 stack[stackpos].cut = tag;
719 int parseColor2(char*str, RGBA*color);
721 int addFillStyle(SHAPE*s, SRECT*r, char*texture)
726 if(texture[0] == '#') {
727 parseColor2(texture, &color);
728 return swf_ShapeAddSolidFillStyle(s, &color);
729 } else if((image = dictionary_lookup(&images, texture))) {
731 swf_GetMatrix(0, &m);
732 m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
733 m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
736 return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
737 } /*else if ((texture = dictionary_lookup(&textures, texture))) {
738 } */ else if ((gradient = dictionary_lookup(&gradients, texture))) {
742 swf_GetMatrix(0, &rot);
743 ccos = cos(-gradient->rotate*2*3.14159265358979/360);
744 csin = sin(-gradient->rotate*2*3.14159265358979/360);
746 rot.r1 = -csin*65536;
749 r2 = swf_TurnRect(*r, &rot);
750 swf_GetMatrix(0, &m);
751 m.sx = (r2.xmax - r2.xmin)*2*ccos;
752 m.r1 = -(r2.xmax - r2.xmin)*2*csin;
753 m.r0 = (r2.ymax - r2.ymin)*2*csin;
754 m.sy = (r2.ymax - r2.ymin)*2*ccos;
755 m.tx = r->xmin + (r->xmax - r->xmin)/2;
756 m.ty = r->ymin + (r->ymax - r->ymin)/2;
757 return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
758 } else if (parseColor2(texture, &color)) {
759 return swf_ShapeAddSolidFillStyle(s, &color);
761 syntaxerror("not a color/fillstyle: %s", texture);
766 RGBA black={r:0,g:0,b:0,a:0};
767 void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
776 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
778 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
781 fs1 = addFillStyle(s, &r2, texture);
784 r.xmin = r2.xmin-linewidth-linewidth/2;
785 r.ymin = r2.ymin-linewidth-linewidth/2;
786 r.xmax = r2.xmax+linewidth+linewidth/2;
787 r.ymax = r2.ymax+linewidth+linewidth/2;
789 swf_SetShapeHeader(tag,s);
790 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
791 swf_ShapeSetLine(tag,s,width,0);
792 swf_ShapeSetLine(tag,s,0,height);
793 swf_ShapeSetLine(tag,s,-width,0);
794 swf_ShapeSetLine(tag,s,0,-height);
795 swf_ShapeSetEnd(tag);
798 s_addcharacter(name, id, tag, r);
802 void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
808 outline = dictionary_lookup(&outlines, outlinename);
810 syntaxerror("outline %s not defined", outlinename);
814 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
816 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
818 fs1 = addFillStyle(s, &r2, texture);
820 syntaxerror("non filled outlines not yet supported- please supply a fill=<color/texture> argument");
822 rect.xmin = r2.xmin-linewidth-linewidth/2;
823 rect.ymin = r2.ymin-linewidth-linewidth/2;
824 rect.xmax = r2.xmax+linewidth+linewidth/2;
825 rect.ymax = r2.ymax+linewidth+linewidth/2;
827 swf_SetRect(tag,&rect);
828 swf_SetShapeStyles(tag, s);
829 swf_SetShapeBits(tag, outline->shape); //does not count bits!
830 swf_SetBlock(tag, outline->shape->data, (outline->shape->bitlen+7)/8);
833 s_addcharacter(name, id, tag, rect);
837 void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
842 r2.xmin = r2.ymin = 0;
846 tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
848 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
850 fs1 = addFillStyle(s, &r2, texture);
852 rect.xmin = r2.xmin-linewidth-linewidth/2;
853 rect.ymin = r2.ymin-linewidth-linewidth/2;
854 rect.xmax = r2.xmax+linewidth+linewidth/2;
855 rect.ymax = r2.ymax+linewidth+linewidth/2;
857 swf_SetRect(tag,&rect);
858 swf_SetShapeHeader(tag,s);
859 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
860 swf_ShapeSetCircle(tag, s, r,r,r,r);
861 swf_ShapeSetEnd(tag);
864 s_addcharacter(name, id, tag, rect);
868 void s_textshape(char*name, char*fontname, float size, char*_text)
871 U8*text = (U8*)_text;
875 font = dictionary_lookup(&fonts, fontname);
877 syntaxerror("font \"%s\" not known!", fontname);
879 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
880 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
881 s_box(name, 0, 0, black, 20, 0);
884 g = font->ascii2glyph[text[0]];
886 outline = malloc(sizeof(outline_t));
887 memset(outline, 0, sizeof(outline_t));
888 outline->shape = font->glyph[g].shape;
889 outline->bbox = font->layout->bounds[g];
893 swf_Shape11DrawerInit(&draw, 0);
894 swf_DrawText(&draw, font, (int)(size*100), _text);
896 outline->shape = swf_ShapeDrawerToShape(&draw);
897 outline->bbox = swf_ShapeDrawerGetBBox(&draw);
901 if(dictionary_lookup(&outlines, name))
902 syntaxerror("outline %s defined twice", name);
903 dictionary_put2(&outlines, name, outline);
906 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
911 font = dictionary_lookup(&fonts, fontname);
913 syntaxerror("font \"%s\" not known!", fontname);
915 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
917 if(!font->numchars) {
918 s_box(name, 0, 0, black, 20, 0);
921 r = swf_SetDefineText(tag, font, &color, text, size);
923 s_addcharacter(name, id, tag, r);
927 void s_quicktime(char*name, char*url)
932 memset(&r, 0, sizeof(r));
934 tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
936 swf_SetString(tag, url);
938 s_addcharacter(name, id, tag, r);
942 void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags)
945 EditTextLayout layout;
948 font = dictionary_lookup(&fonts, fontname);
950 syntaxerror("font \"%s\" not known!", fontname);
951 tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
954 layout.leftmargin = 0;
955 layout.rightmargin = 0;
962 swf_SetEditText(tag, flags|ET_USEOUTLINES, r, text, color, maxlength, font->id, size, &layout, variable);
964 s_addcharacter(name, id, tag, r);
968 /* type: either "jpeg" or "png"
970 void s_image(char*name, char*type, char*filename, int quality)
972 /* an image is actually two folded: 1st bitmap, 2nd character.
973 Both of them can be used separately */
975 /* step 1: the bitmap */
980 warning("image type \"png\" not supported yet!");
981 s_box(name, 0, 0, black, 20, 0);
986 warning("no jpeg support compiled in");
987 s_box(name, 0, 0, black, 20, 0);
990 tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
991 swf_SetU16(tag, imageID);
993 if(swf_SetJPEGBits(tag, filename, quality) < 0) {
994 syntaxerror("Image \"%s\" not found, or contains errors", filename);
997 swf_GetJPEGSize(filename, &width, &height);
1004 s_addimage(name, id, tag, r);
1009 /* step 2: the character */
1010 tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
1011 swf_SetU16(tag, id);
1012 swf_ShapeSetBitmapRect(tag, imageID, width, height);
1014 s_addcharacter(name, id, tag, r);
1018 void dumpSWF(SWF*swf)
1020 TAG* tag = swf->firstTag;
1021 printf("vvvvvvvvvvvvvvvvvvvvv\n");
1023 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
1026 printf("^^^^^^^^^^^^^^^^^^^^^\n");
1029 void s_font(char*name, char*filename)
1032 font = swf_LoadFont(filename);
1035 warning("Couldn't open font file \"%s\"", filename);
1036 font = (SWFFONT*)malloc(sizeof(SWFFONT));
1037 memset(font, 0, sizeof(SWFFONT));
1038 dictionary_put2(&fonts, name, font);
1044 /* fix the layout. Only needed for old fonts */
1046 for(t=0;t<font->numchars;t++) {
1047 font->glyph[t].advance = 0;
1050 swf_FontCreateLayout(font);
1052 /* just in case this thing is used in .edittext later on */
1053 swf_FontPrepareForEditText(font);
1056 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
1057 swf_FontSetDefine2(tag, font);
1060 if(dictionary_lookup(&fonts, name))
1061 syntaxerror("font %s defined twice", name);
1062 dictionary_put2(&fonts, name, font);
1067 typedef struct _sound_t
1073 void s_sound(char*name, char*filename)
1075 struct WAV wav, wav2;
1080 if(!readWAV(filename, &wav)) {
1081 warning("Couldn't read wav file \"%s\"", filename);
1085 convertWAV2mono(&wav, &wav2, 44100);
1086 samples = (U16*)wav2.data;
1087 numsamples = wav2.size/2;
1091 tag = swf_InsertTag(tag, ST_DEFINESOUND);
1092 swf_SetU16(tag, id); //id
1093 swf_SetSoundDefine(tag, samples, numsamples);
1095 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
1099 if(dictionary_lookup(&sounds, name))
1100 syntaxerror("sound %s defined twice", name);
1101 dictionary_put2(&sounds, name, sound);
1109 static char* gradient_getToken(const char**p)
1113 while(**p && strchr(" \t\n\r", **p)) {
1117 while(**p && !strchr(" \t\n\r", **p)) {
1120 result = malloc((*p)-start+1);
1121 memcpy(result,start,(*p)-start+1);
1122 result[(*p)-start] = 0;
1126 float parsePercent(char*str);
1127 RGBA parseColor(char*str);
1129 GRADIENT parseGradient(const char*str)
1132 const char* p = str;
1133 memset(&gradient, 0, sizeof(GRADIENT));
1135 char*posstr,*colorstr;
1138 posstr = gradient_getToken(&p);
1141 pos = parsePercent(posstr);
1142 if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
1143 colorstr = gradient_getToken(&p);
1144 color = parseColor(colorstr);
1145 if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
1146 warning("gradient record too big- max size is 8, rest ignored");
1149 gradient.ratios[gradient.num] = (int)(pos*255.0);
1150 gradient.rgba[gradient.num] = color;
1158 void s_gradient(char*name, const char*text, int radial, int rotate)
1160 gradient_t* gradient;
1161 gradient = malloc(sizeof(gradient_t));
1162 memset(gradient, 0, sizeof(gradient_t));
1163 gradient->gradient = parseGradient(text);
1164 gradient->radial = radial;
1165 gradient->rotate = rotate;
1167 if(dictionary_lookup(&gradients, name))
1168 syntaxerror("gradient %s defined twice", name);
1169 dictionary_put2(&gradients, name, gradient);
1172 void s_action(const char*text)
1175 a = swf_ActionCompile(text, stack[0].swf->fileVersion);
1177 syntaxerror("Couldn't compile ActionScript");
1180 tag = swf_InsertTag(tag, ST_DOACTION);
1182 swf_ActionSet(tag, a);
1187 int s_swf3action(char*name, char*action)
1190 instance_t* object = dictionary_lookup(&instances, name);
1194 a = action_SetTarget(0, name);
1195 if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
1196 else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
1197 else if(!strcmp(action, "stop")) a = action_Stop(a);
1198 else if(!strcmp(action, "play")) a = action_Play(a);
1199 a = action_SetTarget(a, "");
1202 tag = swf_InsertTag(tag, ST_DOACTION);
1203 swf_ActionSet(tag, a);
1208 void s_outline(char*name, char*format, char*source)
1217 swf_Shape11DrawerInit(&draw, 0);
1218 draw_string(&draw, source);
1220 shape = swf_ShapeDrawerToShape(&draw);
1221 //shape2 = swf_ShapeToShape2(shape);
1222 //bounds = swf_GetShapeBoundingBox(shape2);
1223 //swf_Shape2Free(shape2);
1224 bounds = swf_ShapeDrawerGetBBox(&draw);
1225 draw.dealloc(&draw);
1227 outline = (outline_t*)malloc(sizeof(outline_t));
1228 memset(outline, 0, sizeof(outline_t));
1229 outline->shape = shape;
1230 outline->bbox = bounds;
1232 if(dictionary_lookup(&outlines, name))
1233 syntaxerror("outline %s defined twice", name);
1234 dictionary_put2(&outlines, name, outline);
1237 int s_playsound(char*name, int loops, int nomultiple, int stop)
1239 sound_t* sound = dictionary_lookup(&sounds, name);
1244 tag = swf_InsertTag(tag, ST_STARTSOUND);
1245 swf_SetU16(tag, sound->id); //id
1246 memset(&info, 0, sizeof(info));
1249 info.nomultiple = nomultiple;
1250 swf_SetSoundInfo(tag, &info);
1254 void s_includeswf(char*name, char*filename)
1262 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
1263 f = open(filename,O_RDONLY|O_BINARY);
1265 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
1266 s_box(name, 0, 0, black, 20, 0);
1269 if (swf_ReadSWF(f,&swf)<0) {
1270 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
1271 s_box(name, 0, 0, black, 20, 0);
1276 /* FIXME: The following sets the bounding Box for the character.
1277 It is wrong for two reasons:
1278 a) It may be too small (in case objects in the movie clip at the borders)
1279 b) it may be too big (because the poor movie never got autocropped)
1283 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
1284 swf_SetU16(tag, id);
1287 swf_Relocate(&swf, idmap);
1289 ftag = swf.firstTag;
1293 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
1294 if(cutout[t] == ftag->id) {
1298 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
1300 if(ftag->id == ST_END)
1304 /* We simply dump all tags right after the sprite
1305 header, relying on the fact that swf_OptimizeTagOrder() will
1306 sort things out for us later.
1307 We also rely on the fact that the imported SWF is well-formed.
1309 tag = swf_InsertTag(tag, ftag->id);
1310 swf_SetBlock(tag, ftag->data, ftag->len);
1314 syntaxerror("Included file %s contains errors", filename);
1315 tag = swf_InsertTag(tag, ST_END);
1319 s_addcharacter(name, id, tag, r);
1322 SRECT s_getCharBBox(char*name)
1324 character_t* c = dictionary_lookup(&characters, name);
1325 if(!c) syntaxerror("character '%s' unknown(2)", name);
1328 SRECT s_getInstanceBBox(char*name)
1330 instance_t * i = dictionary_lookup(&instances, name);
1332 if(!i) syntaxerror("instance '%s' unknown(4)", name);
1334 if(!c) syntaxerror("internal error(5)");
1337 parameters_t s_getParameters(char*name)
1339 instance_t * i = dictionary_lookup(&instances, name);
1340 if(!i) syntaxerror("instance '%s' unknown(10)", name);
1341 return i->parameters;
1343 void s_startclip(char*instance, char*character, parameters_t p)
1345 character_t* c = dictionary_lookup(&characters, character);
1349 syntaxerror("character %s not known", character);
1351 i = s_addinstance(instance, c, currentdepth);
1353 m = s_instancepos(i->character->size, &p);
1355 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1356 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
1357 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1359 i->lastFrame= currentframe;
1361 stack[stackpos].tag = tag;
1362 stack[stackpos].type = 2;
1371 swf_SetTagPos(stack[stackpos].tag, 0);
1372 swf_GetPlaceObject(stack[stackpos].tag, &p);
1373 p.clipdepth = currentdepth;
1375 swf_ClearTag(stack[stackpos].tag);
1376 swf_SetPlaceObject(stack[stackpos].tag, &p);
1380 void s_put(char*instance, char*character, parameters_t p)
1382 character_t* c = dictionary_lookup(&characters, character);
1386 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
1389 i = s_addinstance(instance, c, currentdepth);
1391 m = s_instancepos(i->character->size, &p);
1393 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1394 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
1396 i->lastFrame = currentframe;
1400 void s_jump(char*instance, parameters_t p)
1402 instance_t* i = dictionary_lookup(&instances, instance);
1405 syntaxerror("instance %s not known", instance);
1409 m = s_instancepos(i->character->size, &p);
1411 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1412 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
1414 i->lastFrame = currentframe;
1417 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
1421 if(num==0 || num==1)
1423 ratio = (float)pos/(float)num;
1425 p.x = (p2->x-p1->x)*ratio + p1->x;
1426 p.y = (p2->y-p1->y)*ratio + p1->y;
1427 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
1428 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
1429 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
1430 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
1432 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
1433 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
1434 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
1435 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
1437 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
1438 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
1439 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
1440 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
1442 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
1443 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
1444 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
1445 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
1449 void s_change(char*instance, parameters_t p2)
1451 instance_t* i = dictionary_lookup(&instances, instance);
1455 int frame, allframes;
1457 syntaxerror("instance %s not known", instance);
1461 allframes = currentframe - i->lastFrame - 1;
1463 warning(".change ignored. can only .put/.change an object once per frame.");
1467 m = s_instancepos(i->character->size, &p2);
1468 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1469 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
1472 /* o.k., we got the start and end point set. Now iterate though all the
1473 tags in between, inserting object changes after each new frame */
1476 if(!t) syntaxerror("internal error(6)");
1478 while(frame < allframes) {
1479 if(t->id == ST_SHOWFRAME) {
1484 p = s_interpolate(&p1, &p2, frame, allframes);
1485 m = s_instancepos(i->character->size, &p); //needed?
1486 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
1487 i->lastFrame = currentframe;
1488 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
1490 if(frame == allframes)
1495 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
1499 void s_delinstance(char*instance)
1501 instance_t* i = dictionary_lookup(&instances, instance);
1503 syntaxerror("instance %s not known", instance);
1505 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
1506 swf_SetU16(tag, i->depth);
1507 dictionary_del(&instances, instance);
1510 void s_qchange(char*instance, parameters_t p)
1517 syntaxerror(".end unexpected");
1518 if(stack[stackpos-1].type == 0)
1520 else if(stack[stackpos-1].type == 1)
1522 else if(stack[stackpos-1].type == 2)
1524 else if(stack[stackpos-1].type == 3)
1526 else syntaxerror("internal error 1");
1529 // ------------------------------------------------------------------------
1531 typedef int command_func_t(map_t*args);
1533 SRECT parseBox(char*str)
1536 float xmin, xmax, ymin, ymax;
1537 char*x = strchr(str, 'x');
1539 if(!strcmp(str, "autocrop")) {
1540 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1544 d1 = strchr(x+1, ':');
1546 d2 = strchr(d1+1, ':');
1548 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1552 else if(d1 && !d2) {
1553 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1559 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1564 r.xmin = (SCOORD)(xmin*20);
1565 r.ymin = (SCOORD)(ymin*20);
1566 r.xmax = (SCOORD)(xmax*20);
1567 r.ymax = (SCOORD)(ymax*20);
1570 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1573 float parseFloat(char*str)
1577 int parseInt(char*str)
1582 if(str[0]=='+' || str[0]=='-')
1586 if(str[t]<'0' || str[t]>'9')
1587 syntaxerror("Not an Integer: \"%s\"", str);
1590 int parseTwip(char*str)
1594 if(str[0]=='+' || str[0]=='-') {
1599 dot = strchr(str, '.');
1603 return sign*parseInt(str)*20;
1605 int l=strlen(++dot);
1607 for(s=str;s<dot-1;s++)
1608 if(*s<'0' || *s>'9')
1609 syntaxerror("Not a coordinate: \"%s\"", str);
1611 if(*s<'0' || *s>'9')
1612 syntaxerror("Not a coordinate: \"%s\"", str);
1614 if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) {
1615 warning("precision loss: %s converted to twip", str);
1620 return sign*atoi(str)*20;
1622 return sign*atoi(str)*20+atoi(dot)*2;
1624 return sign*atoi(str)*20+atoi(dot)/5;
1629 int isPoint(char*str)
1631 if(strchr(str, '('))
1637 SPOINT parsePoint(char*str)
1641 int l = strlen(str);
1642 char*comma = strchr(str, ',');
1643 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1644 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1645 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1646 p.x = parseTwip(tmp);
1647 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1648 p.y = parseTwip(tmp);
1652 int parseColor2(char*str, RGBA*color)
1654 int l = strlen(str);
1658 struct {unsigned char r,g,b;char*name;} colors[] =
1659 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1660 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1661 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1662 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1663 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1664 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1665 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1666 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1667 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1668 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1669 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1670 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1674 if(str[0]=='#' && (l==7 || l==9)) {
1675 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1677 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1679 color->r = r; color->g = g; color->b = b; color->a = a;
1682 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1683 if(!strcmp(str, colors[t].name)) {
1688 color->r = r; color->g = g; color->b = b; color->a = a;
1694 RGBA parseColor(char*str)
1697 if(!parseColor2(str, &c))
1698 syntaxerror("Expression '%s' is not a color", str);
1702 typedef struct _muladd {
1707 MULADD parseMulAdd(char*str)
1710 char* str2 = (char*)malloc(strlen(str)+5);
1717 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1718 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1719 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1720 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1721 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1722 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1723 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1724 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1725 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1726 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1728 syntaxerror("'%s' is not a valid color transform expression", str);
1730 m.add = (int)(add*256);
1731 m.mul = (int)(mul*256);
1736 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1738 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1739 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1741 if(a<-32768) a=-32768;
1742 if(a>32767) a=32767;
1743 if(m<-32768) m=-32768;
1744 if(m>32767) m=32767;
1750 float parsePercent(char*str)
1752 int l = strlen(str);
1756 return atoi(str)/100.0;
1758 syntaxerror("Expression '%s' is not a percentage", str);
1761 int isPercent(char*str)
1763 return str[strlen(str)-1]=='%';
1765 int parseNewSize(char*str, int size)
1768 return parsePercent(str)*size;
1770 return (int)(atof(str)*20);
1773 int isColor(char*str)
1776 return parseColor2(str, &c);
1779 static char* lu(map_t* args, char*name)
1781 char* value = map_lookup(args, name);
1783 map_dump(args, stdout, "");
1784 syntaxerror("internal error 2: value %s should be set", name);
1789 static int c_flash(map_t*args)
1791 char* name = lu(args, "name");
1792 char* compressstr = lu(args, "compress");
1793 SRECT bbox = parseBox(lu(args, "bbox"));
1794 int version = parseInt(lu(args, "version"));
1795 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1797 RGBA color = parseColor(lu(args, "background"));
1798 if(!strcmp(name, "!default!") || override_outputname)
1801 if(!strcmp(compressstr, "default"))
1802 compress = version==6;
1803 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1805 else if(!strcmp(compressstr, "no"))
1807 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1809 s_swf(name, bbox, version, fps, compress, color);
1812 int isRelative(char*str)
1814 return !strncmp(str, "<plus>", 6) ||
1815 !strncmp(str, "<minus>", 7);
1817 char* getOffset(char*str)
1819 if(!strncmp(str, "<plus>", 6))
1821 if(!strncmp(str, "<minus>", 7))
1823 syntaxerror("internal error (347)");
1826 int getSign(char*str)
1828 if(!strncmp(str, "<plus>", 6))
1830 if(!strncmp(str, "<minus>", 7))
1832 syntaxerror("internal error (348)");
1835 static dictionary_t points;
1836 static mem_t mpoints;
1837 int points_initialized = 0;
1839 SPOINT getPoint(SRECT r, char*name)
1842 if(!strcmp(name, "center")) {
1844 p.x = (r.xmin + r.xmax)/2;
1845 p.y = (r.ymin + r.ymax)/2;
1849 if(points_initialized)
1850 l = (int)dictionary_lookup(&points, name);
1852 syntaxerror("Invalid point: \"%s\".", name);
1855 return *(SPOINT*)&mpoints.buffer[l];
1857 static int c_gradient(map_t*args)
1859 char*name = lu(args, "name");
1860 int radial= strcmp(lu(args, "radial"), "radial")?0:1;
1861 int rotate = parseInt(lu(args, "rotate"));
1865 syntaxerror("colon (:) expected");
1867 s_gradient(name, text, radial,rotate);
1870 static int c_point(map_t*args)
1872 char*name = lu(args, "name");
1876 if(!points_initialized) {
1877 dictionary_init(&points);
1879 points_initialized = 1;
1881 p.x = parseTwip(lu(args, "x"));
1882 p.y = parseTwip(lu(args, "y"));
1883 pos = mem_put(&mpoints, &p, sizeof(p));
1884 string_set(&s1, name);
1886 dictionary_put(&points, s1, (void*)pos);
1889 static int c_play(map_t*args)
1891 char*name = lu(args, "name");
1892 char*loop = lu(args, "loop");
1893 char*nomultiple = lu(args, "nomultiple");
1895 if(!strcmp(nomultiple, "nomultiple"))
1898 nm = parseInt(nomultiple);
1900 if(s_playsound(name, parseInt(loop), nm, 0)) {
1902 } else if(s_swf3action(name, "play")) {
1908 static int c_stop(map_t*args)
1910 char*name = lu(args, "name");
1912 if(s_playsound(name, 0,0,1)) {
1914 } else if(s_swf3action(name, "stop")) {
1917 syntaxerror("I don't know anything about sound/movie \"%s\"", name);
1921 static int c_nextframe(map_t*args)
1923 char*name = lu(args, "name");
1925 if(s_swf3action(name, "nextframe")) {
1928 syntaxerror("I don't know anything about movie \"%s\"", name);
1932 static int c_previousframe(map_t*args)
1934 char*name = lu(args, "name");
1936 if(s_swf3action(name, "previousframe")) {
1939 syntaxerror("I don't know anything about movie \"%s\"", name);
1943 static int c_placement(map_t*args, int type)
1945 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1948 char* luminancestr = lu(args, "luminance");
1949 char* scalestr = lu(args, "scale");
1950 char* scalexstr = lu(args, "scalex");
1951 char* scaleystr = lu(args, "scaley");
1952 char* rotatestr = lu(args, "rotate");
1953 char* shearstr = lu(args, "shear");
1954 char* xstr="", *pivotstr="";
1955 char* ystr="", *anglestr="";
1956 char*above = lu(args, "above"); /*FIXME*/
1957 char*below = lu(args, "below");
1958 char* rstr = lu(args, "red");
1959 char* gstr = lu(args, "green");
1960 char* bstr = lu(args, "blue");
1961 char* astr = lu(args, "alpha");
1962 char* pinstr = lu(args, "pin");
1963 char* as = map_lookup(args, "as");
1971 if(type==9) { // (?) .rotate or .arcchange
1972 pivotstr = lu(args, "pivot");
1973 anglestr = lu(args, "angle");
1975 xstr = lu(args, "x");
1976 ystr = lu(args, "y");
1979 luminance = parseMulAdd(luminancestr);
1982 luminance.mul = 256;
1986 if(scalexstr[0]||scaleystr[0])
1987 syntaxerror("scalex/scaley and scale cannot both be set");
1988 scalexstr = scaleystr = scalestr;
1991 if(type == 0 || type == 4) {
1993 character = lu(args, "character");
1994 parameters_clear(&p);
1995 } else if (type == 5) {
1996 character = lu(args, "name");
1997 parameters_clear(&p);
2000 p = s_getParameters(instance);
2005 if(isRelative(xstr)) {
2006 if(type == 0 || type == 4)
2007 syntaxerror("relative x values not allowed for initial put or startclip");
2008 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
2010 p.x = parseTwip(xstr);
2014 if(isRelative(ystr)) {
2015 if(type == 0 || type == 4)
2016 syntaxerror("relative y values not allowed for initial put or startclip");
2017 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
2019 p.y = parseTwip(ystr);
2023 /* scale, scalex, scaley */
2025 oldbbox = s_getCharBBox(character);
2027 oldbbox = s_getInstanceBBox(instance);
2029 oldwidth = oldbbox.xmax - oldbbox.xmin;
2030 oldheight = oldbbox.ymax - oldbbox.ymin;
2032 if(oldwidth==0) p.scalex = 1.0;
2035 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
2039 if(oldheight==0) p.scaley = 1.0;
2042 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
2048 if(isRelative(rotatestr)) {
2049 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
2051 p.rotate = parseFloat(rotatestr);
2057 if(isRelative(shearstr)) {
2058 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
2060 p.shear = parseFloat(shearstr);
2065 if(isPoint(pivotstr))
2066 p.pivot = parsePoint(pivotstr);
2068 p.pivot = getPoint(oldbbox, pivotstr);
2072 p.pin = parsePoint(pinstr);
2074 p.pin = getPoint(oldbbox, pinstr);
2077 /* color transform */
2079 if(rstr[0] || luminancestr[0]) {
2082 r = parseMulAdd(rstr);
2084 r.add = p.cxform.r0;
2085 r.mul = p.cxform.r1;
2087 r = mergeMulAdd(r, luminance);
2088 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
2090 if(gstr[0] || luminancestr[0]) {
2093 g = parseMulAdd(gstr);
2095 g.add = p.cxform.g0;
2096 g.mul = p.cxform.g1;
2098 g = mergeMulAdd(g, luminance);
2099 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
2101 if(bstr[0] || luminancestr[0]) {
2104 b = parseMulAdd(bstr);
2106 b.add = p.cxform.b0;
2107 b.mul = p.cxform.b1;
2109 b = mergeMulAdd(b, luminance);
2110 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
2113 MULADD a = parseMulAdd(astr);
2114 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
2118 s_put(instance, character, p);
2120 s_change(instance, p);
2122 s_qchange(instance, p);
2124 s_jump(instance, p);
2126 s_startclip(instance, character, p);
2127 else if(type == 5) {
2129 s_buttonput(character, as, p);
2131 s_buttonput(character, "shape", p);
2136 static int c_put(map_t*args)
2138 c_placement(args, 0);
2141 static int c_change(map_t*args)
2143 c_placement(args, 1);
2146 static int c_qchange(map_t*args)
2148 c_placement(args, 2);
2151 static int c_arcchange(map_t*args)
2153 c_placement(args, 2);
2156 static int c_jump(map_t*args)
2158 c_placement(args, 3);
2161 static int c_startclip(map_t*args)
2163 c_placement(args, 4);
2166 static int c_show(map_t*args)
2168 c_placement(args, 5);
2171 static int c_del(map_t*args)
2173 char*instance = lu(args, "name");
2174 s_delinstance(instance);
2177 static int c_end(map_t*args)
2182 static int c_sprite(map_t*args)
2184 char* name = lu(args, "name");
2188 static int c_frame(map_t*args)
2190 char*framestr = lu(args, "n");
2191 char*cutstr = lu(args, "cut");
2192 char*name = lu(args, "name");
2195 if(strcmp(cutstr, "no"))
2197 if(isRelative(framestr)) {
2198 frame = s_getframe();
2199 if(getSign(framestr)<0)
2200 syntaxerror("relative frame expressions must be positive");
2201 frame += parseInt(getOffset(framestr));
2204 frame = parseInt(framestr);
2205 if(s_getframe() >= frame
2206 && !(frame==0 && s_getframe()==frame)) // equality is o.k. for frame 0
2207 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
2209 s_frame(frame, cut, name);
2212 static int c_primitive(map_t*args)
2214 char*name = lu(args, "name");
2215 char*command = lu(args, "commandname");
2216 int width=0, height=0, r=0;
2217 int linewidth = parseTwip(lu(args, "line"));
2218 char*colorstr = lu(args, "color");
2219 RGBA color = parseColor(colorstr);
2220 char*fillstr = lu(args, "fill");
2227 if(!strcmp(command, "circle"))
2229 else if(!strcmp(command, "filled"))
2233 width = parseTwip(lu(args, "width"));
2234 height = parseTwip(lu(args, "height"));
2235 } else if (type==1) {
2236 r = parseTwip(lu(args, "r"));
2237 } else if (type==2) {
2238 outline = lu(args, "outline");
2241 if(!strcmp(fillstr, "fill"))
2243 if(!strcmp(fillstr, "none"))
2245 if(width<0 || height<0 || linewidth<0 || r<0)
2246 syntaxerror("values width, height, line, r must be positive");
2248 if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
2249 else if(type==1) s_circle(name, r, color, linewidth, fillstr);
2250 else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
2254 static int c_textshape(map_t*args)
2256 char*name = lu(args, "name");
2257 char*text = lu(args, "text");
2258 char*font = lu(args, "font");
2259 float size = parsePercent(lu(args, "size"));
2261 s_textshape(name, font, size, text);
2265 static int c_swf(map_t*args)
2267 char*name = lu(args, "name");
2268 char*filename = lu(args, "filename");
2269 char*command = lu(args, "commandname");
2270 if(!strcmp(command, "shape"))
2271 warning("Please use .swf instead of .shape");
2272 s_includeswf(name, filename);
2276 static int c_font(map_t*args)
2278 char*name = lu(args, "name");
2279 char*filename = lu(args, "filename");
2280 s_font(name, filename);
2284 static int c_sound(map_t*args)
2286 char*name = lu(args, "name");
2287 char*filename = lu(args, "filename");
2288 s_sound(name, filename);
2292 static int c_text(map_t*args)
2294 char*name = lu(args, "name");
2295 char*text = lu(args, "text");
2296 char*font = lu(args, "font");
2297 float size = parsePercent(lu(args, "size"));
2298 RGBA color = parseColor(lu(args, "color"));
2299 s_text(name, font, text, (int)(size*100), color);
2303 static int c_soundtrack(map_t*args)
2308 static int c_quicktime(map_t*args)
2310 char*name = lu(args, "name");
2311 char*url = lu(args, "url");
2312 s_quicktime(name, url);
2316 static int c_image(map_t*args)
2318 char*command = lu(args, "commandname");
2319 char*name = lu(args, "name");
2320 char*filename = lu(args, "filename");
2321 if(!strcmp(command,"jpeg")) {
2322 int quality = (int)(parsePercent(lu(args, "quality"))*100);
2323 s_image(name, "jpeg", filename, quality);
2325 s_image(name, "png", filename, 0);
2330 static int c_outline(map_t*args)
2332 char*name = lu(args, "name");
2333 char*format = lu(args, "format");
2337 syntaxerror("colon (:) expected");
2339 s_outline(name, format, text);
2343 int fakechar(map_t*args)
2345 char*name = lu(args, "name");
2346 s_box(name, 0, 0, black, 20, 0);
2350 static int c_egon(map_t*args) {return fakechar(args);}
2351 static int c_button(map_t*args) {
2352 char*name = lu(args, "name");
2356 static int current_button_flags = 0;
2357 static int c_on_press(map_t*args)
2359 char*position = lu(args, "position");
2361 if(!strcmp(position, "inside")) {
2362 current_button_flags |= BC_OVERUP_OVERDOWN;
2363 } else if(!strcmp(position, "outside")) {
2364 //current_button_flags |= BC_IDLE_OUTDOWN;
2365 syntaxerror("IDLE_OVERDOWN not supported by SWF");
2366 } else if(!strcmp(position, "anywhere")) {
2367 current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
2370 if(type == RAWDATA) {
2372 s_buttonaction(current_button_flags, action);
2373 current_button_flags = 0;
2379 static int c_on_release(map_t*args)
2381 char*position = lu(args, "position");
2383 if(!strcmp(position, "inside")) {
2384 current_button_flags |= BC_OVERDOWN_OVERUP;
2385 } else if(!strcmp(position, "outside")) {
2386 current_button_flags |= BC_OUTDOWN_IDLE;
2387 } else if(!strcmp(position, "anywhere")) {
2388 current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
2391 if(type == RAWDATA) {
2393 s_buttonaction(current_button_flags, action);
2394 current_button_flags = 0;
2400 static int c_on_move_in(map_t*args)
2402 char*position = lu(args, "state");
2404 if(!strcmp(position, "pressed")) {
2405 current_button_flags |= BC_OUTDOWN_OVERDOWN;
2406 } else if(!strcmp(position, "not_pressed")) {
2407 current_button_flags |= BC_IDLE_OVERUP;
2408 } else if(!strcmp(position, "any")) {
2409 current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
2412 if(type == RAWDATA) {
2414 s_buttonaction(current_button_flags, action);
2415 current_button_flags = 0;
2421 static int c_on_move_out(map_t*args)
2423 char*position = lu(args, "state");
2425 if(!strcmp(position, "pressed")) {
2426 current_button_flags |= BC_OVERDOWN_OUTDOWN;
2427 } else if(!strcmp(position, "not_pressed")) {
2428 current_button_flags |= BC_OVERUP_IDLE;
2429 } else if(!strcmp(position, "any")) {
2430 current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
2433 if(type == RAWDATA) {
2435 s_buttonaction(current_button_flags, action);
2436 current_button_flags = 0;
2442 static int c_on_key(map_t*args)
2444 char*key = lu(args, "key");
2446 if(strlen(key)==1) {
2449 current_button_flags |= 0x4000 + (key[0]*0x200);
2451 syntaxerror("invalid character: %c"+key[0]);
2456 <ctrl-x> = 0x200*(x-'a')
2460 syntaxerror("invalid key: %s",key);
2463 if(type == RAWDATA) {
2465 s_buttonaction(current_button_flags, action);
2466 current_button_flags = 0;
2473 static int c_edittext(map_t*args)
2475 //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
2476 char*name = lu(args, "name");
2477 char*font = lu(args, "font");
2478 int size = (int)(1024*parsePercent(lu(args, "size")));
2479 int width = parseTwip(lu(args, "width"));
2480 int height = parseTwip(lu(args, "height"));
2481 char*text = lu(args, "text");
2482 RGBA color = parseColor(lu(args, "color"));
2483 int maxlength = parseInt(lu(args, "maxlength"));
2484 char*variable = lu(args, "variable");
2485 char*passwordstr = lu(args, "password");
2486 char*wordwrapstr = lu(args, "wordwrap");
2487 char*multilinestr = lu(args, "multiline");
2488 char*htmlstr = lu(args, "html");
2489 char*noselectstr = lu(args, "noselect");
2490 char*readonlystr = lu(args, "readonly");
2491 char*borderstr = lu(args, "border");
2494 if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
2495 if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
2496 if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
2497 if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
2498 if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
2499 if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
2500 if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
2502 s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags);
2506 static int c_morphshape(map_t*args) {return fakechar(args);}
2507 static int c_movie(map_t*args) {return fakechar(args);}
2509 static int c_texture(map_t*args) {return 0;}
2511 static int c_action(map_t*args)
2514 if(type != RAWDATA) {
2515 syntaxerror("colon (:) expected");
2525 command_func_t* func;
2528 {{"flash", c_flash, "bbox=autocrop background=black version=5 fps=50 name=!default! @compress=default"},
2529 {"frame", c_frame, "n=<plus>1 name= @cut=no"},
2530 // "import" type stuff
2531 {"swf", c_swf, "name filename"},
2532 {"shape", c_swf, "name filename"},
2533 {"jpeg", c_image, "name filename quality=80%"},
2534 {"png", c_image, "name filename"},
2535 {"movie", c_movie, "name filename"},
2536 {"sound", c_sound, "name filename"},
2537 {"font", c_font, "name filename"},
2538 {"soundtrack", c_soundtrack, "filename"},
2539 {"quicktime", c_quicktime, "url"},
2541 // generators of primitives
2543 {"point", c_point, "name x=0 y=0"},
2544 {"gradient", c_gradient, "name @radial=0 rotate=0"},
2545 {"outline", c_outline, "name format=simple"},
2546 {"textshape", c_textshape, "name font size=100% text"},
2548 // character generators
2549 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
2550 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
2551 {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
2553 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
2554 {"text", c_text, "name text font size=100% color=white"},
2555 {"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"},
2556 {"morphshape", c_morphshape, "name start end"},
2557 {"button", c_button, "name"},
2558 {"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="},
2559 {"on_press", c_on_press, "position=inside"},
2560 {"on_release", c_on_release, "position=anywhere"},
2561 {"on_move_in", c_on_move_in, "state=not_pressed"},
2562 {"on_move_out", c_on_move_out, "state=not_pressed"},
2563 {"on_key", c_on_key, "key=any"},
2566 {"play", c_play, "name loop=0 @nomultiple=0"},
2567 {"stop", c_stop, "name"},
2568 {"nextframe", c_nextframe, "name"},
2569 {"previousframe", c_previousframe, "name"},
2571 // object placement tags
2572 {"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="},
2573 {"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="},
2574 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2575 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2576 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2577 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
2578 {"del", c_del, "name"},
2579 // virtual object placement
2580 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
2582 // commands which start a block
2583 //startclip (see above)
2584 {"sprite", c_sprite, "name"},
2585 {"action", c_action, ""},
2591 static map_t parseArguments(char*command, char*pattern)
2607 string_set(&t1, "commandname");
2608 string_set(&t2, command);
2609 map_put(&result, t1, t2);
2611 if(!pattern || !*pattern)
2618 if(!strncmp("<i> ", x, 3)) {
2620 if(type == COMMAND || type == RAWDATA) {
2622 syntaxerror("character name expected");
2624 name[pos].str = "instance";
2626 value[pos].str = text;
2627 value[pos].len = strlen(text);
2631 if(type == ASSIGNMENT)
2634 name[pos].str = "character";
2636 value[pos].str = text;
2637 value[pos].len = strlen(text);
2645 isboolean[pos] = (x[0] =='@');
2658 name[pos].len = d-x;
2663 name[pos].len = e-x;
2664 value[pos].str = e+1;
2665 value[pos].len = d-e-1;
2673 /* for(t=0;t<len;t++) {
2674 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
2675 isboolean[t]?"(boolean)":"");
2680 if(type == RAWDATA || type == COMMAND) {
2685 // first, search for boolean arguments
2686 for(pos=0;pos<len;pos++)
2688 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
2690 if(type == ASSIGNMENT)
2692 value[pos].str = text;
2693 value[pos].len = strlen(text);
2694 /*printf("setting boolean parameter %s (to %s)\n",
2695 strdup_n(name[pos], namelen[pos]),
2696 strdup_n(value[pos], valuelen[pos]));*/
2701 // second, search for normal arguments
2703 for(pos=0;pos<len;pos++)
2705 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
2706 (type != ASSIGNMENT && !set[pos])) {
2708 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
2710 if(type == ASSIGNMENT)
2713 value[pos].str = text;
2714 value[pos].len = strlen(text);
2716 printf("setting parameter %s (to %s)\n",
2717 strdup_n(name[pos].str, name[pos].len),
2718 strdup_n(value[pos].str, value[pos].len));
2724 syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
2728 for(t=0;t<len;t++) {
2729 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
2732 for(t=0;t<len;t++) {
2733 if(value[t].str && value[t].str[0] == '*') {
2734 //relative default- take value from some other parameter
2736 for(s=0;s<len;s++) {
2737 if(value[s].len == value[t].len-1 &&
2738 !strncmp(&value[t].str[1], value[s].str, value[s].len))
2739 value[t].str = value[s].str;
2742 if(value[t].str == 0) {
2744 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
2748 /* ok, now construct the dictionary from the parameters */
2752 map_put(&result, name[t], value[t]);
2756 static void parseArgumentsForCommand(char*command)
2761 msg("<verbose> parse Command: %s (line %d)", command, line);
2763 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
2764 if(!strcmp(arguments[t].command, command)) {
2766 /* ugly hack- will be removed soon (once documentation and .sc generating
2767 utilities have been changed) */
2768 if(!strcmp(command, "swf") && !stackpos) {
2769 warning("Please use .flash instead of .swf- this will be mandatory soon");
2774 args = parseArguments(command, arguments[t].arguments);
2780 syntaxerror("command %s not known", command);
2782 // catch missing .flash directives at the beginning of a file
2783 if(strcmp(command, "flash") && !stackpos)
2785 syntaxerror("No movie defined- use .flash first");
2789 printf(".%s\n", command);fflush(stdout);
2790 map_dump(&args, stdout, "\t");fflush(stdout);
2793 (*arguments[nr].func)(&args);
2795 /*if(!strcmp(command, "button") ||
2796 !strcmp(command, "action")) {
2799 if(type == COMMAND) {
2800 if(!strcmp(text, "end"))
2814 int main (int argc,char ** argv)
2817 processargs(argc, argv);
2818 initLog(0,-1,0,0,-1,verbose);
2821 args_callback_usage(argv[0]);
2825 file = generateTokens(filename);
2827 printf("parser returned error.\n");
2833 while(!noMoreTokens()) {
2836 syntaxerror("command expected");
2837 parseArgumentsForCommand(text);