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|O_BINARY);
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)
1056 if(str[0]=='+' || str[0]=='-') {
1061 dot = strchr(str, '.');
1065 return sign*parseInt(str)*20;
1067 int l=strlen(++dot);
1069 for(s=str;s<dot-1;s++)
1070 if(*s<'0' || *s>'9')
1071 syntaxerror("Not a coordinate: \"%s\"", str);
1073 if(*s<'0' || *s>'9')
1074 syntaxerror("Not a coordinate: \"%s\"", str);
1076 if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) {
1077 warning("precision loss: %s converted to twip", str);
1082 return sign*atoi(str)*20;
1084 return sign*atoi(str)*20+atoi(dot)*2;
1086 return sign*atoi(str)*20+atoi(dot)/5;
1091 int isPoint(char*str)
1093 if(strchr(str, '('))
1099 SPOINT parsePoint(char*str)
1103 int l = strlen(str);
1104 char*comma = strchr(str, ',');
1105 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1106 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1107 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1108 p.x = parseTwip(tmp);
1109 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1110 p.y = parseTwip(tmp);
1114 int parseColor2(char*str, RGBA*color)
1116 int l = strlen(str);
1120 struct {unsigned char r,g,b;char*name;} colors[] =
1121 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1122 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1123 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1124 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1125 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1126 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1127 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1128 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1129 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1130 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1131 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1132 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1136 if(str[0]=='#' && (l==7 || l==9)) {
1137 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1139 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1141 color->r = r; color->g = g; color->b = b; color->a = a;
1144 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1145 if(!strcmp(str, colors[t].name)) {
1150 color->r = r; color->g = g; color->b = b; color->a = a;
1156 RGBA parseColor(char*str)
1159 if(!parseColor2(str, &c))
1160 syntaxerror("Expression '%s' is not a color", str);
1164 typedef struct _muladd {
1169 MULADD parseMulAdd(char*str)
1172 char* str2 = (char*)malloc(strlen(str)+5);
1179 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1180 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1181 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1182 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1183 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1184 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1185 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1186 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1187 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1188 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1190 syntaxerror("'%s' is not a valid color transform expression", str);
1192 m.add = (int)(add*256);
1193 m.mul = (int)(mul*256);
1198 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1200 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1201 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1203 if(a<-32768) a=-32768;
1204 if(a>32767) a=32767;
1205 if(m<-32768) m=-32768;
1206 if(m>32767) m=32767;
1212 float parsePercent(char*str)
1214 int l = strlen(str);
1218 return atoi(str)/100.0;
1220 syntaxerror("Expression '%s' is not a percentage", str);
1223 int isPercent(char*str)
1225 return str[strlen(str)-1]=='%';
1227 int parseNewSize(char*str, int size)
1230 return parsePercent(str)*size;
1232 return (int)(atof(str)*20);
1235 int isColor(char*str)
1238 return parseColor2(str, &c);
1241 static char* lu(map_t* args, char*name)
1243 char* value = map_lookup(args, name);
1245 map_dump(args, stdout, "");
1246 syntaxerror("internal error 2: value %s should be set", name);
1251 static int c_swf(map_t*args)
1253 char* name = lu(args, "name");
1254 char* compressstr = lu(args, "compress");
1255 SRECT bbox = parseBox(lu(args, "bbox"));
1256 int version = parseInt(lu(args, "version"));
1257 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1259 if(!strcmp(name, "!default!") || override_outputname)
1262 if(!strcmp(compressstr, "default"))
1263 compress = version==6;
1264 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1266 else if(!strcmp(compressstr, "no"))
1268 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1270 s_swf(name, bbox, version, fps, compress);
1273 int isRelative(char*str)
1275 return !strncmp(str, "<plus>", 6) ||
1276 !strncmp(str, "<minus>", 7);
1278 char* getOffset(char*str)
1280 if(!strncmp(str, "<plus>", 6))
1282 if(!strncmp(str, "<minus>", 7))
1284 syntaxerror("internal error (347)");
1287 int getSign(char*str)
1289 if(!strncmp(str, "<plus>", 6))
1291 if(!strncmp(str, "<minus>", 7))
1293 syntaxerror("internal error (348)");
1296 static dictionary_t points;
1297 static mem_t mpoints;
1298 int points_initialized = 0;
1300 SPOINT getPoint(SRECT r, char*name)
1303 if(!strcmp(name, "center")) {
1305 p.x = (r.xmin + r.xmax)/2;
1306 p.y = (r.ymin + r.ymax)/2;
1310 if(points_initialized)
1311 l = (int)dictionary_lookup(&points, name);
1313 syntaxerror("Invalid point: \"%s\".", name);
1316 return *(SPOINT*)&mpoints.buffer[l];
1318 static int c_point(map_t*args)
1320 char*name = lu(args, "name");
1324 if(!points_initialized) {
1325 dictionary_init(&points);
1327 points_initialized = 1;
1329 p.x = parseTwip(lu(args, "x"));
1330 p.y = parseTwip(lu(args, "y"));
1331 pos = mem_put(&mpoints, &p, sizeof(p));
1332 string_set(&s1, name);
1334 dictionary_put(&points, s1, (void*)pos);
1337 static int c_play(map_t*args)
1339 char*name = lu(args, "sound");
1340 char*loop = lu(args, "loop");
1341 char*nomultiple = lu(args, "nomultiple");
1343 if(!strcmp(nomultiple, "nomultiple"))
1346 nm = parseInt(nomultiple);
1348 s_playsound(name, parseInt(loop), nm, 0);
1352 static int c_stop(map_t*args)
1354 char*name = lu(args, "sound");
1355 s_playsound(name, 0,0,1);
1359 static int c_placement(map_t*args, int type)
1361 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1364 char* luminancestr = lu(args, "luminance");
1365 char* scalestr = lu(args, "scale");
1366 char* scalexstr = lu(args, "scalex");
1367 char* scaleystr = lu(args, "scaley");
1368 char* rotatestr = lu(args, "rotate");
1369 char* shearstr = lu(args, "shear");
1370 char* xstr="", *pivotstr="";
1371 char* ystr="", *anglestr="";
1372 char*above = lu(args, "above"); /*FIXME*/
1373 char*below = lu(args, "below");
1374 char* rstr = lu(args, "red");
1375 char* gstr = lu(args, "green");
1376 char* bstr = lu(args, "blue");
1377 char* astr = lu(args, "alpha");
1378 char* pinstr = lu(args, "pin");
1387 pivotstr = lu(args, "pivot");
1388 anglestr = lu(args, "angle");
1390 xstr = lu(args, "x");
1391 ystr = lu(args, "y");
1394 luminance = parseMulAdd(luminancestr);
1397 luminance.mul = 256;
1401 if(scalexstr[0]||scaleystr[0])
1402 syntaxerror("scalex/scaley and scale cannot both be set");
1403 scalexstr = scaleystr = scalestr;
1406 if(type == 0 || type == 4) {
1408 character = lu(args, "character");
1409 parameters_clear(&p);
1411 p = s_getParameters(instance);
1416 if(isRelative(xstr)) {
1417 if(type == 0 || type == 4)
1418 syntaxerror("relative x values not allowed for initial put or startclip");
1419 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
1421 p.x = parseTwip(xstr);
1425 if(isRelative(ystr)) {
1426 if(type == 0 || type == 4)
1427 syntaxerror("relative y values not allowed for initial put or startclip");
1428 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
1430 p.y = parseTwip(ystr);
1434 /* scale, scalex, scaley */
1436 oldbbox = s_getCharBBox(character);
1438 oldbbox = s_getInstanceBBox(instance);
1440 oldwidth = oldbbox.xmax - oldbbox.xmin;
1441 oldheight = oldbbox.ymax - oldbbox.ymin;
1443 if(oldwidth==0) p.scalex = 1.0;
1446 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
1450 if(oldheight==0) p.scaley = 1.0;
1453 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
1459 if(isRelative(rotatestr)) {
1460 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
1462 p.rotate = parseFloat(rotatestr);
1468 if(isRelative(shearstr)) {
1469 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
1471 p.shear = parseFloat(shearstr);
1476 if(isPoint(pivotstr))
1477 p.pivot = parsePoint(pivotstr);
1479 p.pivot = getPoint(oldbbox, pivotstr);
1483 p.pin = parsePoint(pinstr);
1485 p.pin = getPoint(oldbbox, pinstr);
1488 /* color transform */
1490 if(rstr[0] || luminancestr[0]) {
1493 r = parseMulAdd(rstr);
1495 r.add = p.cxform.r0;
1496 r.mul = p.cxform.r1;
1498 r = mergeMulAdd(r, luminance);
1499 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
1501 if(gstr[0] || luminancestr[0]) {
1504 g = parseMulAdd(gstr);
1506 g.add = p.cxform.g0;
1507 g.mul = p.cxform.g1;
1509 g = mergeMulAdd(g, luminance);
1510 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
1512 if(bstr[0] || luminancestr[0]) {
1515 b = parseMulAdd(bstr);
1517 b.add = p.cxform.b0;
1518 b.mul = p.cxform.b1;
1520 b = mergeMulAdd(b, luminance);
1521 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
1524 MULADD a = parseMulAdd(astr);
1525 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
1529 s_put(instance, character, p);
1531 s_change(instance, p);
1533 s_qchange(instance, p);
1535 s_jump(instance, p);
1537 s_startclip(instance, character, p);
1540 static int c_put(map_t*args)
1542 c_placement(args, 0);
1545 static int c_change(map_t*args)
1547 c_placement(args, 1);
1550 static int c_qchange(map_t*args)
1552 c_placement(args, 2);
1555 static int c_arcchange(map_t*args)
1557 c_placement(args, 2);
1560 static int c_jump(map_t*args)
1562 c_placement(args, 3);
1565 static int c_startclip(map_t*args)
1567 c_placement(args, 4);
1570 static int c_del(map_t*args)
1572 char*instance = lu(args, "name");
1573 s_delinstance(instance);
1576 static int c_end(map_t*args)
1581 static int c_sprite(map_t*args)
1583 char* name = lu(args, "name");
1587 static int c_frame(map_t*args)
1589 char*framestr = lu(args, "n");
1591 if(isRelative(framestr)) {
1592 frame = s_getframe();
1593 if(getSign(framestr)<0)
1594 syntaxerror("relative frame expressions must be positive");
1595 frame += parseInt(getOffset(framestr));
1598 frame = parseInt(framestr);
1599 if(s_getframe() >= frame
1600 && !(frame==0 && s_getframe()==frame)) // equality is o.k. for frame 0
1601 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
1606 static int c_primitive(map_t*args)
1608 char*name = lu(args, "name");
1609 char*command = lu(args, "commandname");
1610 int width=0, height=0, r=0;
1611 int linewidth = parseTwip(lu(args, "line"));
1612 char*colorstr = lu(args, "color");
1613 RGBA color = parseColor(colorstr);
1614 char*fillstr = lu(args, "fill");
1620 if(!strcmp(command, "circle"))
1622 else if(!strcmp(command, "textshape"))
1626 width = parseTwip(lu(args, "width"));
1627 height = parseTwip(lu(args, "height"));
1628 } else if (type==1) {
1629 r = parseTwip(lu(args, "r"));
1630 } else if (type==2) {
1631 text = lu(args, "text");
1632 font = lu(args, "font");
1635 if(!strcmp(fillstr, "fill"))
1637 if(!strcmp(fillstr, "none"))
1639 if(width<0 || height<0 || linewidth<0 || r<0)
1640 syntaxerror("values width, height, line, r must be positive");
1641 if(!dofill || isColor(fillstr)) {
1643 fill = parseColor(fillstr);
1645 /* FIXME - texture fill */
1646 fill.r = fill.g = 0;
1647 fill.b = fill.a = 255;
1648 warning("texture fill not supported yet. Filling with black.");
1650 if(type == 0) s_box(name, width, height, color, linewidth, fill, dofill);
1651 else if(type==1) s_circle(name, r, color, linewidth, fill, dofill);
1652 else if(type==2) s_textshape(name, font, text, color, linewidth, fill, dofill);
1656 static int c_shape(map_t*args)
1658 char*name = lu(args, "name");
1659 char*filename = lu(args, "filename");
1660 s_shape(name, filename);
1664 static int c_font(map_t*args)
1666 char*name = lu(args, "name");
1667 char*filename = lu(args, "filename");
1668 s_font(name, filename);
1672 static int c_sound(map_t*args)
1674 char*name = lu(args, "name");
1675 char*filename = lu(args, "filename");
1676 s_sound(name, filename);
1680 static int c_text(map_t*args)
1682 char*name = lu(args, "name");
1683 char*text = lu(args, "text");
1684 char*font = lu(args, "font");
1685 float size = parsePercent(lu(args, "size"));
1686 RGBA color = parseColor(lu(args, "color"));
1687 s_text(name, font, text, (int)(size*100), color);
1691 static int c_soundtrack(map_t*args)
1696 int fakechar(map_t*args)
1698 char*name = lu(args, "name");
1699 s_box(name, 0, 0, black, 20, black, 0);
1703 static int c_egon(map_t*args) {return fakechar(args);}
1704 static int c_button(map_t*args) {return fakechar(args);}
1705 static int c_edittext(map_t*args) {return fakechar(args);}
1707 static int c_morphshape(map_t*args) {return fakechar(args);}
1708 static int c_image(map_t*args) {return fakechar(args);}
1709 static int c_movie(map_t*args) {return fakechar(args);}
1711 static int c_buttonsounds(map_t*args) {return 0;}
1712 static int c_buttonput(map_t*args) {return 0;}
1713 static int c_texture(map_t*args) {return 0;}
1714 static int c_action(map_t*args) {return 0;}
1718 command_func_t* func;
1721 {{"swf", c_swf, "bbox=autocrop version=5 fps=50 name=!default! @compress=default"},
1722 {"frame", c_frame, "n=<plus>1"},
1724 // "import" type stuff
1725 {"shape", c_shape, "name filename"},
1726 {"morphshape", c_morphshape, "name start end"},
1727 {"jpeg", c_image, "name filename quality=80%"},
1728 {"png", c_image, "name filename"},
1729 {"movie", c_movie, "name filename"},
1730 {"sound", c_sound, "name filename"},
1731 {"font", c_font, "name filename"},
1732 {"soundtrack", c_soundtrack, "filename"},
1734 // character generators
1735 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
1736 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
1737 {"textshape", c_primitive, "name text font color=white line=1 @fill=none"},
1738 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
1739 {"button", c_button, "name shape over=*shape press=*shape area=*shape"},
1740 {"text", c_text, "name text font size=100% color=white"},
1741 {"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"},
1743 {"buttonsounds", c_buttonsounds, "name press=0 release=0 enter=0 leave=0"},
1746 {"play", c_play, "sound loop=0 @nomultiple=0"},
1747 {"stop", c_stop, "sound"},
1749 // object placement tags
1750 {"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="},
1751 {"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="},
1752 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1753 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1754 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1755 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1756 {"del", c_del, "name"},
1757 // virtual object placement
1758 {"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="},
1759 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
1760 {"point", c_point, "name x=0 y=0"},
1762 // commands which start a block
1763 //startclip (see above)
1764 {"sprite", c_sprite, "name"},
1765 {"action", c_action, ""},
1771 static map_t parseArguments(char*command, char*pattern)
1787 string_set(&t1, "commandname");
1788 string_set(&t2, command);
1789 map_put(&result, t1, t2);
1791 if(!pattern || !*pattern)
1798 if(!strncmp("<i> ", x, 3)) {
1800 if(type == COMMAND || type == LABEL) {
1802 syntaxerror("character name expected");
1804 name[pos].str = "instance";
1806 value[pos].str = text;
1807 value[pos].len = strlen(text);
1811 if(type == ASSIGNMENT)
1814 name[pos].str = "character";
1816 value[pos].str = text;
1817 value[pos].len = strlen(text);
1825 isboolean[pos] = (x[0] =='@');
1838 name[pos].len = d-x;
1843 name[pos].len = e-x;
1844 value[pos].str = e+1;
1845 value[pos].len = d-e-1;
1853 /* for(t=0;t<len;t++) {
1854 printf("(%d) %s=%s %s\n", t, strndup(name[t], namelen[t]), strndup(value[t], valuelen[t]),
1855 isboolean[t]?"(boolean)":"");
1860 if(type == LABEL || type == COMMAND) {
1865 // first, search for boolean arguments
1866 for(pos=0;pos<len;pos++)
1868 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
1870 if(type == ASSIGNMENT)
1872 value[pos].str = text;
1873 value[pos].len = strlen(text);
1874 /*printf("setting boolean parameter %s (to %s)\n",
1875 strndup(name[pos], namelen[pos]),
1876 strndup(value[pos], valuelen[pos]));*/
1881 // second, search for normal arguments
1883 for(pos=0;pos<len;pos++)
1885 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
1886 (type != ASSIGNMENT && !set[pos])) {
1888 syntaxerror("value %s set twice (old value:%s)", text, strndup(value[pos].str, value[pos].len));
1890 if(type == ASSIGNMENT)
1893 value[pos].str = text;
1894 value[pos].len = strlen(text);
1896 printf("setting parameter %s (to %s)\n",
1897 strndup(name[pos].str, name[pos].len),
1898 strndup(value[pos].str, value[pos].len));
1904 syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
1908 for(t=0;t<len;t++) {
1909 printf("%s=%s\n", strndup(name[t].str, name[t].len), strndup(value[t].str, value[t].len));
1912 for(t=0;t<len;t++) {
1913 if(value[t].str && value[t].str[0] == '*') {
1914 //relative default- take value from some other parameter
1916 for(s=0;s<len;s++) {
1917 if(value[s].len == value[t].len-1 &&
1918 !strncmp(&value[t].str[1], value[s].str, value[s].len))
1919 value[t].str = value[s].str;
1922 if(value[t].str == 0) {
1924 syntaxerror("value for parameter %s missing (no default)", strndup(name[t].str, name[t].len));
1928 /* ok, now construct the dictionary from the parameters */
1932 map_put(&result, name[t], value[t]);
1936 static void parseArgumentsForCommand(char*command)
1941 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
1942 if(!strcmp(arguments[t].command, command)) {
1943 args = parseArguments(command, arguments[t].arguments);
1948 syntaxerror("command %s not known", command);
1951 printf(".%s\n", command);fflush(stdout);
1952 map_dump(&args, stdout, "\t");fflush(stdout);
1955 (*arguments[nr].func)(&args);
1957 if(!strcmp(command, "button") ||
1958 !strcmp(command, "action")) {
1961 if(type == COMMAND) {
1962 if(!strcmp(text, "end"))
1976 int main (int argc,char ** argv)
1979 processargs(argc, argv);
1980 initLog(0,-1,0,0,-1,verbose);
1983 args_callback_usage(argv[0]);
1986 file = generateTokens(filename);
1988 printf("parser returned error.\n");
1995 while(!noMoreTokens()) {
1998 syntaxerror("command expected");
1999 parseArgumentsForCommand(text);