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 if(!strcmp(nomultiple, "nomultiple"))
1339 nm = parseInt(nomultiple);
1341 s_playsound(name, parseInt(loop), nm, 0);
1345 static int c_stop(map_t*args)
1347 char*name = lu(args, "sound");
1348 s_playsound(name, 0,0,1);
1352 static int c_placement(map_t*args, int type)
1354 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1357 char* luminancestr = lu(args, "luminance");
1358 char* scalestr = lu(args, "scale");
1359 char* scalexstr = lu(args, "scalex");
1360 char* scaleystr = lu(args, "scaley");
1361 char* rotatestr = lu(args, "rotate");
1362 char* shearstr = lu(args, "shear");
1363 char* xstr="", *pivotstr="";
1364 char* ystr="", *anglestr="";
1365 char*above = lu(args, "above"); /*FIXME*/
1366 char*below = lu(args, "below");
1367 char* rstr = lu(args, "red");
1368 char* gstr = lu(args, "green");
1369 char* bstr = lu(args, "blue");
1370 char* astr = lu(args, "alpha");
1371 char* pinstr = lu(args, "pin");
1380 pivotstr = lu(args, "pivot");
1381 anglestr = lu(args, "angle");
1383 xstr = lu(args, "x");
1384 ystr = lu(args, "y");
1387 luminance = parseMulAdd(luminancestr);
1390 luminance.mul = 256;
1394 if(scalexstr[0]||scaleystr[0])
1395 syntaxerror("scalex/scaley and scale cannot both be set");
1396 scalexstr = scaleystr = scalestr;
1399 if(type == 0 || type == 4) {
1401 character = lu(args, "character");
1402 parameters_clear(&p);
1404 p = s_getParameters(instance);
1409 if(isRelative(xstr)) {
1410 if(type == 0 || type == 4)
1411 syntaxerror("relative x values not allowed for initial put or startclip");
1412 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
1414 p.x = parseTwip(xstr);
1418 if(isRelative(ystr)) {
1419 if(type == 0 || type == 4)
1420 syntaxerror("relative y values not allowed for initial put or startclip");
1421 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
1423 p.y = parseTwip(ystr);
1427 /* scale, scalex, scaley */
1429 oldbbox = s_getCharBBox(character);
1431 oldbbox = s_getInstanceBBox(instance);
1433 oldwidth = oldbbox.xmax - oldbbox.xmin;
1434 oldheight = oldbbox.ymax - oldbbox.ymin;
1436 if(oldwidth==0) p.scalex = 1.0;
1439 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
1443 if(oldheight==0) p.scaley = 1.0;
1446 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
1452 if(isRelative(rotatestr)) {
1453 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
1455 p.rotate = parseFloat(rotatestr);
1461 if(isRelative(shearstr)) {
1462 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
1464 p.shear = parseFloat(shearstr);
1469 if(isPoint(pivotstr))
1470 p.pivot = parsePoint(pivotstr);
1472 p.pivot = getPoint(oldbbox, pivotstr);
1476 p.pin = parsePoint(pinstr);
1478 p.pin = getPoint(oldbbox, pinstr);
1481 /* color transform */
1483 if(rstr[0] || luminancestr[0]) {
1486 r = parseMulAdd(rstr);
1488 r.add = p.cxform.r0;
1489 r.mul = p.cxform.r1;
1491 r = mergeMulAdd(r, luminance);
1492 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
1494 if(gstr[0] || luminancestr[0]) {
1497 g = parseMulAdd(gstr);
1499 g.add = p.cxform.g0;
1500 g.mul = p.cxform.g1;
1502 g = mergeMulAdd(g, luminance);
1503 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
1505 if(bstr[0] || luminancestr[0]) {
1508 b = parseMulAdd(bstr);
1510 b.add = p.cxform.b0;
1511 b.mul = p.cxform.b1;
1513 b = mergeMulAdd(b, luminance);
1514 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
1517 MULADD a = parseMulAdd(astr);
1518 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
1522 s_put(instance, character, p);
1524 s_change(instance, p);
1526 s_qchange(instance, p);
1528 s_jump(instance, p);
1530 s_startclip(instance, character, p);
1533 static int c_put(map_t*args)
1535 c_placement(args, 0);
1538 static int c_change(map_t*args)
1540 c_placement(args, 1);
1543 static int c_qchange(map_t*args)
1545 c_placement(args, 2);
1548 static int c_arcchange(map_t*args)
1550 c_placement(args, 2);
1553 static int c_jump(map_t*args)
1555 c_placement(args, 3);
1558 static int c_startclip(map_t*args)
1560 c_placement(args, 4);
1563 static int c_del(map_t*args)
1565 char*instance = lu(args, "name");
1566 s_delinstance(instance);
1569 static int c_end(map_t*args)
1574 static int c_sprite(map_t*args)
1576 char* name = lu(args, "name");
1580 static int c_frame(map_t*args)
1582 char*framestr = lu(args, "n");
1584 if(isRelative(framestr)) {
1585 frame = s_getframe();
1586 if(getSign(framestr)<0)
1587 syntaxerror("relative frame expressions must be positive");
1588 frame += parseInt(getOffset(framestr));
1591 frame = parseInt(framestr);
1592 if(s_getframe() >= frame
1593 && !(frame==0 && s_getframe()==frame)) // equality is o.k. for frame 0
1594 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
1599 static int c_primitive(map_t*args)
1601 char*name = lu(args, "name");
1602 char*command = lu(args, "commandname");
1603 int width=0, height=0, r=0;
1604 int linewidth = parseTwip(lu(args, "line"));
1605 char*colorstr = lu(args, "color");
1606 RGBA color = parseColor(colorstr);
1607 char*fillstr = lu(args, "fill");
1613 if(!strcmp(command, "circle"))
1615 else if(!strcmp(command, "textshape"))
1619 width = parseTwip(lu(args, "width"));
1620 height = parseTwip(lu(args, "height"));
1621 } else if (type==1) {
1622 r = parseTwip(lu(args, "r"));
1623 } else if (type==2) {
1624 text = lu(args, "text");
1625 font = lu(args, "font");
1628 if(!strcmp(fillstr, "fill"))
1630 if(!strcmp(fillstr, "none"))
1632 if(width<0 || height<0 || linewidth<0 || r<0)
1633 syntaxerror("values width, height, line, r must be positive");
1634 if(!dofill || isColor(fillstr)) {
1636 fill = parseColor(fillstr);
1638 /* FIXME - texture fill */
1639 fill.r = fill.g = 0;
1640 fill.b = fill.a = 255;
1641 warning("texture fill not supported yet. Filling with black.");
1643 if(type == 0) s_box(name, width, height, color, linewidth, fill, dofill);
1644 else if(type==1) s_circle(name, r, color, linewidth, fill, dofill);
1645 else if(type==2) s_textshape(name, font, text, color, linewidth, fill, dofill);
1649 static int c_shape(map_t*args)
1651 char*name = lu(args, "name");
1652 char*filename = lu(args, "filename");
1653 s_shape(name, filename);
1657 static int c_font(map_t*args)
1659 char*name = lu(args, "name");
1660 char*filename = lu(args, "filename");
1661 s_font(name, filename);
1665 static int c_sound(map_t*args)
1667 char*name = lu(args, "name");
1668 char*filename = lu(args, "filename");
1669 s_sound(name, filename);
1673 static int c_text(map_t*args)
1675 char*name = lu(args, "name");
1676 char*text = lu(args, "text");
1677 char*font = lu(args, "font");
1678 float size = parsePercent(lu(args, "size"));
1679 RGBA color = parseColor(lu(args, "color"));
1680 s_text(name, font, text, (int)(size*100), color);
1684 static int c_soundtrack(map_t*args)
1689 int fakechar(map_t*args)
1691 char*name = lu(args, "name");
1692 s_box(name, 0, 0, black, 20, black, 0);
1696 static int c_egon(map_t*args) {return fakechar(args);}
1697 static int c_button(map_t*args) {return fakechar(args);}
1698 static int c_edittext(map_t*args) {return fakechar(args);}
1700 static int c_morphshape(map_t*args) {return fakechar(args);}
1701 static int c_image(map_t*args) {return fakechar(args);}
1702 static int c_movie(map_t*args) {return fakechar(args);}
1704 static int c_buttonsounds(map_t*args) {return 0;}
1705 static int c_buttonput(map_t*args) {return 0;}
1706 static int c_texture(map_t*args) {return 0;}
1707 static int c_action(map_t*args) {return 0;}
1711 command_func_t* func;
1714 {{"swf", c_swf, "bbox=autocrop version=5 fps=50 name=!default! @compress=default"},
1715 {"frame", c_frame, "n=<plus>1"},
1717 // "import" type stuff
1718 {"shape", c_shape, "name filename"},
1719 {"morphshape", c_morphshape, "name start end"},
1720 {"jpeg", c_image, "name filename quality=80%"},
1721 {"png", c_image, "name filename"},
1722 {"movie", c_movie, "name filename"},
1723 {"sound", c_sound, "name filename"},
1724 {"font", c_font, "name filename"},
1725 {"soundtrack", c_soundtrack, "filename"},
1727 // character generators
1728 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
1729 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
1730 {"textshape", c_primitive, "name text font color=white line=1 @fill=none"},
1731 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
1732 {"button", c_button, "name shape over=*shape press=*shape area=*shape"},
1733 {"text", c_text, "name text font size=100% color=white"},
1734 {"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"},
1736 {"buttonsounds", c_buttonsounds, "name press=0 release=0 enter=0 leave=0"},
1739 {"play", c_play, "sound loop=0 @nomultiple=0"},
1740 {"stop", c_stop, "sound"},
1742 // object placement tags
1743 {"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="},
1744 {"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="},
1745 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1746 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1747 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1748 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1749 {"del", c_del, "name"},
1750 // virtual object placement
1751 {"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="},
1752 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
1753 {"point", c_point, "name x=0 y=0"},
1755 // commands which start a block
1756 //startclip (see above)
1757 {"sprite", c_sprite, "name"},
1758 {"action", c_action, ""},
1764 static map_t parseArguments(char*command, char*pattern)
1780 string_set(&t1, "commandname");
1781 string_set(&t2, command);
1782 map_put(&result, t1, t2);
1784 if(!pattern || !*pattern)
1791 if(!strncmp("<i> ", x, 3)) {
1793 if(type == COMMAND || type == LABEL) {
1795 syntaxerror("character name expected");
1797 name[pos].str = "instance";
1799 value[pos].str = text;
1800 value[pos].len = strlen(text);
1804 if(type == ASSIGNMENT)
1807 name[pos].str = "character";
1809 value[pos].str = text;
1810 value[pos].len = strlen(text);
1818 isboolean[pos] = (x[0] =='@');
1831 name[pos].len = d-x;
1836 name[pos].len = e-x;
1837 value[pos].str = e+1;
1838 value[pos].len = d-e-1;
1846 /* for(t=0;t<len;t++) {
1847 printf("(%d) %s=%s %s\n", t, strndup(name[t], namelen[t]), strndup(value[t], valuelen[t]),
1848 isboolean[t]?"(boolean)":"");
1853 if(type == LABEL || type == COMMAND) {
1858 // first, search for boolean arguments
1859 for(pos=0;pos<len;pos++)
1861 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
1863 if(type == ASSIGNMENT)
1865 value[pos].str = text;
1866 value[pos].len = strlen(text);
1867 /*printf("setting boolean parameter %s (to %s)\n",
1868 strndup(name[pos], namelen[pos]),
1869 strndup(value[pos], valuelen[pos]));*/
1874 // second, search for normal arguments
1876 for(pos=0;pos<len;pos++)
1878 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
1879 (type != ASSIGNMENT && !set[pos])) {
1881 syntaxerror("value %s set twice (old value:%s)", text, strndup(value[pos].str, value[pos].len));
1883 if(type == ASSIGNMENT)
1886 value[pos].str = text;
1887 value[pos].len = strlen(text);
1889 printf("setting parameter %s (to %s)\n",
1890 strndup(name[pos].str, name[pos].len),
1891 strndup(value[pos].str, value[pos].len));
1897 syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
1901 for(t=0;t<len;t++) {
1902 printf("%s=%s\n", strndup(name[t].str, name[t].len), strndup(value[t].str, value[t].len));
1905 for(t=0;t<len;t++) {
1906 if(value[t].str && value[t].str[0] == '*') {
1907 //relative default- take value from some other parameter
1909 for(s=0;s<len;s++) {
1910 if(value[s].len == value[t].len-1 &&
1911 !strncmp(&value[t].str[1], value[s].str, value[s].len))
1912 value[t].str = value[s].str;
1915 if(value[t].str == 0) {
1917 syntaxerror("value for parameter %s missing (no default)", strndup(name[t].str, name[t].len));
1921 /* ok, now construct the dictionary from the parameters */
1925 map_put(&result, name[t], value[t]);
1929 static void parseArgumentsForCommand(char*command)
1934 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
1935 if(!strcmp(arguments[t].command, command)) {
1936 args = parseArguments(command, arguments[t].arguments);
1941 syntaxerror("command %s not known", command);
1944 printf(".%s\n", command);fflush(stdout);
1945 map_dump(&args, stdout, "\t");fflush(stdout);
1948 (*arguments[nr].func)(&args);
1950 if(!strcmp(command, "button") ||
1951 !strcmp(command, "action")) {
1954 if(type == COMMAND) {
1955 if(!strcmp(text, "end"))
1969 int main (int argc,char ** argv)
1972 processargs(argc, argv);
1973 initLog(0,-1,0,0,-1,verbose);
1976 args_callback_usage(argv[0]);
1979 file = generateTokens(filename);
1981 printf("parser returned error.\n");
1988 while(!noMoreTokens()) {
1991 syntaxerror("command expected");
1992 parseArgumentsForCommand(text);