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 */
17 #include "../config.h"
18 #include "../lib/rfxswf.h"
19 #include "../lib/log.h"
20 #include "../lib/args.h"
27 static char * filename = 0;
28 static char * outputname = "output.swf";
29 static int verbose = 2;
30 static int override_outputname = 0;
32 static struct options_t options[] =
40 int args_callback_option(char*name,char*val)
42 if(!strcmp(name, "V")) {
43 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
46 else if(!strcmp(name, "o")) {
48 override_outputname = 1;
51 else if(!strcmp(name, "v")) {
56 printf("Unknown option: -%s\n", name);
61 int args_callback_longoption(char*name,char*val)
63 return args_long2shortoption(options, name, val);
65 void args_callback_usage(char*name)
67 printf("Usage: %s [-o filename] file.wav\n", name);
68 printf("\t-v , --verbose\t\t\t Be more verbose\n");
69 printf("\t-o , --output filename\t\t set output filename (default: output.swf)\n");
70 printf("\t-V , --version\t\t\t Print program version and exit\n");
72 int args_callback_command(char*name,char*val)
75 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
82 static struct token_t* file;
91 static void syntaxerror(char*format, ...)
95 va_start(arglist, format);
96 vsprintf(buf, format, arglist);
98 printf("\"%s\", line %d column %d: error- %s\n", filename, line, column, buf);
102 static void warning(char*format, ...)
106 va_start(arglist, format);
107 vsprintf(buf, format, arglist);
109 printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
112 static void readToken()
114 type = file[pos].type;
116 syntaxerror("unexpected end of file");
118 text = file[pos].text;
119 textlen = strlen(text);
120 line = file[pos].line;
121 column = file[pos].column;
123 //printf("---> %d(%s) %s\n", type, type_names[type], text);
126 static void pushBack()
129 if(!pos) syntaxerror("internal error 3");
134 textlen = strlen(text);
137 column = file[p].column;
140 static int noMoreTokens()
142 if(file[pos].type == END)
147 // ------------------------------ swf routines ----------------------------
151 int type; //0=swf, 1=sprite, 2=clip
157 /* for sprites (1): */
163 dictionary_t oldinstances;
167 static int stackpos = 0;
169 static dictionary_t characters;
170 static char idmap[65536];
171 static TAG*tag = 0; //current tag
173 static int id; //current character id
174 static int currentframe; //current frame in current level
175 static SRECT currentrect; //current bounding box in current level
176 static U16 currentdepth;
177 static dictionary_t instances;
178 static dictionary_t fonts;
179 static dictionary_t sounds;
181 typedef struct _parameters {
183 float scalex, scaley;
191 typedef struct _character {
197 typedef struct _instance {
198 character_t*character;
200 parameters_t parameters;
201 TAG* lastTag; //last tag which set the object
202 U16 lastFrame; //frame lastTag is in
205 static void character_init(character_t*c)
207 memset(c, 0, sizeof(character_t));
209 static character_t* character_new()
212 c = (character_t*)malloc(sizeof(character_t));
216 static void instance_init(instance_t*i)
218 memset(i, 0, sizeof(instance_t));
220 static instance_t* instance_new()
223 c = (instance_t*)malloc(sizeof(instance_t));
228 static void incrementid()
232 syntaxerror("Out of character ids.");
237 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
239 character_t* c = character_new();
241 c->definingTag = ctag;
244 if(dictionary_lookup(&characters, name))
245 syntaxerror("character %s defined twice", name);
246 dictionary_put2(&characters, name, c);
248 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
250 swf_SetString(tag, name);
251 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
254 swf_SetString(tag, name);
256 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
258 instance_t* i = instance_new();
261 //swf_GetMatrix(0, &i->matrix);
262 if(dictionary_lookup(&instances, name))
263 syntaxerror("object %s defined twice", name);
264 dictionary_put2(&instances, name, i);
268 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)
271 p->scalex = scalex; p->scaley = scaley;
272 p->pin = pin; p->pivot = pivot;
273 p->rotate = rotate; p->cxform = cxform;
277 static void parameters_clear(parameters_t*p)
280 p->scalex = 1.0; p->scaley = 1.0;
281 p->pin.x = 1; p->pin.y = 0;
282 p->pivot.x = 0; p->pivot.y = 0;
285 swf_GetCXForm(0, &p->cxform, 1);
288 static void makeMatrix(MATRIX*m, parameters_t*p)
297 sx = p->scalex*cos(p->rotate/360*2*3.14159265358979);
298 r1 = -p->scalex*sin(p->rotate/360*2*3.14159265358979)+sx*p->shear;
299 r0 = p->scaley*sin(p->rotate/360*2*3.14159265358979);
300 sy = p->scaley*cos(p->rotate/360*2*3.14159265358979)+r0*p->shear;
302 m->sx = (int)(sx*65536+0.5);
303 m->r1 = (int)(r1*65536+0.5);
304 m->r0 = (int)(r0*65536+0.5);
305 m->sy = (int)(sy*65536+0.5);
309 h = swf_TurnPoint(p->pin, m);
314 static MATRIX s_instancepos(instance_t*i, parameters_t*p)
319 r = swf_TurnRect(i->character->size, &m);
320 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
321 currentrect.xmax == 0 && currentrect.ymax == 0)
324 swf_ExpandRect2(¤trect, &r);
328 void s_swf(char*name, SRECT r, int version, int fps, int compress)
330 SWF*swf = (SWF*)malloc(sizeof(SWF));
334 syntaxerror(".swf blocks can't be nested");
336 memset(swf, 0, sizeof(swf));
337 swf->fileVersion = version;
339 swf->frameRate = fps;
340 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
341 swf->compressed = compress;
342 rgb.r = 0x00;rgb.g = 0x00;rgb.b = 0x00;
343 swf_SetRGB(tag,&rgb);
345 if(stackpos==sizeof(stack)/sizeof(stack[0]))
346 syntaxerror("too many levels of recursion");
348 dictionary_init(&characters);
349 dictionary_init(&instances);
350 dictionary_init(&fonts);
351 dictionary_init(&sounds);
353 memset(&stack[stackpos], 0, sizeof(stack[0]));
354 stack[stackpos].type = 0;
355 stack[stackpos].filename = strdup(name);
356 stack[stackpos].swf = swf;
357 stack[stackpos].oldframe = -1;
362 memset(¤trect, 0, sizeof(currentrect));
365 memset(idmap, 0, sizeof(idmap));
369 void s_sprite(char*name)
371 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
372 swf_SetU16(tag, id); //id
373 swf_SetU16(tag, 0); //frames
375 memset(&stack[stackpos], 0, sizeof(stack[0]));
376 stack[stackpos].type = 1;
377 stack[stackpos].oldframe = currentframe;
378 stack[stackpos].olddepth = currentdepth;
379 stack[stackpos].oldrect = currentrect;
380 stack[stackpos].oldinstances = instances;
381 stack[stackpos].tag = tag;
382 stack[stackpos].id = id;
383 stack[stackpos].name = strdup(name);
385 /* FIXME: those four fields should be bundled together */
386 dictionary_init(&instances);
389 memset(¤trect, 0, sizeof(currentrect));
395 static void s_endSprite()
397 SRECT r = currentrect;
400 /* TODO: before clearing, prepend "<spritename>." to names and
401 copy into old instances dict */
402 dictionary_clear(&instances);
404 currentframe = stack[stackpos].oldframe;
405 currentrect = stack[stackpos].oldrect;
406 currentdepth = stack[stackpos].olddepth;
407 instances = stack[stackpos].oldinstances;
408 tag = swf_InsertTag(tag, ST_END);
410 tag = stack[stackpos].tag;
413 syntaxerror("internal error(7)");
415 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
416 free(stack[stackpos].name);
419 static void s_endSWF()
426 swf = stack[stackpos].swf;
427 filename = stack[stackpos].filename;
429 tag = swf_InsertTag(tag, ST_SHOWFRAME);
430 tag = swf_InsertTag(tag, ST_END);
432 swf_OptimizeTagOrder(swf);
434 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin))
435 swf->movieSize = currentrect; /* "autocrop" */
437 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
438 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
439 swf->movieSize.ymax += 20;
442 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
444 syntaxerror("couldn't create output file %s", filename);
447 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
449 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
453 dictionary_clear(&instances);
454 dictionary_clear(&characters);
455 dictionary_clear(&fonts);
456 dictionary_clear(&sounds);
465 if(stack[stackpos-1].type == 0)
466 syntaxerror("End of file encountered in .swf block");
467 if(stack[stackpos-1].type == 1)
468 syntaxerror("End of file encountered in .sprite block");
469 if(stack[stackpos-1].type == 2)
470 syntaxerror("End of file encountered in .clip block");
482 for(t=currentframe;t<nr;t++) {
483 tag = swf_InsertTag(tag, ST_SHOWFRAME);
488 RGBA black={r:0,g:0,b:0,a:0};
489 void s_box(char*name, int width, int height, RGBA color, int linewidth, RGBA fill, int dofill)
494 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
496 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
498 fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
500 r.xmin = -linewidth-linewidth/2;
501 r.ymin = -linewidth-linewidth/2;
502 r.xmax = width+linewidth+linewidth/2;
503 r.ymax = height+linewidth+linewidth/2;
505 swf_SetShapeHeader(tag,s);
506 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
507 swf_ShapeSetLine(tag,s,width,0);
508 swf_ShapeSetLine(tag,s,0,height);
509 swf_ShapeSetLine(tag,s,-width,0);
510 swf_ShapeSetLine(tag,s,0,-height);
511 swf_ShapeSetEnd(tag);
514 s_addcharacter(name, id, tag, r);
518 void s_circle(char*name, int r, RGBA color, int linewidth, RGBA fill, int dofill)
523 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
525 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
527 fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
529 rect.xmin = -linewidth-linewidth/2;
530 rect.ymin = -linewidth-linewidth/2;
531 rect.xmax = 2*r+linewidth+linewidth/2;
532 rect.ymax = 2*r+linewidth+linewidth/2;
534 swf_SetRect(tag,&rect);
535 swf_SetShapeHeader(tag,s);
536 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
537 swf_ShapeSetCircle(tag, s, r,r,r,r);
538 swf_ShapeSetEnd(tag);
541 s_addcharacter(name, id, tag, rect);
545 void s_textshape(char*name, char*fontname, char*_text, RGBA color, int linewidth, RGBA fill, int dofill)
551 U8*text = (U8*)_text;
554 font = dictionary_lookup(&fonts, fontname);
556 syntaxerror("font \"%s\" not known!", fontname);
558 syntaxerror("textshapes must be filled", fontname);
560 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
561 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
562 s_box(name, 0, 0, black, 20, black, 0);
565 g = font->ascii2glyph[text[0]];
566 rect = font->layout->bounds[g];
569 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
571 fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
573 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
575 swf_SetRect(tag, &rect);
576 swf_SetShapeStyles(tag, s);
577 swf_SetSimpleShape(tag, font->glyph[g].shape);
580 s_addcharacter(name, id, tag, rect);
583 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
588 font = dictionary_lookup(&fonts, fontname);
590 syntaxerror("font \"%s\" not known!", fontname);
592 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
594 if(!font->numchars) {
595 s_box(name, 0, 0, black, 20, black, 0);
598 r = swf_SetDefineText(tag, font, &color, text, size);
600 s_addcharacter(name, id, tag, r);
604 void dumpSWF(SWF*swf)
606 TAG* tag = swf->firstTag;
607 printf("vvvvvvvvvvvvvvvvvvvvv\n");
609 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
612 printf("^^^^^^^^^^^^^^^^^^^^^\n");
615 void s_font(char*name, char*filename)
620 f = open(filename,O_RDONLY|O_BINARY);
622 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
623 font = (SWFFONT*)malloc(sizeof(SWFFONT));
624 memset(font, 0, sizeof(SWFFONT));
625 dictionary_put2(&fonts, name, font);
629 if (swf_ReadSWF(f,&swf)>=0) {
630 swf_FontExtract(&swf, 0x4e46, &font);
635 syntaxerror("File \"%s\" isn't a valid rfxswf font file", filename);
640 /* fix the layout. Only needed for old fonts */
642 for(t=0;t<font->numchars;t++) {
643 font->glyph[t].advance = 0;
646 swf_FontCreateLayout(font);
650 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
651 swf_FontSetDefine2(tag, font);
654 if(dictionary_lookup(&fonts, name))
655 syntaxerror("font %s defined twice", name);
656 dictionary_put2(&fonts, name, font);
659 typedef struct _sound_t
665 void s_sound(char*name, char*filename)
667 struct WAV wav, wav2;
672 if(!readWAV(filename, &wav)) {
673 warning("Couldn't read wav file \"%s\"", filename);
677 convertWAV2mono(&wav, &wav2, 44100);
678 samples = (U16*)wav2.data;
679 numsamples = wav2.size/2;
683 tag = swf_InsertTag(tag, ST_DEFINESOUND);
684 swf_SetU16(tag, id); //id
685 swf_SetSoundDefine(tag, samples, numsamples);
687 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
691 if(dictionary_lookup(&sounds, name))
692 syntaxerror("sound %s defined twice", name);
693 dictionary_put2(&sounds, name, sound);
701 void s_playsound(char*name, int loops, int nomultiple, int stop)
703 sound_t* sound = dictionary_lookup(&sounds, name);
706 syntaxerror("Don't know anything about sound \"%s\"", name);
708 tag = swf_InsertTag(tag, ST_STARTSOUND);
709 swf_SetU16(tag, sound->id); //id
710 memset(&info, 0, sizeof(info));
713 info.nomultiple = nomultiple;
714 swf_SetSoundInfo(tag, &info);
717 void s_shape(char*name, char*filename)
725 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
726 f = open(filename,O_RDONLY);
728 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
729 s_box(name, 0, 0, black, 20, black, 0);
732 if (swf_ReadSWF(f,&swf)<0) {
733 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
734 s_box(name, 0, 0, black, 20, black, 0);
739 /* FIXME: The following sets the bounding Box for the character.
740 It is wrong for two reasons:
741 a) It may be too small (in case objects in the movie clip at the borders)
742 b) it may be too big (because the poor movie never got autocropped)
746 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
750 swf_Relocate(&swf, idmap);
756 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
757 if(cutout[t] == ftag->id) {
761 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
763 if(ftag->id == ST_END)
767 /* We simply dump all tags right after the sprite
768 header, relying on the fact that swf_OptimizeTagOrder() will
769 sort things out for us later.
770 We also rely on the fact that the imported SWF is well-formed.
772 tag = swf_InsertTag(tag, ftag->id);
773 swf_SetBlock(tag, ftag->data, ftag->len);
777 syntaxerror("Included file %s contains errors", filename);
778 tag = swf_InsertTag(tag, ST_END);
782 s_addcharacter(name, id, tag, r);
785 SRECT s_getCharBBox(char*name)
787 character_t* c = dictionary_lookup(&characters, name);
788 if(!c) syntaxerror("character '%s' unknown(2)", name);
791 SRECT s_getInstanceBBox(char*name)
793 instance_t * i = dictionary_lookup(&instances, name);
795 if(!i) syntaxerror("instance '%s' unknown(4)", name);
797 if(!c) syntaxerror("internal error(5)");
800 parameters_t s_getParameters(char*name)
802 instance_t * i = dictionary_lookup(&instances, name);
803 if(!i) syntaxerror("instance '%s' unknown(10)", name);
804 return i->parameters;
806 void s_startclip(char*instance, char*character, parameters_t p)
808 character_t* c = dictionary_lookup(&characters, character);
812 syntaxerror("character %s not known", character);
814 i = s_addinstance(instance, c, currentdepth);
816 m = s_instancepos(i, &p);
818 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
819 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
820 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
822 i->lastFrame= currentframe;
824 stack[stackpos].tag = tag;
825 stack[stackpos].type = 2;
834 swf_SetTagPos(stack[stackpos].tag, 0);
835 swf_GetPlaceObject(stack[stackpos].tag, &p);
836 p.clipdepth = currentdepth;
837 swf_ClearTag(stack[stackpos].tag);
838 swf_SetPlaceObject(stack[stackpos].tag, &p);
842 void s_put(char*instance, char*character, parameters_t p)
844 character_t* c = dictionary_lookup(&characters, character);
848 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
851 i = s_addinstance(instance, c, currentdepth);
853 m = s_instancepos(i, &p);
855 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
856 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
858 i->lastFrame = currentframe;
862 void s_jump(char*instance, parameters_t p)
864 instance_t* i = dictionary_lookup(&instances, instance);
867 syntaxerror("instance %s not known", instance);
871 m = s_instancepos(i, &p);
873 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
874 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
876 i->lastFrame = currentframe;
879 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
885 ratio = (float)pos/(float)num;
887 p.x = (p2->x-p1->x)*ratio + p1->x;
888 p.y = (p2->y-p1->y)*ratio + p1->y;
889 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
890 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
891 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
892 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
894 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
895 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
896 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
897 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
899 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
900 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
901 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
902 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
904 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
905 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
906 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
907 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
911 void s_change(char*instance, parameters_t p2)
913 instance_t* i = dictionary_lookup(&instances, instance);
917 int frame, allframes;
919 syntaxerror("instance %s not known", instance);
923 allframes = currentframe - i->lastFrame - 1;
925 warning(".change ignored. can only .put/.change an object once per frame.");
929 m = s_instancepos(i, &p2);
930 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
931 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
934 /* o.k., we got the start and end point set. Now iterate though all the
935 tags in between, inserting object changes after each new frame */
938 if(!t) syntaxerror("internal error(6)");
940 while(frame < allframes) {
941 if(t->id == ST_SHOWFRAME) {
946 p = s_interpolate(&p1, &p2, frame, allframes);
947 m = s_instancepos(i, &p); //needed?
948 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
949 i->lastFrame = currentframe;
950 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
952 if(frame == allframes)
957 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
961 void s_delinstance(char*instance)
963 instance_t* i = dictionary_lookup(&instances, instance);
965 syntaxerror("instance %s not known", instance);
967 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
968 swf_SetU16(tag, i->depth);
969 dictionary_del(&instances, instance);
972 void s_qchange(char*instance, parameters_t p)
979 syntaxerror(".end unexpected");
980 if(stack[stackpos-1].type == 0)
982 else if(stack[stackpos-1].type == 1)
984 else if(stack[stackpos-1].type == 2)
986 else syntaxerror("internal error 1");
989 // ------------------------------------------------------------------------
991 typedef int command_func_t(map_t*args);
993 SRECT parseBox(char*str)
996 float xmin, xmax, ymin, ymax;
997 char*x = strchr(str, 'x');
999 if(!strcmp(str, "autocrop")) {
1000 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1004 d1 = strchr(x+1, ':');
1006 d2 = strchr(d1+1, ':');
1008 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1012 else if(d1 && !d2) {
1013 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1019 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1024 r.xmin = (SCOORD)(xmin*20);
1025 r.ymin = (SCOORD)(ymin*20);
1026 r.xmax = (SCOORD)(xmax*20);
1027 r.ymax = (SCOORD)(ymax*20);
1030 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1033 float parseFloat(char*str)
1037 int parseInt(char*str)
1042 if(str[0]=='+' || str[0]=='-')
1046 if(str[t]<'0' || str[t]>'9')
1047 syntaxerror("Not an Integer: \"%s\"", str);
1050 int parseTwip(char*str)
1054 if(str[0]=='+' || str[0]=='-') {
1059 dot = strchr(str, '.');
1063 return sign*parseInt(str)*20;
1065 int l=strlen(++dot);
1067 for(s=str;s<dot-1;s++)
1068 if(*s<'0' || *s>'9')
1069 syntaxerror("Not a coordinate: \"%s\"", str);
1071 if(*s<'0' || *s>'9')
1072 syntaxerror("Not a coordinate: \"%s\"", str);
1074 if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) {
1075 warning("precision loss: %s converted to twip", str);
1080 return sign*atoi(str)*20;
1082 return sign*atoi(str)*20+atoi(dot)*2;
1084 return sign*atoi(str)*20+atoi(dot)/5;
1089 int isPoint(char*str)
1091 if(strchr(str, '('))
1097 SPOINT parsePoint(char*str)
1101 int l = strlen(str);
1102 char*comma = strchr(str, ',');
1103 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1104 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1105 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1106 p.x = parseTwip(tmp);
1107 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1108 p.y = parseTwip(tmp);
1112 int parseColor2(char*str, RGBA*color)
1114 int l = strlen(str);
1118 struct {unsigned char r,g,b;char*name;} colors[] =
1119 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1120 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1121 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1122 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1123 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1124 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1125 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1126 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1127 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1128 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1129 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1130 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1134 if(str[0]=='#' && (l==7 || l==9)) {
1135 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1137 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1139 color->r = r; color->g = g; color->b = b; color->a = a;
1142 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1143 if(!strcmp(str, colors[t].name)) {
1148 color->r = r; color->g = g; color->b = b; color->a = a;
1154 RGBA parseColor(char*str)
1157 if(!parseColor2(str, &c))
1158 syntaxerror("Expression '%s' is not a color", str);
1162 typedef struct _muladd {
1167 MULADD parseMulAdd(char*str)
1170 char* str2 = (char*)malloc(strlen(str)+5);
1177 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1178 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1179 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1180 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1181 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1182 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1183 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1184 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1185 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1186 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1188 syntaxerror("'%s' is not a valid color transform expression", str);
1190 m.add = (int)(add*256);
1191 m.mul = (int)(mul*256);
1196 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1198 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1199 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1201 if(a<-32768) a=-32768;
1202 if(a>32767) a=32767;
1203 if(m<-32768) m=-32768;
1204 if(m>32767) m=32767;
1210 float parsePercent(char*str)
1212 int l = strlen(str);
1216 return atoi(str)/100.0;
1218 syntaxerror("Expression '%s' is not a percentage", str);
1221 int isPercent(char*str)
1223 return str[strlen(str)-1]=='%';
1225 int parseNewSize(char*str, int size)
1228 return parsePercent(str)*size;
1230 return (int)(atof(str)*20);
1233 int isColor(char*str)
1236 return parseColor2(str, &c);
1239 static char* lu(map_t* args, char*name)
1241 char* value = map_lookup(args, name);
1243 map_dump(args, stdout, "");
1244 syntaxerror("internal error 2: value %s should be set", name);
1249 static int c_swf(map_t*args)
1251 char* name = lu(args, "name");
1252 char* compressstr = lu(args, "compress");
1253 SRECT bbox = parseBox(lu(args, "bbox"));
1254 int version = parseInt(lu(args, "version"));
1255 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1257 if(!strcmp(name, "!default!") || override_outputname)
1260 if(!strcmp(compressstr, "default"))
1261 compress = version==6;
1262 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1264 else if(!strcmp(compressstr, "no"))
1266 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1268 s_swf(name, bbox, version, fps, compress);
1271 int isRelative(char*str)
1273 return !strncmp(str, "<plus>", 6) ||
1274 !strncmp(str, "<minus>", 7);
1276 char* getOffset(char*str)
1278 if(!strncmp(str, "<plus>", 6))
1280 if(!strncmp(str, "<minus>", 7))
1282 syntaxerror("internal error (347)");
1285 int getSign(char*str)
1287 if(!strncmp(str, "<plus>", 6))
1289 if(!strncmp(str, "<minus>", 7))
1291 syntaxerror("internal error (348)");
1294 static dictionary_t points;
1295 static mem_t mpoints;
1296 int points_initialized = 0;
1298 SPOINT getPoint(SRECT r, char*name)
1301 if(!strcmp(name, "center")) {
1303 p.x = (r.xmin + r.xmax)/2;
1304 p.y = (r.ymin + r.ymax)/2;
1308 if(points_initialized)
1309 l = (int)dictionary_lookup(&points, name);
1311 syntaxerror("Invalid point: \"%s\".", name);
1314 return *(SPOINT*)&mpoints.buffer[l];
1316 static int c_gradient(map_t*args)
1320 static int c_point(map_t*args)
1322 char*name = lu(args, "name");
1326 if(!points_initialized) {
1327 dictionary_init(&points);
1329 points_initialized = 1;
1331 p.x = parseTwip(lu(args, "x"));
1332 p.y = parseTwip(lu(args, "y"));
1333 pos = mem_put(&mpoints, &p, sizeof(p));
1334 string_set(&s1, name);
1336 dictionary_put(&points, s1, (void*)pos);
1339 static int c_play(map_t*args)
1341 char*name = lu(args, "sound");
1342 char*loop = lu(args, "loop");
1343 char*nomultiple = lu(args, "nomultiple");
1345 if(!strcmp(nomultiple, "nomultiple"))
1348 nm = parseInt(nomultiple);
1350 s_playsound(name, parseInt(loop), nm, 0);
1354 static int c_stop(map_t*args)
1356 char*name = lu(args, "sound");
1357 s_playsound(name, 0,0,1);
1361 static int c_placement(map_t*args, int type)
1363 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1366 char* luminancestr = lu(args, "luminance");
1367 char* scalestr = lu(args, "scale");
1368 char* scalexstr = lu(args, "scalex");
1369 char* scaleystr = lu(args, "scaley");
1370 char* rotatestr = lu(args, "rotate");
1371 char* shearstr = lu(args, "shear");
1372 char* xstr="", *pivotstr="";
1373 char* ystr="", *anglestr="";
1374 char*above = lu(args, "above"); /*FIXME*/
1375 char*below = lu(args, "below");
1376 char* rstr = lu(args, "red");
1377 char* gstr = lu(args, "green");
1378 char* bstr = lu(args, "blue");
1379 char* astr = lu(args, "alpha");
1380 char* pinstr = lu(args, "pin");
1389 pivotstr = lu(args, "pivot");
1390 anglestr = lu(args, "angle");
1392 xstr = lu(args, "x");
1393 ystr = lu(args, "y");
1396 luminance = parseMulAdd(luminancestr);
1399 luminance.mul = 256;
1403 if(scalexstr[0]||scaleystr[0])
1404 syntaxerror("scalex/scaley and scale cannot both be set");
1405 scalexstr = scaleystr = scalestr;
1408 if(type == 0 || type == 4) {
1410 character = lu(args, "character");
1411 parameters_clear(&p);
1413 p = s_getParameters(instance);
1418 if(isRelative(xstr)) {
1419 if(type == 0 || type == 4)
1420 syntaxerror("relative x values not allowed for initial put or startclip");
1421 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
1423 p.x = parseTwip(xstr);
1427 if(isRelative(ystr)) {
1428 if(type == 0 || type == 4)
1429 syntaxerror("relative y values not allowed for initial put or startclip");
1430 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
1432 p.y = parseTwip(ystr);
1436 /* scale, scalex, scaley */
1438 oldbbox = s_getCharBBox(character);
1440 oldbbox = s_getInstanceBBox(instance);
1442 oldwidth = oldbbox.xmax - oldbbox.xmin;
1443 oldheight = oldbbox.ymax - oldbbox.ymin;
1445 if(oldwidth==0) p.scalex = 1.0;
1448 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
1452 if(oldheight==0) p.scaley = 1.0;
1455 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
1461 if(isRelative(rotatestr)) {
1462 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
1464 p.rotate = parseFloat(rotatestr);
1470 if(isRelative(shearstr)) {
1471 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
1473 p.shear = parseFloat(shearstr);
1478 if(isPoint(pivotstr))
1479 p.pivot = parsePoint(pivotstr);
1481 p.pivot = getPoint(oldbbox, pivotstr);
1485 p.pin = parsePoint(pinstr);
1487 p.pin = getPoint(oldbbox, pinstr);
1490 /* color transform */
1492 if(rstr[0] || luminancestr[0]) {
1495 r = parseMulAdd(rstr);
1497 r.add = p.cxform.r0;
1498 r.mul = p.cxform.r1;
1500 r = mergeMulAdd(r, luminance);
1501 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
1503 if(gstr[0] || luminancestr[0]) {
1506 g = parseMulAdd(gstr);
1508 g.add = p.cxform.g0;
1509 g.mul = p.cxform.g1;
1511 g = mergeMulAdd(g, luminance);
1512 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
1514 if(bstr[0] || luminancestr[0]) {
1517 b = parseMulAdd(bstr);
1519 b.add = p.cxform.b0;
1520 b.mul = p.cxform.b1;
1522 b = mergeMulAdd(b, luminance);
1523 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
1526 MULADD a = parseMulAdd(astr);
1527 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
1531 s_put(instance, character, p);
1533 s_change(instance, p);
1535 s_qchange(instance, p);
1537 s_jump(instance, p);
1539 s_startclip(instance, character, p);
1542 static int c_put(map_t*args)
1544 c_placement(args, 0);
1547 static int c_change(map_t*args)
1549 c_placement(args, 1);
1552 static int c_qchange(map_t*args)
1554 c_placement(args, 2);
1557 static int c_arcchange(map_t*args)
1559 c_placement(args, 2);
1562 static int c_jump(map_t*args)
1564 c_placement(args, 3);
1567 static int c_startclip(map_t*args)
1569 c_placement(args, 4);
1572 static int c_del(map_t*args)
1574 char*instance = lu(args, "name");
1575 s_delinstance(instance);
1578 static int c_end(map_t*args)
1583 static int c_sprite(map_t*args)
1585 char* name = lu(args, "name");
1589 static int c_frame(map_t*args)
1591 char*framestr = lu(args, "n");
1593 if(isRelative(framestr)) {
1594 frame = s_getframe();
1595 if(getSign(framestr)<0)
1596 syntaxerror("relative frame expressions must be positive");
1597 frame += parseInt(getOffset(framestr));
1600 frame = parseInt(framestr);
1601 if(s_getframe() >= frame
1602 && !(frame==0 && s_getframe()==frame)) // equality is o.k. for frame 0
1603 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
1608 static int c_primitive(map_t*args)
1610 char*name = lu(args, "name");
1611 char*command = lu(args, "commandname");
1612 int width=0, height=0, r=0;
1613 int linewidth = parseTwip(lu(args, "line"));
1614 char*colorstr = lu(args, "color");
1615 RGBA color = parseColor(colorstr);
1616 char*fillstr = lu(args, "fill");
1622 if(!strcmp(command, "circle"))
1624 else if(!strcmp(command, "textshape"))
1628 width = parseTwip(lu(args, "width"));
1629 height = parseTwip(lu(args, "height"));
1630 } else if (type==1) {
1631 r = parseTwip(lu(args, "r"));
1632 } else if (type==2) {
1633 text = lu(args, "text");
1634 font = lu(args, "font");
1637 if(!strcmp(fillstr, "fill"))
1639 if(!strcmp(fillstr, "none"))
1641 if(width<0 || height<0 || linewidth<0 || r<0)
1642 syntaxerror("values width, height, line, r must be positive");
1643 if(!dofill || isColor(fillstr)) {
1645 fill = parseColor(fillstr);
1647 /* FIXME - texture fill */
1648 fill.r = fill.g = 0;
1649 fill.b = fill.a = 255;
1650 warning("texture fill not supported yet. Filling with black.");
1652 if(type == 0) s_box(name, width, height, color, linewidth, fill, dofill);
1653 else if(type==1) s_circle(name, r, color, linewidth, fill, dofill);
1654 else if(type==2) s_textshape(name, font, text, color, linewidth, fill, dofill);
1658 static int c_shape(map_t*args)
1660 char*name = lu(args, "name");
1661 char*filename = lu(args, "filename");
1662 s_shape(name, filename);
1666 static int c_font(map_t*args)
1668 char*name = lu(args, "name");
1669 char*filename = lu(args, "filename");
1670 s_font(name, filename);
1674 static int c_sound(map_t*args)
1676 char*name = lu(args, "name");
1677 char*filename = lu(args, "filename");
1678 s_sound(name, filename);
1682 static int c_text(map_t*args)
1684 char*name = lu(args, "name");
1685 char*text = lu(args, "text");
1686 char*font = lu(args, "font");
1687 float size = parsePercent(lu(args, "size"));
1688 RGBA color = parseColor(lu(args, "color"));
1689 s_text(name, font, text, (int)(size*100), color);
1693 static int c_soundtrack(map_t*args)
1698 int fakechar(map_t*args)
1700 char*name = lu(args, "name");
1701 s_box(name, 0, 0, black, 20, black, 0);
1705 static int c_egon(map_t*args) {return fakechar(args);}
1706 static int c_button(map_t*args) {return fakechar(args);}
1707 static int c_edittext(map_t*args) {return fakechar(args);}
1709 static int c_morphshape(map_t*args) {return fakechar(args);}
1710 static int c_image(map_t*args) {return fakechar(args);}
1711 static int c_movie(map_t*args) {return fakechar(args);}
1713 static int c_buttonsounds(map_t*args) {return 0;}
1714 static int c_buttonput(map_t*args) {return 0;}
1715 static int c_texture(map_t*args) {return 0;}
1716 static int c_action(map_t*args) {return 0;}
1720 command_func_t* func;
1723 {{"swf", c_swf, "bbox=autocrop version=5 fps=50 name=!default! @compress=default"},
1724 {"frame", c_frame, "n=<plus>1"},
1726 // "import" type stuff
1727 {"shape", c_shape, "name filename"},
1728 {"morphshape", c_morphshape, "name start end"},
1729 {"jpeg", c_image, "name filename quality=80%"},
1730 {"png", c_image, "name filename"},
1731 {"movie", c_movie, "name filename"},
1732 {"sound", c_sound, "name filename"},
1733 {"font", c_font, "name filename"},
1734 {"soundtrack", c_soundtrack, "filename"},
1736 // generators of primitives
1738 {"point", c_point, "name x=0 y=0"},
1739 {"gradient", c_gradient, "name"},
1741 // character generators
1742 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
1743 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
1744 {"textshape", c_primitive, "name text font color=white line=1 @fill=none"},
1745 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
1746 {"button", c_button, "name shape over=*shape press=*shape area=*shape"},
1747 {"text", c_text, "name text font size=100% color=white"},
1748 {"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"},
1750 {"buttonsounds", c_buttonsounds, "name press=0 release=0 enter=0 leave=0"},
1753 {"play", c_play, "sound loop=0 @nomultiple=0"},
1754 {"stop", c_stop, "sound"},
1756 // object placement tags
1757 {"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="},
1758 {"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="},
1759 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1760 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1761 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1762 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1763 {"del", c_del, "name"},
1764 // virtual object placement
1765 {"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="},
1766 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
1768 // commands which start a block
1769 //startclip (see above)
1770 {"sprite", c_sprite, "name"},
1771 {"action", c_action, ""},
1777 static map_t parseArguments(char*command, char*pattern)
1793 string_set(&t1, "commandname");
1794 string_set(&t2, command);
1795 map_put(&result, t1, t2);
1797 if(!pattern || !*pattern)
1804 if(!strncmp("<i> ", x, 3)) {
1806 if(type == COMMAND || type == LABEL) {
1808 syntaxerror("character name expected");
1810 name[pos].str = "instance";
1812 value[pos].str = text;
1813 value[pos].len = strlen(text);
1817 if(type == ASSIGNMENT)
1820 name[pos].str = "character";
1822 value[pos].str = text;
1823 value[pos].len = strlen(text);
1831 isboolean[pos] = (x[0] =='@');
1844 name[pos].len = d-x;
1849 name[pos].len = e-x;
1850 value[pos].str = e+1;
1851 value[pos].len = d-e-1;
1859 /* for(t=0;t<len;t++) {
1860 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
1861 isboolean[t]?"(boolean)":"");
1866 if(type == LABEL || type == COMMAND) {
1871 // first, search for boolean arguments
1872 for(pos=0;pos<len;pos++)
1874 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
1876 if(type == ASSIGNMENT)
1878 value[pos].str = text;
1879 value[pos].len = strlen(text);
1880 /*printf("setting boolean parameter %s (to %s)\n",
1881 strdup_n(name[pos], namelen[pos]),
1882 strdup_n(value[pos], valuelen[pos]));*/
1887 // second, search for normal arguments
1889 for(pos=0;pos<len;pos++)
1891 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
1892 (type != ASSIGNMENT && !set[pos])) {
1894 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
1896 if(type == ASSIGNMENT)
1899 value[pos].str = text;
1900 value[pos].len = strlen(text);
1902 printf("setting parameter %s (to %s)\n",
1903 strdup_n(name[pos].str, name[pos].len),
1904 strdup_n(value[pos].str, value[pos].len));
1910 syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
1914 for(t=0;t<len;t++) {
1915 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
1918 for(t=0;t<len;t++) {
1919 if(value[t].str && value[t].str[0] == '*') {
1920 //relative default- take value from some other parameter
1922 for(s=0;s<len;s++) {
1923 if(value[s].len == value[t].len-1 &&
1924 !strncmp(&value[t].str[1], value[s].str, value[s].len))
1925 value[t].str = value[s].str;
1928 if(value[t].str == 0) {
1930 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
1934 /* ok, now construct the dictionary from the parameters */
1938 map_put(&result, name[t], value[t]);
1942 static void parseArgumentsForCommand(char*command)
1947 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
1948 if(!strcmp(arguments[t].command, command)) {
1949 args = parseArguments(command, arguments[t].arguments);
1954 syntaxerror("command %s not known", command);
1957 printf(".%s\n", command);fflush(stdout);
1958 map_dump(&args, stdout, "\t");fflush(stdout);
1961 (*arguments[nr].func)(&args);
1963 if(!strcmp(command, "button") ||
1964 !strcmp(command, "action")) {
1967 if(type == COMMAND) {
1968 if(!strcmp(text, "end"))
1982 int main (int argc,char ** argv)
1985 processargs(argc, argv);
1986 initLog(0,-1,0,0,-1,verbose);
1989 args_callback_usage(argv[0]);
1992 file = generateTokens(filename);
1994 printf("parser returned error.\n");
2001 while(!noMoreTokens()) {
2004 syntaxerror("command expected");
2005 parseArgumentsForCommand(text);