2 Compiles swf code (.sc) files into .swf files.
4 Part of the swftools package.
6 Copyright (c) 2001 Matthias Kramm <kramm@quiss.org>
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
29 #include "../config.h"
30 #include "../lib/rfxswf.h"
31 #include "../lib/log.h"
32 #include "../lib/args.h"
39 static char * filename = 0;
40 static char * outputname = "output.swf";
41 static int verbose = 2;
42 static int override_outputname = 0;
44 static struct options_t options[] =
52 int args_callback_option(char*name,char*val)
54 if(!strcmp(name, "V")) {
55 printf("swfc - part of %s %s\n", PACKAGE, VERSION);
58 else if(!strcmp(name, "o")) {
60 override_outputname = 1;
63 else if(!strcmp(name, "v")) {
68 printf("Unknown option: -%s\n", name);
73 int args_callback_longoption(char*name,char*val)
75 return args_long2shortoption(options, name, val);
77 void args_callback_usage(char*name)
79 printf("Usage: %s [-o filename] file.wav\n", name);
80 printf("\t-v , --verbose\t\t\t Be more verbose\n");
81 printf("\t-o , --output filename\t\t set output filename (default: output.swf)\n");
82 printf("\t-V , --version\t\t\t Print program version and exit\n");
84 int args_callback_command(char*name,char*val)
87 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
94 static struct token_t* file;
103 static void syntaxerror(char*format, ...)
107 va_start(arglist, format);
108 vsprintf(buf, format, arglist);
110 printf("\"%s\", line %d column %d: error- %s\n", filename, line, column, buf);
114 static void warning(char*format, ...)
118 va_start(arglist, format);
119 vsprintf(buf, format, arglist);
121 printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
124 static void readToken()
126 type = file[pos].type;
128 syntaxerror("unexpected end of file");
130 text = file[pos].text;
131 textlen = strlen(text);
132 line = file[pos].line;
133 column = file[pos].column;
135 //printf("---> %d(%s) %s\n", type, type_names[type], text);
138 static void pushBack()
141 if(!pos) syntaxerror("internal error 3");
146 textlen = strlen(text);
149 column = file[p].column;
152 static int noMoreTokens()
154 if(file[pos].type == END)
159 // ------------------------------ swf routines ----------------------------
163 int type; //0=swf, 1=sprite, 2=clip
169 /* for sprites (1): */
175 dictionary_t oldinstances;
179 static int stackpos = 0;
181 static dictionary_t characters;
182 static char idmap[65536];
183 static TAG*tag = 0; //current tag
185 static int id; //current character id
186 static int currentframe; //current frame in current level
187 static SRECT currentrect; //current bounding box in current level
188 static U16 currentdepth;
189 static dictionary_t instances;
190 static dictionary_t fonts;
191 static dictionary_t sounds;
193 typedef struct _parameters {
195 float scalex, scaley;
203 typedef struct _character {
209 typedef struct _instance {
210 character_t*character;
212 parameters_t parameters;
213 TAG* lastTag; //last tag which set the object
214 U16 lastFrame; //frame lastTag is in
217 static void character_init(character_t*c)
219 memset(c, 0, sizeof(character_t));
221 static character_t* character_new()
224 c = (character_t*)malloc(sizeof(character_t));
228 static void instance_init(instance_t*i)
230 memset(i, 0, sizeof(instance_t));
232 static instance_t* instance_new()
235 c = (instance_t*)malloc(sizeof(instance_t));
240 static void incrementid()
244 syntaxerror("Out of character ids.");
249 static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
251 character_t* c = character_new();
253 c->definingTag = ctag;
256 if(dictionary_lookup(&characters, name))
257 syntaxerror("character %s defined twice", name);
258 dictionary_put2(&characters, name, c);
260 tag = swf_InsertTag(tag, ST_NAMECHARACTER);
262 swf_SetString(tag, name);
263 tag = swf_InsertTag(tag, ST_EXPORTASSETS);
266 swf_SetString(tag, name);
268 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
270 instance_t* i = instance_new();
273 //swf_GetMatrix(0, &i->matrix);
274 if(dictionary_lookup(&instances, name))
275 syntaxerror("object %s defined twice", name);
276 dictionary_put2(&instances, name, i);
280 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)
283 p->scalex = scalex; p->scaley = scaley;
284 p->pin = pin; p->pivot = pivot;
285 p->rotate = rotate; p->cxform = cxform;
289 static void parameters_clear(parameters_t*p)
292 p->scalex = 1.0; p->scaley = 1.0;
293 p->pin.x = 1; p->pin.y = 0;
294 p->pivot.x = 0; p->pivot.y = 0;
297 swf_GetCXForm(0, &p->cxform, 1);
300 static void makeMatrix(MATRIX*m, parameters_t*p)
309 sx = p->scalex*cos(p->rotate/360*2*3.14159265358979);
310 r1 = -p->scalex*sin(p->rotate/360*2*3.14159265358979)+sx*p->shear;
311 r0 = p->scaley*sin(p->rotate/360*2*3.14159265358979);
312 sy = p->scaley*cos(p->rotate/360*2*3.14159265358979)+r0*p->shear;
314 m->sx = (int)(sx*65536+0.5);
315 m->r1 = (int)(r1*65536+0.5);
316 m->r0 = (int)(r0*65536+0.5);
317 m->sy = (int)(sy*65536+0.5);
321 h = swf_TurnPoint(p->pin, m);
326 static MATRIX s_instancepos(instance_t*i, parameters_t*p)
331 r = swf_TurnRect(i->character->size, &m);
332 if(currentrect.xmin == 0 && currentrect.ymin == 0 &&
333 currentrect.xmax == 0 && currentrect.ymax == 0)
336 swf_ExpandRect2(¤trect, &r);
340 void s_swf(char*name, SRECT r, int version, int fps, int compress)
342 SWF*swf = (SWF*)malloc(sizeof(SWF));
346 syntaxerror(".swf blocks can't be nested");
348 memset(swf, 0, sizeof(swf));
349 swf->fileVersion = version;
351 swf->frameRate = fps;
352 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
353 swf->compressed = compress;
354 rgb.r = 0x00;rgb.g = 0x00;rgb.b = 0x00;
355 swf_SetRGB(tag,&rgb);
357 if(stackpos==sizeof(stack)/sizeof(stack[0]))
358 syntaxerror("too many levels of recursion");
360 dictionary_init(&characters);
361 dictionary_init(&instances);
362 dictionary_init(&fonts);
363 dictionary_init(&sounds);
365 memset(&stack[stackpos], 0, sizeof(stack[0]));
366 stack[stackpos].type = 0;
367 stack[stackpos].filename = strdup(name);
368 stack[stackpos].swf = swf;
369 stack[stackpos].oldframe = -1;
374 memset(¤trect, 0, sizeof(currentrect));
377 memset(idmap, 0, sizeof(idmap));
381 void s_sprite(char*name)
383 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
384 swf_SetU16(tag, id); //id
385 swf_SetU16(tag, 0); //frames
387 memset(&stack[stackpos], 0, sizeof(stack[0]));
388 stack[stackpos].type = 1;
389 stack[stackpos].oldframe = currentframe;
390 stack[stackpos].olddepth = currentdepth;
391 stack[stackpos].oldrect = currentrect;
392 stack[stackpos].oldinstances = instances;
393 stack[stackpos].tag = tag;
394 stack[stackpos].id = id;
395 stack[stackpos].name = strdup(name);
397 /* FIXME: those four fields should be bundled together */
398 dictionary_init(&instances);
401 memset(¤trect, 0, sizeof(currentrect));
407 static void s_endSprite()
409 SRECT r = currentrect;
412 /* TODO: before clearing, prepend "<spritename>." to names and
413 copy into old instances dict */
414 dictionary_clear(&instances);
416 currentframe = stack[stackpos].oldframe;
417 currentrect = stack[stackpos].oldrect;
418 currentdepth = stack[stackpos].olddepth;
419 instances = stack[stackpos].oldinstances;
420 tag = swf_InsertTag(tag, ST_END);
422 tag = stack[stackpos].tag;
425 syntaxerror("internal error(7)");
427 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
428 free(stack[stackpos].name);
431 static void s_endSWF()
438 swf = stack[stackpos].swf;
439 filename = stack[stackpos].filename;
441 tag = swf_InsertTag(tag, ST_SHOWFRAME);
442 tag = swf_InsertTag(tag, ST_END);
444 swf_OptimizeTagOrder(swf);
446 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin))
447 swf->movieSize = currentrect; /* "autocrop" */
449 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
450 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
451 swf->movieSize.ymax += 20;
454 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
456 syntaxerror("couldn't create output file %s", filename);
459 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
461 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
465 dictionary_clear(&instances);
466 dictionary_clear(&characters);
467 dictionary_clear(&fonts);
468 dictionary_clear(&sounds);
477 if(stack[stackpos-1].type == 0)
478 syntaxerror("End of file encountered in .swf block");
479 if(stack[stackpos-1].type == 1)
480 syntaxerror("End of file encountered in .sprite block");
481 if(stack[stackpos-1].type == 2)
482 syntaxerror("End of file encountered in .clip block");
494 for(t=currentframe;t<nr;t++) {
495 tag = swf_InsertTag(tag, ST_SHOWFRAME);
500 RGBA black={r:0,g:0,b:0,a:0};
501 void s_box(char*name, int width, int height, RGBA color, int linewidth, RGBA fill, int dofill)
506 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
508 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
510 fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
512 r.xmin = -linewidth-linewidth/2;
513 r.ymin = -linewidth-linewidth/2;
514 r.xmax = width+linewidth+linewidth/2;
515 r.ymax = height+linewidth+linewidth/2;
517 swf_SetShapeHeader(tag,s);
518 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
519 swf_ShapeSetLine(tag,s,width,0);
520 swf_ShapeSetLine(tag,s,0,height);
521 swf_ShapeSetLine(tag,s,-width,0);
522 swf_ShapeSetLine(tag,s,0,-height);
523 swf_ShapeSetEnd(tag);
526 s_addcharacter(name, id, tag, r);
530 void s_circle(char*name, int r, RGBA color, int linewidth, RGBA fill, int dofill)
535 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
537 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
539 fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
541 rect.xmin = -linewidth-linewidth/2;
542 rect.ymin = -linewidth-linewidth/2;
543 rect.xmax = 2*r+linewidth+linewidth/2;
544 rect.ymax = 2*r+linewidth+linewidth/2;
546 swf_SetRect(tag,&rect);
547 swf_SetShapeHeader(tag,s);
548 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
549 swf_ShapeSetCircle(tag, s, r,r,r,r);
550 swf_ShapeSetEnd(tag);
553 s_addcharacter(name, id, tag, rect);
557 void s_textshape(char*name, char*fontname, char*_text, RGBA color, int linewidth, RGBA fill, int dofill)
563 U8*text = (U8*)_text;
566 font = dictionary_lookup(&fonts, fontname);
568 syntaxerror("font \"%s\" not known!", fontname);
570 syntaxerror("textshapes must be filled", fontname);
572 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
573 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
574 s_box(name, 0, 0, black, 20, black, 0);
577 g = font->ascii2glyph[text[0]];
578 rect = font->layout->bounds[g];
581 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
583 fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
585 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
587 swf_SetRect(tag, &rect);
588 swf_SetShapeStyles(tag, s);
589 swf_SetSimpleShape(tag, font->glyph[g].shape);
592 s_addcharacter(name, id, tag, rect);
595 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
600 font = dictionary_lookup(&fonts, fontname);
602 syntaxerror("font \"%s\" not known!", fontname);
604 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
606 if(!font->numchars) {
607 s_box(name, 0, 0, black, 20, black, 0);
610 r = swf_SetDefineText(tag, font, &color, text, size);
612 s_addcharacter(name, id, tag, r);
616 void dumpSWF(SWF*swf)
618 TAG* tag = swf->firstTag;
619 printf("vvvvvvvvvvvvvvvvvvvvv\n");
621 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
624 printf("^^^^^^^^^^^^^^^^^^^^^\n");
627 void s_font(char*name, char*filename)
632 f = open(filename,O_RDONLY|O_BINARY);
634 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
635 font = (SWFFONT*)malloc(sizeof(SWFFONT));
636 memset(font, 0, sizeof(SWFFONT));
637 dictionary_put2(&fonts, name, font);
641 if (swf_ReadSWF(f,&swf)>=0) {
642 swf_FontExtract(&swf, 0x4e46, &font);
647 syntaxerror("File \"%s\" isn't a valid rfxswf font file", filename);
652 /* fix the layout. Only needed for old fonts */
654 for(t=0;t<font->numchars;t++) {
655 font->glyph[t].advance = 0;
658 swf_FontCreateLayout(font);
662 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
663 swf_FontSetDefine2(tag, font);
666 if(dictionary_lookup(&fonts, name))
667 syntaxerror("font %s defined twice", name);
668 dictionary_put2(&fonts, name, font);
671 typedef struct _sound_t
677 void s_sound(char*name, char*filename)
679 struct WAV wav, wav2;
684 if(!readWAV(filename, &wav)) {
685 warning("Couldn't read wav file \"%s\"", filename);
689 convertWAV2mono(&wav, &wav2, 44100);
690 samples = (U16*)wav2.data;
691 numsamples = wav2.size/2;
695 tag = swf_InsertTag(tag, ST_DEFINESOUND);
696 swf_SetU16(tag, id); //id
697 swf_SetSoundDefine(tag, samples, numsamples);
699 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
703 if(dictionary_lookup(&sounds, name))
704 syntaxerror("sound %s defined twice", name);
705 dictionary_put2(&sounds, name, sound);
713 void s_playsound(char*name, int loops, int nomultiple, int stop)
715 sound_t* sound = dictionary_lookup(&sounds, name);
718 syntaxerror("Don't know anything about sound \"%s\"", name);
720 tag = swf_InsertTag(tag, ST_STARTSOUND);
721 swf_SetU16(tag, sound->id); //id
722 memset(&info, 0, sizeof(info));
725 info.nomultiple = nomultiple;
726 swf_SetSoundInfo(tag, &info);
729 void s_shape(char*name, char*filename)
737 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
738 f = open(filename,O_RDONLY);
740 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
741 s_box(name, 0, 0, black, 20, black, 0);
744 if (swf_ReadSWF(f,&swf)<0) {
745 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
746 s_box(name, 0, 0, black, 20, black, 0);
751 /* FIXME: The following sets the bounding Box for the character.
752 It is wrong for two reasons:
753 a) It may be too small (in case objects in the movie clip at the borders)
754 b) it may be too big (because the poor movie never got autocropped)
758 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
762 swf_Relocate(&swf, idmap);
768 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
769 if(cutout[t] == ftag->id) {
773 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
775 if(ftag->id == ST_END)
779 /* We simply dump all tags right after the sprite
780 header, relying on the fact that swf_OptimizeTagOrder() will
781 sort things out for us later.
782 We also rely on the fact that the imported SWF is well-formed.
784 tag = swf_InsertTag(tag, ftag->id);
785 swf_SetBlock(tag, ftag->data, ftag->len);
789 syntaxerror("Included file %s contains errors", filename);
790 tag = swf_InsertTag(tag, ST_END);
794 s_addcharacter(name, id, tag, r);
797 SRECT s_getCharBBox(char*name)
799 character_t* c = dictionary_lookup(&characters, name);
800 if(!c) syntaxerror("character '%s' unknown(2)", name);
803 SRECT s_getInstanceBBox(char*name)
805 instance_t * i = dictionary_lookup(&instances, name);
807 if(!i) syntaxerror("instance '%s' unknown(4)", name);
809 if(!c) syntaxerror("internal error(5)");
812 parameters_t s_getParameters(char*name)
814 instance_t * i = dictionary_lookup(&instances, name);
815 if(!i) syntaxerror("instance '%s' unknown(10)", name);
816 return i->parameters;
818 void s_startclip(char*instance, char*character, parameters_t p)
820 character_t* c = dictionary_lookup(&characters, character);
824 syntaxerror("character %s not known", character);
826 i = s_addinstance(instance, c, currentdepth);
828 m = s_instancepos(i, &p);
830 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
831 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
832 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
834 i->lastFrame= currentframe;
836 stack[stackpos].tag = tag;
837 stack[stackpos].type = 2;
846 swf_SetTagPos(stack[stackpos].tag, 0);
847 swf_GetPlaceObject(stack[stackpos].tag, &p);
848 p.clipdepth = currentdepth;
849 swf_ClearTag(stack[stackpos].tag);
850 swf_SetPlaceObject(stack[stackpos].tag, &p);
854 void s_put(char*instance, char*character, parameters_t p)
856 character_t* c = dictionary_lookup(&characters, character);
860 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
863 i = s_addinstance(instance, c, currentdepth);
865 m = s_instancepos(i, &p);
867 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
868 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
870 i->lastFrame = currentframe;
874 void s_jump(char*instance, parameters_t p)
876 instance_t* i = dictionary_lookup(&instances, instance);
879 syntaxerror("instance %s not known", instance);
883 m = s_instancepos(i, &p);
885 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
886 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
888 i->lastFrame = currentframe;
891 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
897 ratio = (float)pos/(float)num;
899 p.x = (p2->x-p1->x)*ratio + p1->x;
900 p.y = (p2->y-p1->y)*ratio + p1->y;
901 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
902 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
903 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
904 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
906 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
907 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
908 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
909 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
911 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
912 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
913 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
914 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
916 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
917 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
918 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
919 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
923 void s_change(char*instance, parameters_t p2)
925 instance_t* i = dictionary_lookup(&instances, instance);
929 int frame, allframes;
931 syntaxerror("instance %s not known", instance);
935 allframes = currentframe - i->lastFrame - 1;
937 warning(".change ignored. can only .put/.change an object once per frame.");
941 m = s_instancepos(i, &p2);
942 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
943 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
946 /* o.k., we got the start and end point set. Now iterate though all the
947 tags in between, inserting object changes after each new frame */
950 if(!t) syntaxerror("internal error(6)");
952 while(frame < allframes) {
953 if(t->id == ST_SHOWFRAME) {
958 p = s_interpolate(&p1, &p2, frame, allframes);
959 m = s_instancepos(i, &p); //needed?
960 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
961 i->lastFrame = currentframe;
962 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
964 if(frame == allframes)
969 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
973 void s_delinstance(char*instance)
975 instance_t* i = dictionary_lookup(&instances, instance);
977 syntaxerror("instance %s not known", instance);
979 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
980 swf_SetU16(tag, i->depth);
981 dictionary_del(&instances, instance);
984 void s_qchange(char*instance, parameters_t p)
991 syntaxerror(".end unexpected");
992 if(stack[stackpos-1].type == 0)
994 else if(stack[stackpos-1].type == 1)
996 else if(stack[stackpos-1].type == 2)
998 else syntaxerror("internal error 1");
1001 // ------------------------------------------------------------------------
1003 typedef int command_func_t(map_t*args);
1005 SRECT parseBox(char*str)
1008 float xmin, xmax, ymin, ymax;
1009 char*x = strchr(str, 'x');
1011 if(!strcmp(str, "autocrop")) {
1012 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1016 d1 = strchr(x+1, ':');
1018 d2 = strchr(d1+1, ':');
1020 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1024 else if(d1 && !d2) {
1025 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1031 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1036 r.xmin = (SCOORD)(xmin*20);
1037 r.ymin = (SCOORD)(ymin*20);
1038 r.xmax = (SCOORD)(xmax*20);
1039 r.ymax = (SCOORD)(ymax*20);
1042 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1045 float parseFloat(char*str)
1049 int parseInt(char*str)
1054 if(str[0]=='+' || str[0]=='-')
1058 if(str[t]<'0' || str[t]>'9')
1059 syntaxerror("Not an Integer: \"%s\"", str);
1062 int parseTwip(char*str)
1066 if(str[0]=='+' || str[0]=='-') {
1071 dot = strchr(str, '.');
1075 return sign*parseInt(str)*20;
1077 int l=strlen(++dot);
1079 for(s=str;s<dot-1;s++)
1080 if(*s<'0' || *s>'9')
1081 syntaxerror("Not a coordinate: \"%s\"", str);
1083 if(*s<'0' || *s>'9')
1084 syntaxerror("Not a coordinate: \"%s\"", str);
1086 if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) {
1087 warning("precision loss: %s converted to twip", str);
1092 return sign*atoi(str)*20;
1094 return sign*atoi(str)*20+atoi(dot)*2;
1096 return sign*atoi(str)*20+atoi(dot)/5;
1101 int isPoint(char*str)
1103 if(strchr(str, '('))
1109 SPOINT parsePoint(char*str)
1113 int l = strlen(str);
1114 char*comma = strchr(str, ',');
1115 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1116 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1117 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1118 p.x = parseTwip(tmp);
1119 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1120 p.y = parseTwip(tmp);
1124 int parseColor2(char*str, RGBA*color)
1126 int l = strlen(str);
1130 struct {unsigned char r,g,b;char*name;} colors[] =
1131 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1132 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1133 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1134 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1135 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1136 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1137 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1138 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1139 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1140 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1141 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1142 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1146 if(str[0]=='#' && (l==7 || l==9)) {
1147 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1149 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1151 color->r = r; color->g = g; color->b = b; color->a = a;
1154 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1155 if(!strcmp(str, colors[t].name)) {
1160 color->r = r; color->g = g; color->b = b; color->a = a;
1166 RGBA parseColor(char*str)
1169 if(!parseColor2(str, &c))
1170 syntaxerror("Expression '%s' is not a color", str);
1174 typedef struct _muladd {
1179 MULADD parseMulAdd(char*str)
1182 char* str2 = (char*)malloc(strlen(str)+5);
1189 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1190 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1191 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1192 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1193 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1194 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1195 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1196 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1197 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1198 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1200 syntaxerror("'%s' is not a valid color transform expression", str);
1202 m.add = (int)(add*256);
1203 m.mul = (int)(mul*256);
1208 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1210 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1211 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1213 if(a<-32768) a=-32768;
1214 if(a>32767) a=32767;
1215 if(m<-32768) m=-32768;
1216 if(m>32767) m=32767;
1222 float parsePercent(char*str)
1224 int l = strlen(str);
1228 return atoi(str)/100.0;
1230 syntaxerror("Expression '%s' is not a percentage", str);
1233 int isPercent(char*str)
1235 return str[strlen(str)-1]=='%';
1237 int parseNewSize(char*str, int size)
1240 return parsePercent(str)*size;
1242 return (int)(atof(str)*20);
1245 int isColor(char*str)
1248 return parseColor2(str, &c);
1251 static char* lu(map_t* args, char*name)
1253 char* value = map_lookup(args, name);
1255 map_dump(args, stdout, "");
1256 syntaxerror("internal error 2: value %s should be set", name);
1261 static int c_swf(map_t*args)
1263 char* name = lu(args, "name");
1264 char* compressstr = lu(args, "compress");
1265 SRECT bbox = parseBox(lu(args, "bbox"));
1266 int version = parseInt(lu(args, "version"));
1267 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1269 if(!strcmp(name, "!default!") || override_outputname)
1272 if(!strcmp(compressstr, "default"))
1273 compress = version==6;
1274 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1276 else if(!strcmp(compressstr, "no"))
1278 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1280 s_swf(name, bbox, version, fps, compress);
1283 int isRelative(char*str)
1285 return !strncmp(str, "<plus>", 6) ||
1286 !strncmp(str, "<minus>", 7);
1288 char* getOffset(char*str)
1290 if(!strncmp(str, "<plus>", 6))
1292 if(!strncmp(str, "<minus>", 7))
1294 syntaxerror("internal error (347)");
1297 int getSign(char*str)
1299 if(!strncmp(str, "<plus>", 6))
1301 if(!strncmp(str, "<minus>", 7))
1303 syntaxerror("internal error (348)");
1306 static dictionary_t points;
1307 static mem_t mpoints;
1308 int points_initialized = 0;
1310 SPOINT getPoint(SRECT r, char*name)
1313 if(!strcmp(name, "center")) {
1315 p.x = (r.xmin + r.xmax)/2;
1316 p.y = (r.ymin + r.ymax)/2;
1320 if(points_initialized)
1321 l = (int)dictionary_lookup(&points, name);
1323 syntaxerror("Invalid point: \"%s\".", name);
1326 return *(SPOINT*)&mpoints.buffer[l];
1328 static int c_gradient(map_t*args)
1332 static int c_point(map_t*args)
1334 char*name = lu(args, "name");
1338 if(!points_initialized) {
1339 dictionary_init(&points);
1341 points_initialized = 1;
1343 p.x = parseTwip(lu(args, "x"));
1344 p.y = parseTwip(lu(args, "y"));
1345 pos = mem_put(&mpoints, &p, sizeof(p));
1346 string_set(&s1, name);
1348 dictionary_put(&points, s1, (void*)pos);
1351 static int c_play(map_t*args)
1353 char*name = lu(args, "sound");
1354 char*loop = lu(args, "loop");
1355 char*nomultiple = lu(args, "nomultiple");
1357 if(!strcmp(nomultiple, "nomultiple"))
1360 nm = parseInt(nomultiple);
1362 s_playsound(name, parseInt(loop), nm, 0);
1366 static int c_stop(map_t*args)
1368 char*name = lu(args, "sound");
1369 s_playsound(name, 0,0,1);
1373 static int c_placement(map_t*args, int type)
1375 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1378 char* luminancestr = lu(args, "luminance");
1379 char* scalestr = lu(args, "scale");
1380 char* scalexstr = lu(args, "scalex");
1381 char* scaleystr = lu(args, "scaley");
1382 char* rotatestr = lu(args, "rotate");
1383 char* shearstr = lu(args, "shear");
1384 char* xstr="", *pivotstr="";
1385 char* ystr="", *anglestr="";
1386 char*above = lu(args, "above"); /*FIXME*/
1387 char*below = lu(args, "below");
1388 char* rstr = lu(args, "red");
1389 char* gstr = lu(args, "green");
1390 char* bstr = lu(args, "blue");
1391 char* astr = lu(args, "alpha");
1392 char* pinstr = lu(args, "pin");
1401 pivotstr = lu(args, "pivot");
1402 anglestr = lu(args, "angle");
1404 xstr = lu(args, "x");
1405 ystr = lu(args, "y");
1408 luminance = parseMulAdd(luminancestr);
1411 luminance.mul = 256;
1415 if(scalexstr[0]||scaleystr[0])
1416 syntaxerror("scalex/scaley and scale cannot both be set");
1417 scalexstr = scaleystr = scalestr;
1420 if(type == 0 || type == 4) {
1422 character = lu(args, "character");
1423 parameters_clear(&p);
1425 p = s_getParameters(instance);
1430 if(isRelative(xstr)) {
1431 if(type == 0 || type == 4)
1432 syntaxerror("relative x values not allowed for initial put or startclip");
1433 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
1435 p.x = parseTwip(xstr);
1439 if(isRelative(ystr)) {
1440 if(type == 0 || type == 4)
1441 syntaxerror("relative y values not allowed for initial put or startclip");
1442 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
1444 p.y = parseTwip(ystr);
1448 /* scale, scalex, scaley */
1450 oldbbox = s_getCharBBox(character);
1452 oldbbox = s_getInstanceBBox(instance);
1454 oldwidth = oldbbox.xmax - oldbbox.xmin;
1455 oldheight = oldbbox.ymax - oldbbox.ymin;
1457 if(oldwidth==0) p.scalex = 1.0;
1460 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
1464 if(oldheight==0) p.scaley = 1.0;
1467 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
1473 if(isRelative(rotatestr)) {
1474 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
1476 p.rotate = parseFloat(rotatestr);
1482 if(isRelative(shearstr)) {
1483 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
1485 p.shear = parseFloat(shearstr);
1490 if(isPoint(pivotstr))
1491 p.pivot = parsePoint(pivotstr);
1493 p.pivot = getPoint(oldbbox, pivotstr);
1497 p.pin = parsePoint(pinstr);
1499 p.pin = getPoint(oldbbox, pinstr);
1502 /* color transform */
1504 if(rstr[0] || luminancestr[0]) {
1507 r = parseMulAdd(rstr);
1509 r.add = p.cxform.r0;
1510 r.mul = p.cxform.r1;
1512 r = mergeMulAdd(r, luminance);
1513 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
1515 if(gstr[0] || luminancestr[0]) {
1518 g = parseMulAdd(gstr);
1520 g.add = p.cxform.g0;
1521 g.mul = p.cxform.g1;
1523 g = mergeMulAdd(g, luminance);
1524 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
1526 if(bstr[0] || luminancestr[0]) {
1529 b = parseMulAdd(bstr);
1531 b.add = p.cxform.b0;
1532 b.mul = p.cxform.b1;
1534 b = mergeMulAdd(b, luminance);
1535 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
1538 MULADD a = parseMulAdd(astr);
1539 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
1543 s_put(instance, character, p);
1545 s_change(instance, p);
1547 s_qchange(instance, p);
1549 s_jump(instance, p);
1551 s_startclip(instance, character, p);
1554 static int c_put(map_t*args)
1556 c_placement(args, 0);
1559 static int c_change(map_t*args)
1561 c_placement(args, 1);
1564 static int c_qchange(map_t*args)
1566 c_placement(args, 2);
1569 static int c_arcchange(map_t*args)
1571 c_placement(args, 2);
1574 static int c_jump(map_t*args)
1576 c_placement(args, 3);
1579 static int c_startclip(map_t*args)
1581 c_placement(args, 4);
1584 static int c_del(map_t*args)
1586 char*instance = lu(args, "name");
1587 s_delinstance(instance);
1590 static int c_end(map_t*args)
1595 static int c_sprite(map_t*args)
1597 char* name = lu(args, "name");
1601 static int c_frame(map_t*args)
1603 char*framestr = lu(args, "n");
1605 if(isRelative(framestr)) {
1606 frame = s_getframe();
1607 if(getSign(framestr)<0)
1608 syntaxerror("relative frame expressions must be positive");
1609 frame += parseInt(getOffset(framestr));
1612 frame = parseInt(framestr);
1613 if(s_getframe() >= frame
1614 && !(frame==0 && s_getframe()==frame)) // equality is o.k. for frame 0
1615 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
1620 static int c_primitive(map_t*args)
1622 char*name = lu(args, "name");
1623 char*command = lu(args, "commandname");
1624 int width=0, height=0, r=0;
1625 int linewidth = parseTwip(lu(args, "line"));
1626 char*colorstr = lu(args, "color");
1627 RGBA color = parseColor(colorstr);
1628 char*fillstr = lu(args, "fill");
1634 if(!strcmp(command, "circle"))
1636 else if(!strcmp(command, "textshape"))
1640 width = parseTwip(lu(args, "width"));
1641 height = parseTwip(lu(args, "height"));
1642 } else if (type==1) {
1643 r = parseTwip(lu(args, "r"));
1644 } else if (type==2) {
1645 text = lu(args, "text");
1646 font = lu(args, "font");
1649 if(!strcmp(fillstr, "fill"))
1651 if(!strcmp(fillstr, "none"))
1653 if(width<0 || height<0 || linewidth<0 || r<0)
1654 syntaxerror("values width, height, line, r must be positive");
1655 if(!dofill || isColor(fillstr)) {
1657 fill = parseColor(fillstr);
1659 /* FIXME - texture fill */
1660 fill.r = fill.g = 0;
1661 fill.b = fill.a = 255;
1662 warning("texture fill not supported yet. Filling with black.");
1664 if(type == 0) s_box(name, width, height, color, linewidth, fill, dofill);
1665 else if(type==1) s_circle(name, r, color, linewidth, fill, dofill);
1666 else if(type==2) s_textshape(name, font, text, color, linewidth, fill, dofill);
1670 static int c_shape(map_t*args)
1672 char*name = lu(args, "name");
1673 char*filename = lu(args, "filename");
1674 s_shape(name, filename);
1678 static int c_font(map_t*args)
1680 char*name = lu(args, "name");
1681 char*filename = lu(args, "filename");
1682 s_font(name, filename);
1686 static int c_sound(map_t*args)
1688 char*name = lu(args, "name");
1689 char*filename = lu(args, "filename");
1690 s_sound(name, filename);
1694 static int c_text(map_t*args)
1696 char*name = lu(args, "name");
1697 char*text = lu(args, "text");
1698 char*font = lu(args, "font");
1699 float size = parsePercent(lu(args, "size"));
1700 RGBA color = parseColor(lu(args, "color"));
1701 s_text(name, font, text, (int)(size*100), color);
1705 static int c_soundtrack(map_t*args)
1710 int fakechar(map_t*args)
1712 char*name = lu(args, "name");
1713 s_box(name, 0, 0, black, 20, black, 0);
1717 static int c_egon(map_t*args) {return fakechar(args);}
1718 static int c_button(map_t*args) {return fakechar(args);}
1719 static int c_edittext(map_t*args) {return fakechar(args);}
1721 static int c_morphshape(map_t*args) {return fakechar(args);}
1722 static int c_image(map_t*args) {return fakechar(args);}
1723 static int c_movie(map_t*args) {return fakechar(args);}
1725 static int c_buttonsounds(map_t*args) {return 0;}
1726 static int c_buttonput(map_t*args) {return 0;}
1727 static int c_texture(map_t*args) {return 0;}
1728 static int c_action(map_t*args) {return 0;}
1732 command_func_t* func;
1735 {{"swf", c_swf, "bbox=autocrop version=5 fps=50 name=!default! @compress=default"},
1736 {"frame", c_frame, "n=<plus>1"},
1738 // "import" type stuff
1739 {"shape", c_shape, "name filename"},
1740 {"morphshape", c_morphshape, "name start end"},
1741 {"jpeg", c_image, "name filename quality=80%"},
1742 {"png", c_image, "name filename"},
1743 {"movie", c_movie, "name filename"},
1744 {"sound", c_sound, "name filename"},
1745 {"font", c_font, "name filename"},
1746 {"soundtrack", c_soundtrack, "filename"},
1748 // generators of primitives
1750 {"point", c_point, "name x=0 y=0"},
1751 {"gradient", c_gradient, "name"},
1753 // character generators
1754 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
1755 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
1756 {"textshape", c_primitive, "name text font color=white line=1 @fill=none"},
1757 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
1758 {"button", c_button, "name shape over=*shape press=*shape area=*shape"},
1759 {"text", c_text, "name text font size=100% color=white"},
1760 {"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"},
1762 {"buttonsounds", c_buttonsounds, "name press=0 release=0 enter=0 leave=0"},
1765 {"play", c_play, "sound loop=0 @nomultiple=0"},
1766 {"stop", c_stop, "sound"},
1768 // object placement tags
1769 {"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="},
1770 {"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="},
1771 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1772 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1773 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1774 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1775 {"del", c_del, "name"},
1776 // virtual object placement
1777 {"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="},
1778 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
1780 // commands which start a block
1781 //startclip (see above)
1782 {"sprite", c_sprite, "name"},
1783 {"action", c_action, ""},
1789 static map_t parseArguments(char*command, char*pattern)
1805 string_set(&t1, "commandname");
1806 string_set(&t2, command);
1807 map_put(&result, t1, t2);
1809 if(!pattern || !*pattern)
1816 if(!strncmp("<i> ", x, 3)) {
1818 if(type == COMMAND || type == LABEL) {
1820 syntaxerror("character name expected");
1822 name[pos].str = "instance";
1824 value[pos].str = text;
1825 value[pos].len = strlen(text);
1829 if(type == ASSIGNMENT)
1832 name[pos].str = "character";
1834 value[pos].str = text;
1835 value[pos].len = strlen(text);
1843 isboolean[pos] = (x[0] =='@');
1856 name[pos].len = d-x;
1861 name[pos].len = e-x;
1862 value[pos].str = e+1;
1863 value[pos].len = d-e-1;
1871 /* for(t=0;t<len;t++) {
1872 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
1873 isboolean[t]?"(boolean)":"");
1878 if(type == LABEL || type == COMMAND) {
1883 // first, search for boolean arguments
1884 for(pos=0;pos<len;pos++)
1886 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
1888 if(type == ASSIGNMENT)
1890 value[pos].str = text;
1891 value[pos].len = strlen(text);
1892 /*printf("setting boolean parameter %s (to %s)\n",
1893 strdup_n(name[pos], namelen[pos]),
1894 strdup_n(value[pos], valuelen[pos]));*/
1899 // second, search for normal arguments
1901 for(pos=0;pos<len;pos++)
1903 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
1904 (type != ASSIGNMENT && !set[pos])) {
1906 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
1908 if(type == ASSIGNMENT)
1911 value[pos].str = text;
1912 value[pos].len = strlen(text);
1914 printf("setting parameter %s (to %s)\n",
1915 strdup_n(name[pos].str, name[pos].len),
1916 strdup_n(value[pos].str, value[pos].len));
1922 syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
1926 for(t=0;t<len;t++) {
1927 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
1930 for(t=0;t<len;t++) {
1931 if(value[t].str && value[t].str[0] == '*') {
1932 //relative default- take value from some other parameter
1934 for(s=0;s<len;s++) {
1935 if(value[s].len == value[t].len-1 &&
1936 !strncmp(&value[t].str[1], value[s].str, value[s].len))
1937 value[t].str = value[s].str;
1940 if(value[t].str == 0) {
1942 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
1946 /* ok, now construct the dictionary from the parameters */
1950 map_put(&result, name[t], value[t]);
1954 static void parseArgumentsForCommand(char*command)
1959 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
1960 if(!strcmp(arguments[t].command, command)) {
1961 args = parseArguments(command, arguments[t].arguments);
1966 syntaxerror("command %s not known", command);
1969 printf(".%s\n", command);fflush(stdout);
1970 map_dump(&args, stdout, "\t");fflush(stdout);
1973 (*arguments[nr].func)(&args);
1975 if(!strcmp(command, "button") ||
1976 !strcmp(command, "action")) {
1979 if(type == COMMAND) {
1980 if(!strcmp(text, "end"))
1994 int main (int argc,char ** argv)
1997 processargs(argc, argv);
1998 initLog(0,-1,0,0,-1,verbose);
2001 args_callback_usage(argv[0]);
2004 file = generateTokens(filename);
2006 printf("parser returned error.\n");
2013 while(!noMoreTokens()) {
2016 syntaxerror("command expected");
2017 parseArgumentsForCommand(text);