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 file is distributed under the GPL, see file COPYING for details */
16 #define logf logarithmf // logf is also used by ../lib/log.h
19 #include "../config.h"
20 #include "../lib/rfxswf.h"
21 #include "../lib/log.h"
22 #include "../lib/args.h"
29 static char * filename = 0;
30 static char * outputname = "output.swf";
31 static int verbose = 2;
32 static int override_outputname = 0;
34 static struct options_t options[] =
42 int args_callback_option(char*name,char*val)
44 if(!strcmp(name, "V")) {
45 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
48 else if(!strcmp(name, "o")) {
50 override_outputname = 1;
53 else if(!strcmp(name, "v")) {
58 printf("Unknown option: -%s\n", name);
63 int args_callback_longoption(char*name,char*val)
65 return args_long2shortoption(options, name, val);
67 void args_callback_usage(char*name)
69 printf("Usage: %s [-o filename] file.wav\n", name);
70 printf("\t-v , --verbose\t\t\t Be more verbose\n");
71 printf("\t-o , --output filename\t\t set output filename (default: output.swf)\n");
72 printf("\t-V , --version\t\t\t Print program version and exit\n");
74 int args_callback_command(char*name,char*val)
77 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
84 static struct token_t* file;
93 static void syntaxerror(char*format, ...)
97 va_start(arglist, format);
98 vsprintf(buf, format, arglist);
100 printf("\"%s\", line %d column %d: error- %s\n", filename, line, column, buf);
104 static void warning(char*format, ...)
108 va_start(arglist, format);
109 vsprintf(buf, format, arglist);
111 printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
114 static void readToken()
116 type = file[pos].type;
118 syntaxerror("unexpected end of file");
120 text = file[pos].text;
121 textlen = strlen(text);
122 line = file[pos].line;
123 column = file[pos].column;
125 //printf("---> %d(%s) %s\n", type, type_names[type], text);
128 static void pushBack()
131 if(!pos) syntaxerror("internal error 3");
136 textlen = strlen(text);
139 column = file[p].column;
142 static int noMoreTokens()
144 if(file[pos].type == END)
149 // ------------------------------ swf routines ----------------------------
153 int type; //0=swf, 1=sprite, 2=clip
159 /* for sprites (1): */
165 dictionary_t oldinstances;
169 static int stackpos = 0;
171 static dictionary_t characters;
172 static char idmap[65536];
173 static TAG*tag = 0; //current tag
175 static int id; //current character id
176 static int currentframe; //current frame in current level
177 static SRECT currentrect; //current bounding box in current level
178 static U16 currentdepth;
179 static dictionary_t instances;
180 static dictionary_t fonts;
181 static dictionary_t sounds;
183 typedef struct _parameters {
185 float scalex, scaley;
193 typedef struct _character {
199 typedef struct _instance {
200 character_t*character;
202 parameters_t parameters;
203 TAG* lastTag; //last tag which set the object
204 U16 lastFrame; //frame lastTag is in
207 static void character_init(character_t*c)
209 memset(c, 0, sizeof(character_t));
211 static character_t* character_new()
214 c = (character_t*)malloc(sizeof(character_t));
218 static void instance_init(instance_t*i)
220 memset(i, 0, sizeof(instance_t));
222 static instance_t* instance_new()
225 c = (instance_t*)malloc(sizeof(instance_t));
230 static void incrementid()
234 syntaxerror("Out of character ids.");
239 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
241 character_t* c = character_new();
243 c->definingTag = ctag;
246 if(dictionary_lookup(&characters, name))
247 syntaxerror("character %s defined twice", name);
248 dictionary_put2(&characters, name, c);
250 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
252 swf_SetString(tag, name);
253 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
256 swf_SetString(tag, name);
258 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
260 instance_t* i = instance_new();
263 //swf_GetMatrix(0, &i->matrix);
264 if(dictionary_lookup(&instances, name))
265 syntaxerror("object %s defined twice", name);
266 dictionary_put2(&instances, name, i);
270 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)
273 p->scalex = scalex; p->scaley = scaley;
274 p->pin = pin; p->pivot = pivot;
275 p->rotate = rotate; p->cxform = cxform;
279 static void parameters_clear(parameters_t*p)
282 p->scalex = 1.0; p->scaley = 1.0;
283 p->pin.x = 1; p->pin.y = 0;
284 p->pivot.x = 0; p->pivot.y = 0;
287 swf_GetCXForm(0, &p->cxform, 1);
290 static void makeMatrix(MATRIX*m, parameters_t*p)
299 sx = p->scalex*cos(p->rotate/360*2*3.14159265358979);
300 r1 = -p->scalex*sin(p->rotate/360*2*3.14159265358979)+sx*p->shear;
301 r0 = p->scaley*sin(p->rotate/360*2*3.14159265358979);
302 sy = p->scaley*cos(p->rotate/360*2*3.14159265358979)+r0*p->shear;
304 m->sx = (int)(sx*65536+0.5);
305 m->r1 = (int)(r1*65536+0.5);
306 m->r0 = (int)(r0*65536+0.5);
307 m->sy = (int)(sy*65536+0.5);
311 h = swf_TurnPoint(p->pin, m);
316 static MATRIX s_instancepos(instance_t*i, parameters_t*p)
321 r = swf_TurnRect(i->character->size, &m);
322 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
323 currentrect.xmax == 0 && currentrect.ymax == 0)
326 swf_ExpandRect2(¤trect, &r);
330 void s_swf(char*name, SRECT r, int version, int fps, int compress)
332 SWF*swf = (SWF*)malloc(sizeof(SWF));
336 syntaxerror(".swf blocks can't be nested");
338 memset(swf, 0, sizeof(swf));
339 swf->fileVersion = version;
341 swf->frameRate = fps;
342 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
343 swf->compressed = compress;
344 rgb.r = 0x00;rgb.g = 0x00;rgb.b = 0x00;
345 swf_SetRGB(tag,&rgb);
347 if(stackpos==sizeof(stack)/sizeof(stack[0]))
348 syntaxerror("too many levels of recursion");
350 dictionary_init(&characters);
351 dictionary_init(&instances);
352 dictionary_init(&fonts);
353 dictionary_init(&sounds);
355 memset(&stack[stackpos], 0, sizeof(stack[0]));
356 stack[stackpos].type = 0;
357 stack[stackpos].filename = strdup(name);
358 stack[stackpos].swf = swf;
359 stack[stackpos].oldframe = -1;
364 memset(¤trect, 0, sizeof(currentrect));
367 memset(idmap, 0, sizeof(idmap));
371 void s_sprite(char*name)
373 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
374 swf_SetU16(tag, id); //id
375 swf_SetU16(tag, 0); //frames
377 memset(&stack[stackpos], 0, sizeof(stack[0]));
378 stack[stackpos].type = 1;
379 stack[stackpos].oldframe = currentframe;
380 stack[stackpos].olddepth = currentdepth;
381 stack[stackpos].oldrect = currentrect;
382 stack[stackpos].oldinstances = instances;
383 stack[stackpos].tag = tag;
384 stack[stackpos].id = id;
385 stack[stackpos].name = strdup(name);
387 /* FIXME: those four fields should be bundled together */
388 dictionary_init(&instances);
391 memset(¤trect, 0, sizeof(currentrect));
397 static void s_endSprite()
399 SRECT r = currentrect;
402 /* TODO: before clearing, prepend "<spritename>." to names and
403 copy into old instances dict */
404 dictionary_clear(&instances);
406 currentframe = stack[stackpos].oldframe;
407 currentrect = stack[stackpos].oldrect;
408 currentdepth = stack[stackpos].olddepth;
409 instances = stack[stackpos].oldinstances;
410 tag = swf_InsertTag(tag, ST_END);
412 tag = stack[stackpos].tag;
415 syntaxerror("internal error(7)");
417 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
418 free(stack[stackpos].name);
421 static void s_endSWF()
428 swf = stack[stackpos].swf;
429 filename = stack[stackpos].filename;
431 tag = swf_InsertTag(tag, ST_SHOWFRAME);
432 tag = swf_InsertTag(tag, ST_END);
434 swf_OptimizeTagOrder(swf);
436 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin))
437 swf->movieSize = currentrect; /* "autocrop" */
439 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
440 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
441 swf->movieSize.ymax += 20;
444 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
446 syntaxerror("couldn't create output file %s", filename);
449 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
451 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
455 dictionary_clear(&instances);
456 dictionary_clear(&characters);
457 dictionary_clear(&fonts);
458 dictionary_clear(&sounds);
467 if(stack[stackpos-1].type == 0)
468 syntaxerror("End of file encountered in .swf block");
469 if(stack[stackpos-1].type == 1)
470 syntaxerror("End of file encountered in .sprite block");
471 if(stack[stackpos-1].type == 2)
472 syntaxerror("End of file encountered in .clip block");
484 for(t=currentframe;t<nr;t++) {
485 tag = swf_InsertTag(tag, ST_SHOWFRAME);
490 RGBA black={r:0,g:0,b:0,a:0};
491 void s_box(char*name, int width, int height, RGBA color, int linewidth, RGBA fill, int dofill)
496 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
498 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
500 fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
502 r.xmin = -linewidth-linewidth/2;
503 r.ymin = -linewidth-linewidth/2;
504 r.xmax = width+linewidth+linewidth/2;
505 r.ymax = height+linewidth+linewidth/2;
507 swf_SetShapeHeader(tag,s);
508 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
509 swf_ShapeSetLine(tag,s,width,0);
510 swf_ShapeSetLine(tag,s,0,height);
511 swf_ShapeSetLine(tag,s,-width,0);
512 swf_ShapeSetLine(tag,s,0,-height);
513 swf_ShapeSetEnd(tag);
516 s_addcharacter(name, id, tag, r);
520 void s_circle(char*name, int r, RGBA color, int linewidth, RGBA fill, int dofill)
525 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
527 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
529 fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
531 rect.xmin = -linewidth-linewidth/2;
532 rect.ymin = -linewidth-linewidth/2;
533 rect.xmax = 2*r+linewidth+linewidth/2;
534 rect.ymax = 2*r+linewidth+linewidth/2;
536 swf_SetRect(tag,&rect);
537 swf_SetShapeHeader(tag,s);
538 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
539 swf_ShapeSetCircle(tag, s, r,r,r,r);
540 swf_ShapeSetEnd(tag);
543 s_addcharacter(name, id, tag, rect);
547 void s_textshape(char*name, char*fontname, char*_text, RGBA color, int linewidth, RGBA fill, int dofill)
553 U8*text = (U8*)_text;
556 font = dictionary_lookup(&fonts, fontname);
558 syntaxerror("font \"%s\" not known!", fontname);
560 syntaxerror("textshapes must be filled", fontname);
562 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
563 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
564 s_box(name, 0, 0, black, 20, black, 0);
567 g = font->ascii2glyph[text[0]];
568 rect = font->layout->bounds[g];
571 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
573 fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
575 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
577 swf_SetRect(tag, &rect);
578 swf_SetShapeStyles(tag, s);
579 swf_SetSimpleShape(tag, font->glyph[g].shape);
582 s_addcharacter(name, id, tag, rect);
585 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
590 font = dictionary_lookup(&fonts, fontname);
592 syntaxerror("font \"%s\" not known!", fontname);
594 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
596 if(!font->numchars) {
597 s_box(name, 0, 0, black, 20, black, 0);
600 r = swf_SetDefineText(tag, font, &color, text, size);
602 s_addcharacter(name, id, tag, r);
606 void dumpSWF(SWF*swf)
608 TAG* tag = swf->firstTag;
609 printf("vvvvvvvvvvvvvvvvvvvvv\n");
611 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
614 printf("^^^^^^^^^^^^^^^^^^^^^\n");
617 void s_font(char*name, char*filename)
622 f = open(filename,O_RDONLY);
624 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
625 font = (SWFFONT*)malloc(sizeof(SWFFONT));
626 memset(font, 0, sizeof(SWFFONT));
627 dictionary_put2(&fonts, name, font);
631 if (swf_ReadSWF(f,&swf)>=0) {
632 swf_FontExtract(&swf, 0x4e46, &font);
637 syntaxerror("File \"%s\" isn't a valid rfxswf font file", filename);
642 /* fix the layout. Only needed for old fonts */
644 for(t=0;t<font->numchars;t++) {
645 font->glyph[t].advance = 0;
648 swf_FontCreateLayout(font);
652 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
653 swf_FontSetDefine2(tag, font);
656 if(dictionary_lookup(&fonts, name))
657 syntaxerror("font %s defined twice", name);
658 dictionary_put2(&fonts, name, font);
661 typedef struct _sound_t
667 void s_sound(char*name, char*filename)
669 struct WAV wav, wav2;
674 if(!readWAV(filename, &wav)) {
675 warning("Couldn't read wav file \"%s\"", filename);
679 convertWAV2mono(&wav, &wav2, 44100);
680 samples = (U16*)wav2.data;
681 numsamples = wav2.size/2;
685 tag = swf_InsertTag(tag, ST_DEFINESOUND);
686 swf_SetU16(tag, id); //id
687 swf_SetSoundDefine(tag, samples, numsamples);
689 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
693 if(dictionary_lookup(&sounds, name))
694 syntaxerror("sound %s defined twice", name);
695 dictionary_put2(&sounds, name, sound);
703 void s_playsound(char*name, int loops, int nomultiple, int stop)
705 sound_t* sound = dictionary_lookup(&sounds, name);
708 syntaxerror("Don't know anything about sound \"%s\"", name);
710 tag = swf_InsertTag(tag, ST_STARTSOUND);
711 swf_SetU16(tag, sound->id); //id
712 memset(&info, 0, sizeof(info));
715 info.nomultiple = nomultiple;
716 swf_SetSoundInfo(tag, &info);
719 void s_shape(char*name, char*filename)
727 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
728 f = open(filename,O_RDONLY);
730 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
731 s_box(name, 0, 0, black, 20, black, 0);
734 if (swf_ReadSWF(f,&swf)<0) {
735 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
736 s_box(name, 0, 0, black, 20, black, 0);
741 /* FIXME: The following sets the bounding Box for the character.
742 It is wrong for two reasons:
743 a) It may be too small (in case objects in the movie clip at the borders)
744 b) it may be too big (because the poor movie never got autocropped)
748 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
752 swf_Relocate(&swf, idmap);
758 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
759 if(cutout[t] == ftag->id) {
763 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
765 if(ftag->id == ST_END)
769 /* We simply dump all tags right after the sprite
770 header, relying on the fact that swf_OptimizeTagOrder() will
771 sort things out for us later.
772 We also rely on the fact that the imported SWF is well-formed.
774 tag = swf_InsertTag(tag, ftag->id);
775 swf_SetBlock(tag, ftag->data, ftag->len);
779 syntaxerror("Included file %s contains errors", filename);
780 tag = swf_InsertTag(tag, ST_END);
784 s_addcharacter(name, id, tag, r);
787 SRECT s_getCharBBox(char*name)
789 character_t* c = dictionary_lookup(&characters, name);
790 if(!c) syntaxerror("character '%s' unknown(2)", name);
793 SRECT s_getInstanceBBox(char*name)
795 instance_t * i = dictionary_lookup(&instances, name);
797 if(!i) syntaxerror("instance '%s' unknown(4)", name);
799 if(!c) syntaxerror("internal error(5)");
802 parameters_t s_getParameters(char*name)
804 instance_t * i = dictionary_lookup(&instances, name);
805 if(!i) syntaxerror("instance '%s' unknown(10)", name);
806 return i->parameters;
808 void s_startclip(char*instance, char*character, parameters_t p)
810 character_t* c = dictionary_lookup(&characters, character);
814 syntaxerror("character %s not known", character);
816 i = s_addinstance(instance, c, currentdepth);
818 m = s_instancepos(i, &p);
820 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
821 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
822 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
824 i->lastFrame= currentframe;
826 stack[stackpos].tag = tag;
827 stack[stackpos].type = 2;
836 swf_SetTagPos(stack[stackpos].tag, 0);
837 swf_GetPlaceObject(stack[stackpos].tag, &p);
838 p.clipdepth = currentdepth;
839 swf_ClearTag(stack[stackpos].tag);
840 swf_SetPlaceObject(stack[stackpos].tag, &p);
844 void s_put(char*instance, char*character, parameters_t p)
846 character_t* c = dictionary_lookup(&characters, character);
850 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
853 i = s_addinstance(instance, c, currentdepth);
855 m = s_instancepos(i, &p);
857 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
858 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
860 i->lastFrame = currentframe;
864 void s_jump(char*instance, parameters_t p)
866 instance_t* i = dictionary_lookup(&instances, instance);
869 syntaxerror("instance %s not known", instance);
873 m = s_instancepos(i, &p);
875 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
876 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
878 i->lastFrame = currentframe;
881 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
887 ratio = (float)pos/(float)num;
889 p.x = (p2->x-p1->x)*ratio + p1->x;
890 p.y = (p2->y-p1->y)*ratio + p1->y;
891 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
892 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
893 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
894 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
896 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
897 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
898 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
899 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
901 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
902 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
903 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
904 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
906 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
907 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
908 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
909 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
913 void s_change(char*instance, parameters_t p2)
915 instance_t* i = dictionary_lookup(&instances, instance);
919 int frame, allframes;
921 syntaxerror("instance %s not known", instance);
925 allframes = currentframe - i->lastFrame - 1;
927 warning(".change ignored. can only .put/.change an object once per frame.");
931 m = s_instancepos(i, &p2);
932 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
933 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
936 /* o.k., we got the start and end point set. Now iterate though all the
937 tags in between, inserting object changes after each new frame */
940 if(!t) syntaxerror("internal error(6)");
942 while(frame < allframes) {
943 if(t->id == ST_SHOWFRAME) {
948 p = s_interpolate(&p1, &p2, frame, allframes);
949 m = s_instancepos(i, &p); //needed?
950 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
951 i->lastFrame = currentframe;
952 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
954 if(frame == allframes)
959 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
963 void s_delinstance(char*instance)
965 instance_t* i = dictionary_lookup(&instances, instance);
967 syntaxerror("instance %s not known", instance);
969 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
970 swf_SetU16(tag, i->depth);
971 dictionary_del(&instances, instance);
974 void s_qchange(char*instance, parameters_t p)
981 syntaxerror(".end unexpected");
982 if(stack[stackpos-1].type == 0)
984 else if(stack[stackpos-1].type == 1)
986 else if(stack[stackpos-1].type == 2)
988 else syntaxerror("internal error 1");
991 // ------------------------------------------------------------------------
993 typedef int command_func_t(map_t*args);
995 SRECT parseBox(char*str)
998 float xmin, xmax, ymin, ymax;
999 char*x = strchr(str, 'x');
1001 if(!strcmp(str, "autocrop")) {
1002 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1006 d1 = strchr(x+1, ':');
1008 d2 = strchr(d1+1, ':');
1010 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1014 else if(d1 && !d2) {
1015 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1021 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1026 r.xmin = (SCOORD)(xmin*20);
1027 r.ymin = (SCOORD)(ymin*20);
1028 r.xmax = (SCOORD)(xmax*20);
1029 r.ymax = (SCOORD)(ymax*20);
1032 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1035 float parseFloat(char*str)
1039 int parseInt(char*str)
1044 if(str[0]=='+' || str[0]=='-')
1048 if(str[t]<'0' || str[t]>'9')
1049 syntaxerror("Not an Integer: \"%s\"", str);
1052 int parseTwip(char*str)
1054 char*dot = strchr(str, '.');
1058 return parseInt(str)*20;
1060 int l=strlen(++dot);
1062 for(s=str;s<dot-1;s++)
1063 if(*s<'0' || *s>'9')
1064 syntaxerror("Not a coordinate: \"%s\"", str);
1066 if(*s<'0' || *s>'9')
1067 syntaxerror("Not a coordinate: \"%s\"", str);
1069 if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) {
1070 warning("precision loss: %s converted to twip", str);
1075 return atoi(str)*20;
1077 return atoi(str)*20+atoi(dot)*2;
1079 return atoi(str)*20+atoi(dot)/5;
1084 int isPoint(char*str)
1086 if(strchr(str, '('))
1092 SPOINT parsePoint(char*str)
1096 int l = strlen(str);
1097 char*comma = strchr(str, ',');
1098 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1099 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1100 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1101 p.x = parseTwip(tmp);
1102 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1103 p.y = parseTwip(tmp);
1107 int parseColor2(char*str, RGBA*color)
1109 int l = strlen(str);
1113 struct {unsigned char r,g,b;char*name;} colors[] =
1114 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1115 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1116 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1117 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1118 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1119 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1120 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1121 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1122 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1123 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1124 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1125 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1129 if(str[0]=='#' && (l==7 || l==9)) {
1130 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1132 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1134 color->r = r; color->g = g; color->b = b; color->a = a;
1137 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1138 if(!strcmp(str, colors[t].name)) {
1143 color->r = r; color->g = g; color->b = b; color->a = a;
1149 RGBA parseColor(char*str)
1152 if(!parseColor2(str, &c))
1153 syntaxerror("Expression '%s' is not a color", str);
1157 typedef struct _muladd {
1162 MULADD parseMulAdd(char*str)
1165 char* str2 = (char*)malloc(strlen(str)+5);
1172 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1173 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1174 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1175 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1176 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1177 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1178 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1179 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1180 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1181 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1183 syntaxerror("'%s' is not a valid color transform expression", str);
1185 m.add = (int)(add*256);
1186 m.mul = (int)(mul*256);
1191 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1193 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1194 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1196 if(a<-32768) a=-32768;
1197 if(a>32767) a=32767;
1198 if(m<-32768) m=-32768;
1199 if(m>32767) m=32767;
1205 float parsePercent(char*str)
1207 int l = strlen(str);
1211 return atoi(str)/100.0;
1213 syntaxerror("Expression '%s' is not a percentage", str);
1216 int isPercent(char*str)
1218 return str[strlen(str)-1]=='%';
1220 int parseNewSize(char*str, int size)
1223 return parsePercent(str)*size;
1225 return (int)(atof(str)*20);
1228 int isColor(char*str)
1231 return parseColor2(str, &c);
1234 static char* lu(map_t* args, char*name)
1236 char* value = map_lookup(args, name);
1238 map_dump(args, stdout, "");
1239 syntaxerror("internal error 2: value %s should be set", name);
1244 static int c_swf(map_t*args)
1246 char* name = lu(args, "name");
1247 char* compressstr = lu(args, "compress");
1248 SRECT bbox = parseBox(lu(args, "bbox"));
1249 int version = parseInt(lu(args, "version"));
1250 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1252 if(!strcmp(name, "!default!") || override_outputname)
1255 if(!strcmp(compressstr, "default"))
1256 compress = version==6;
1257 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1259 else if(!strcmp(compressstr, "no"))
1261 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1263 s_swf(name, bbox, version, fps, compress);
1266 int isRelative(char*str)
1268 return !strncmp(str, "<plus>", 6) ||
1269 !strncmp(str, "<minus>", 7);
1271 char* getOffset(char*str)
1273 if(!strncmp(str, "<plus>", 6))
1275 if(!strncmp(str, "<minus>", 7))
1277 syntaxerror("internal error (347)");
1280 int getSign(char*str)
1282 if(!strncmp(str, "<plus>", 6))
1284 if(!strncmp(str, "<minus>", 7))
1286 syntaxerror("internal error (348)");
1289 static dictionary_t points;
1290 static mem_t mpoints;
1291 int points_initialized = 0;
1293 SPOINT getPoint(SRECT r, char*name)
1296 if(!strcmp(name, "center")) {
1298 p.x = (r.xmin + r.xmax)/2;
1299 p.y = (r.ymin + r.ymax)/2;
1303 if(points_initialized)
1304 l = (int)dictionary_lookup(&points, name);
1306 syntaxerror("Invalid point: \"%s\".", name);
1309 return *(SPOINT*)&mpoints.buffer[l];
1311 static int c_point(map_t*args)
1313 char*name = lu(args, "name");
1317 if(!points_initialized) {
1318 dictionary_init(&points);
1320 points_initialized = 1;
1322 p.x = parseTwip(lu(args, "x"));
1323 p.y = parseTwip(lu(args, "y"));
1324 pos = mem_put(&mpoints, &p, sizeof(p));
1325 string_set(&s1, name);
1327 dictionary_put(&points, s1, (void*)pos);
1330 static int c_play(map_t*args)
1332 char*name = lu(args, "sound");
1333 char*loop = lu(args, "loop");
1334 char*nomultiple = lu(args, "nomultiple");
1336 s_playsound(name, parseInt(loop), parseInt(nomultiple), 0);
1340 static int c_stop(map_t*args)
1342 char*name = lu(args, "sound");
1343 s_playsound(name, 0,0,1);
1347 static int c_placement(map_t*args, int type)
1349 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1352 char* luminancestr = lu(args, "luminance");
1353 char* scalestr = lu(args, "scale");
1354 char* scalexstr = lu(args, "scalex");
1355 char* scaleystr = lu(args, "scaley");
1356 char* rotatestr = lu(args, "rotate");
1357 char* shearstr = lu(args, "shear");
1358 char* xstr="", *pivotstr="";
1359 char* ystr="", *anglestr="";
1360 char*above = lu(args, "above"); /*FIXME*/
1361 char*below = lu(args, "below");
1362 char* rstr = lu(args, "red");
1363 char* gstr = lu(args, "green");
1364 char* bstr = lu(args, "blue");
1365 char* astr = lu(args, "alpha");
1366 char* pinstr = lu(args, "pin");
1375 pivotstr = lu(args, "pivot");
1376 anglestr = lu(args, "angle");
1378 xstr = lu(args, "x");
1379 ystr = lu(args, "y");
1382 luminance = parseMulAdd(luminancestr);
1385 luminance.mul = 256;
1389 if(scalexstr[0]||scaleystr[0])
1390 syntaxerror("scalex/scaley and scale cannot both be set");
1391 scalexstr = scaleystr = scalestr;
1394 if(type == 0 || type == 4) {
1396 character = lu(args, "character");
1397 parameters_clear(&p);
1399 p = s_getParameters(instance);
1404 if(isRelative(xstr)) {
1405 if(type == 0 || type == 4)
1406 syntaxerror("relative x values not allowed for initial put or startclip");
1407 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
1409 p.x = parseTwip(xstr);
1413 if(isRelative(ystr)) {
1414 if(type == 0 || type == 4)
1415 syntaxerror("relative y values not allowed for initial put or startclip");
1416 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
1418 p.y = parseTwip(ystr);
1422 /* scale, scalex, scaley */
1424 oldbbox = s_getCharBBox(character);
1426 oldbbox = s_getInstanceBBox(instance);
1428 oldwidth = oldbbox.xmax - oldbbox.xmin;
1429 oldheight = oldbbox.ymax - oldbbox.ymin;
1431 if(oldwidth==0) p.scalex = 1.0;
1434 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
1438 if(oldheight==0) p.scaley = 1.0;
1441 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
1447 if(isRelative(rotatestr)) {
1448 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
1450 p.rotate = parseFloat(rotatestr);
1456 if(isRelative(shearstr)) {
1457 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
1459 p.shear = parseFloat(shearstr);
1464 if(isPoint(pivotstr))
1465 p.pivot = parsePoint(pivotstr);
1467 p.pivot = getPoint(oldbbox, pivotstr);
1471 p.pin = parsePoint(pinstr);
1473 p.pin = getPoint(oldbbox, pinstr);
1476 /* color transform */
1478 if(rstr[0] || luminancestr[0]) {
1481 r = parseMulAdd(rstr);
1483 r.add = p.cxform.r0;
1484 r.mul = p.cxform.r1;
1486 r = mergeMulAdd(r, luminance);
1487 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
1489 if(gstr[0] || luminancestr[0]) {
1492 g = parseMulAdd(gstr);
1494 g.add = p.cxform.g0;
1495 g.mul = p.cxform.g1;
1497 g = mergeMulAdd(g, luminance);
1498 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
1500 if(bstr[0] || luminancestr[0]) {
1503 b = parseMulAdd(bstr);
1505 b.add = p.cxform.b0;
1506 b.mul = p.cxform.b1;
1508 b = mergeMulAdd(b, luminance);
1509 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
1512 MULADD a = parseMulAdd(astr);
1513 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
1517 s_put(instance, character, p);
1519 s_change(instance, p);
1521 s_qchange(instance, p);
1523 s_jump(instance, p);
1525 s_startclip(instance, character, p);
1528 static int c_put(map_t*args)
1530 c_placement(args, 0);
1533 static int c_change(map_t*args)
1535 c_placement(args, 1);
1538 static int c_qchange(map_t*args)
1540 c_placement(args, 2);
1543 static int c_arcchange(map_t*args)
1545 c_placement(args, 2);
1548 static int c_jump(map_t*args)
1550 c_placement(args, 3);
1553 static int c_startclip(map_t*args)
1555 c_placement(args, 4);
1558 static int c_del(map_t*args)
1560 char*instance = lu(args, "name");
1561 s_delinstance(instance);
1564 static int c_end(map_t*args)
1569 static int c_sprite(map_t*args)
1571 char* name = lu(args, "name");
1575 static int c_frame(map_t*args)
1577 char*framestr = lu(args, "n");
1579 if(isRelative(framestr)) {
1580 frame = s_getframe();
1581 if(getSign(framestr)<0)
1582 syntaxerror("relative frame expressions must be positive");
1583 frame += parseInt(getOffset(framestr));
1586 frame = parseInt(framestr);
1587 if(s_getframe() >= frame
1588 && !(frame==0 && s_getframe()==frame)) // equality is o.k. for frame 0
1589 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
1594 static int c_primitive(map_t*args)
1596 char*name = lu(args, "name");
1597 char*command = lu(args, "commandname");
1598 int width=0, height=0, r=0;
1599 int linewidth = parseTwip(lu(args, "line"));
1600 char*colorstr = lu(args, "color");
1601 RGBA color = parseColor(colorstr);
1602 char*fillstr = lu(args, "fill");
1608 if(!strcmp(command, "circle"))
1610 else if(!strcmp(command, "textshape"))
1614 width = parseTwip(lu(args, "width"));
1615 height = parseTwip(lu(args, "height"));
1616 } else if (type==1) {
1617 r = parseTwip(lu(args, "r"));
1618 } else if (type==2) {
1619 text = lu(args, "text");
1620 font = lu(args, "font");
1623 if(!strcmp(fillstr, "fill"))
1625 if(!strcmp(fillstr, "none"))
1627 if(width<0 || height<0 || linewidth<0 || r<0)
1628 syntaxerror("values width, height, line, r must be positive");
1629 if(!dofill || isColor(fillstr)) {
1631 fill = parseColor(fillstr);
1633 /* FIXME - texture fill */
1634 fill.r = fill.g = 0;
1635 fill.b = fill.a = 255;
1636 warning("texture fill not supported yet. Filling with black.");
1638 if(type == 0) s_box(name, width, height, color, linewidth, fill, dofill);
1639 else if(type==1) s_circle(name, r, color, linewidth, fill, dofill);
1640 else if(type==2) s_textshape(name, font, text, color, linewidth, fill, dofill);
1644 static int c_shape(map_t*args)
1646 char*name = lu(args, "name");
1647 char*filename = lu(args, "filename");
1648 s_shape(name, filename);
1652 static int c_font(map_t*args)
1654 char*name = lu(args, "name");
1655 char*filename = lu(args, "filename");
1656 s_font(name, filename);
1660 static int c_sound(map_t*args)
1662 char*name = lu(args, "name");
1663 char*filename = lu(args, "filename");
1664 s_sound(name, filename);
1668 static int c_text(map_t*args)
1670 char*name = lu(args, "name");
1671 char*text = lu(args, "text");
1672 char*font = lu(args, "font");
1673 float size = parsePercent(lu(args, "size"));
1674 RGBA color = parseColor(lu(args, "color"));
1675 s_text(name, font, text, (int)(size*100), color);
1679 static int c_soundtrack(map_t*args)
1684 int fakechar(map_t*args)
1686 char*name = lu(args, "name");
1687 s_box(name, 0, 0, black, 20, black, 0);
1691 static int c_egon(map_t*args) {return fakechar(args);}
1692 static int c_button(map_t*args) {return fakechar(args);}
1693 static int c_edittext(map_t*args) {return fakechar(args);}
1695 static int c_morphshape(map_t*args) {return fakechar(args);}
1696 static int c_image(map_t*args) {return fakechar(args);}
1697 static int c_movie(map_t*args) {return fakechar(args);}
1699 static int c_buttonsounds(map_t*args) {return 0;}
1700 static int c_buttonput(map_t*args) {return 0;}
1701 static int c_texture(map_t*args) {return 0;}
1702 static int c_action(map_t*args) {return 0;}
1706 command_func_t* func;
1709 {{"swf", c_swf, "bbox=autocrop version=5 fps=50 name=!default! @compress=default"},
1710 {"frame", c_frame, "n=<plus>1"},
1712 // "import" type stuff
1713 {"shape", c_shape, "name filename"},
1714 {"morphshape", c_morphshape, "name start end"},
1715 {"jpeg", c_image, "name filename quality=80%"},
1716 {"png", c_image, "name filename"},
1717 {"movie", c_movie, "name filename"},
1718 {"sound", c_sound, "name filename"},
1719 {"font", c_font, "name filename"},
1720 {"soundtrack", c_soundtrack, "filename"},
1722 // character generators
1723 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
1724 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
1725 {"textshape", c_primitive, "name text font color=white line=1 @fill=none"},
1726 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
1727 {"button", c_button, "name shape over=*shape press=*shape area=*shape"},
1728 {"text", c_text, "name text font size=100% color=white"},
1729 {"edittext", c_edittext, "name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
1731 {"buttonsounds", c_buttonsounds, "name press=0 release=0 enter=0 leave=0"},
1734 {"play", c_play, "sound loop=0 @nomultiple=0"},
1735 {"stop", c_stop, "sound"},
1737 // object placement tags
1738 {"put", c_put, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1739 {"startclip", c_startclip, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1740 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1741 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1742 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1743 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1744 {"del", c_del, "name"},
1745 // virtual object placement
1746 {"buttonput", c_buttonput, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex=100% scaley=100% shear=0 rotate=0 above= below="},
1747 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
1748 {"point", c_point, "name x=0 y=0"},
1750 // commands which start a block
1751 //startclip (see above)
1752 {"sprite", c_sprite, "name"},
1753 {"action", c_action, ""},
1759 static map_t parseArguments(char*command, char*pattern)
1775 string_set(&t1, "commandname");
1776 string_set(&t2, command);
1777 map_put(&result, t1, t2);
1779 if(!pattern || !*pattern)
1786 if(!strncmp("<i> ", x, 3)) {
1788 if(type == COMMAND || type == LABEL) {
1790 syntaxerror("character name expected");
1792 name[pos].str = "instance";
1794 value[pos].str = text;
1795 value[pos].len = strlen(text);
1799 if(type == ASSIGNMENT)
1802 name[pos].str = "character";
1804 value[pos].str = text;
1805 value[pos].len = strlen(text);
1813 isboolean[pos] = (x[0] =='@');
1826 name[pos].len = d-x;
1831 name[pos].len = e-x;
1832 value[pos].str = e+1;
1833 value[pos].len = d-e-1;
1841 /* for(t=0;t<len;t++) {
1842 printf("(%d) %s=%s %s\n", t, strndup(name[t], namelen[t]), strndup(value[t], valuelen[t]),
1843 isboolean[t]?"(boolean)":"");
1848 if(type == LABEL || type == COMMAND) {
1853 // first, search for boolean arguments
1854 for(pos=0;pos<len;pos++)
1856 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
1858 if(type == ASSIGNMENT)
1860 value[pos].str = text;
1861 value[pos].len = strlen(text);
1862 /*printf("setting boolean parameter %s (to %s)\n",
1863 strndup(name[pos], namelen[pos]),
1864 strndup(value[pos], valuelen[pos]));*/
1869 // second, search for normal arguments
1871 for(pos=0;pos<len;pos++)
1873 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
1874 (type != ASSIGNMENT && !set[pos])) {
1876 syntaxerror("value %s set twice (old value:%s)", text, strndup(value[pos].str, value[pos].len));
1878 if(type == ASSIGNMENT)
1881 value[pos].str = text;
1882 value[pos].len = strlen(text);
1884 printf("setting parameter %s (to %s)\n",
1885 strndup(name[pos].str, name[pos].len),
1886 strndup(value[pos].str, value[pos].len));
1892 syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
1896 for(t=0;t<len;t++) {
1897 printf("%s=%s\n", strndup(name[t].str, name[t].len), strndup(value[t].str, value[t].len));
1900 for(t=0;t<len;t++) {
1901 if(value[t].str && value[t].str[0] == '*') {
1902 //relative default- take value from some other parameter
1904 for(s=0;s<len;s++) {
1905 if(value[s].len == value[t].len-1 &&
1906 !strncmp(&value[t].str[1], value[s].str, value[s].len))
1907 value[t].str = value[s].str;
1910 if(value[t].str == 0) {
1912 syntaxerror("value for parameter %s missing (no default)", strndup(name[t].str, name[t].len));
1916 /* ok, now construct the dictionary from the parameters */
1920 map_put(&result, name[t], value[t]);
1924 static void parseArgumentsForCommand(char*command)
1929 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
1930 if(!strcmp(arguments[t].command, command)) {
1931 args = parseArguments(command, arguments[t].arguments);
1936 syntaxerror("command %s not known", command);
1939 printf(".%s\n", command);fflush(stdout);
1940 map_dump(&args, stdout, "\t");fflush(stdout);
1943 (*arguments[nr].func)(&args);
1945 if(!strcmp(command, "button") ||
1946 !strcmp(command, "action")) {
1949 if(type == COMMAND) {
1950 if(!strcmp(text, "end"))
1964 int main (int argc,char ** argv)
1967 processargs(argc, argv);
1968 initLog(0,-1,0,0,-1,verbose);
1971 args_callback_usage(argv[0]);
1974 file = generateTokens(filename);
1976 printf("parser returned error.\n");
1983 while(!noMoreTokens()) {
1986 syntaxerror("command expected");
1987 parseArgumentsForCommand(text);