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, RGBA background)
342 SWF*swf = (SWF*)malloc(sizeof(SWF));
345 syntaxerror(".swf blocks can't be nested");
347 memset(swf, 0, sizeof(swf));
348 swf->fileVersion = version;
350 swf->frameRate = fps;
351 swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
352 swf->compressed = compress;
353 swf_SetRGB(tag,&background);
355 if(stackpos==sizeof(stack)/sizeof(stack[0]))
356 syntaxerror("too many levels of recursion");
358 dictionary_init(&characters);
359 dictionary_init(&instances);
360 dictionary_init(&fonts);
361 dictionary_init(&sounds);
363 memset(&stack[stackpos], 0, sizeof(stack[0]));
364 stack[stackpos].type = 0;
365 stack[stackpos].filename = strdup(name);
366 stack[stackpos].swf = swf;
367 stack[stackpos].oldframe = -1;
372 memset(¤trect, 0, sizeof(currentrect));
375 memset(idmap, 0, sizeof(idmap));
379 void s_sprite(char*name)
381 tag = swf_InsertTag(tag, ST_DEFINESPRITE);
382 swf_SetU16(tag, id); //id
383 swf_SetU16(tag, 0); //frames
385 memset(&stack[stackpos], 0, sizeof(stack[0]));
386 stack[stackpos].type = 1;
387 stack[stackpos].oldframe = currentframe;
388 stack[stackpos].olddepth = currentdepth;
389 stack[stackpos].oldrect = currentrect;
390 stack[stackpos].oldinstances = instances;
391 stack[stackpos].tag = tag;
392 stack[stackpos].id = id;
393 stack[stackpos].name = strdup(name);
395 /* FIXME: those four fields should be bundled together */
396 dictionary_init(&instances);
399 memset(¤trect, 0, sizeof(currentrect));
405 static void s_endSprite()
407 SRECT r = currentrect;
410 /* TODO: before clearing, prepend "<spritename>." to names and
411 copy into old instances dict */
412 dictionary_clear(&instances);
414 currentframe = stack[stackpos].oldframe;
415 currentrect = stack[stackpos].oldrect;
416 currentdepth = stack[stackpos].olddepth;
417 instances = stack[stackpos].oldinstances;
418 tag = swf_InsertTag(tag, ST_END);
420 tag = stack[stackpos].tag;
423 syntaxerror("internal error(7)");
425 s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
426 free(stack[stackpos].name);
429 static void s_endSWF()
436 swf = stack[stackpos].swf;
437 filename = stack[stackpos].filename;
439 tag = swf_InsertTag(tag, ST_SHOWFRAME);
440 tag = swf_InsertTag(tag, ST_END);
442 swf_OptimizeTagOrder(swf);
444 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin))
445 swf->movieSize = currentrect; /* "autocrop" */
447 if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
448 swf->movieSize.xmax += 20; /* 1 by 1 pixels */
449 swf->movieSize.ymax += 20;
452 fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
454 syntaxerror("couldn't create output file %s", filename);
457 {if(swf_WriteSWC(fi, swf)<0) syntaxerror("WriteSWC() failed.\n");}
459 {if(swf_WriteSWF(fi, swf)<0) syntaxerror("WriteSWF() failed.\n");}
463 dictionary_clear(&instances);
464 dictionary_clear(&characters);
465 dictionary_clear(&fonts);
466 dictionary_clear(&sounds);
475 if(stack[stackpos-1].type == 0)
476 syntaxerror("End of file encountered in .swf block");
477 if(stack[stackpos-1].type == 1)
478 syntaxerror("End of file encountered in .sprite block");
479 if(stack[stackpos-1].type == 2)
480 syntaxerror("End of file encountered in .clip block");
492 for(t=currentframe;t<nr;t++) {
493 tag = swf_InsertTag(tag, ST_SHOWFRAME);
498 RGBA black={r:0,g:0,b:0,a:0};
499 void s_box(char*name, int width, int height, RGBA color, int linewidth, RGBA fill, int dofill)
504 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
506 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
508 fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
510 r.xmin = -linewidth-linewidth/2;
511 r.ymin = -linewidth-linewidth/2;
512 r.xmax = width+linewidth+linewidth/2;
513 r.ymax = height+linewidth+linewidth/2;
515 swf_SetShapeHeader(tag,s);
516 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
517 swf_ShapeSetLine(tag,s,width,0);
518 swf_ShapeSetLine(tag,s,0,height);
519 swf_ShapeSetLine(tag,s,-width,0);
520 swf_ShapeSetLine(tag,s,0,-height);
521 swf_ShapeSetEnd(tag);
524 s_addcharacter(name, id, tag, r);
528 void s_circle(char*name, int r, RGBA color, int linewidth, RGBA fill, int dofill)
533 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
535 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
537 fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
539 rect.xmin = -linewidth-linewidth/2;
540 rect.ymin = -linewidth-linewidth/2;
541 rect.xmax = 2*r+linewidth+linewidth/2;
542 rect.ymax = 2*r+linewidth+linewidth/2;
544 swf_SetRect(tag,&rect);
545 swf_SetShapeHeader(tag,s);
546 swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
547 swf_ShapeSetCircle(tag, s, r,r,r,r);
548 swf_ShapeSetEnd(tag);
551 s_addcharacter(name, id, tag, rect);
555 void s_textshape(char*name, char*fontname, char*_text, RGBA color, int linewidth, RGBA fill, int dofill)
561 U8*text = (U8*)_text;
564 font = dictionary_lookup(&fonts, fontname);
566 syntaxerror("font \"%s\" not known!", fontname);
568 syntaxerror("textshapes must be filled", fontname);
570 if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
571 warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
572 s_box(name, 0, 0, black, 20, black, 0);
575 g = font->ascii2glyph[text[0]];
576 rect = font->layout->bounds[g];
579 ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
581 fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
583 tag = swf_InsertTag(tag, ST_DEFINESHAPE);
585 swf_SetRect(tag, &rect);
586 swf_SetShapeStyles(tag, s);
587 swf_SetSimpleShape(tag, font->glyph[g].shape);
590 s_addcharacter(name, id, tag, rect);
593 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
598 font = dictionary_lookup(&fonts, fontname);
600 syntaxerror("font \"%s\" not known!", fontname);
602 tag = swf_InsertTag(tag, ST_DEFINETEXT2);
604 if(!font->numchars) {
605 s_box(name, 0, 0, black, 20, black, 0);
608 r = swf_SetDefineText(tag, font, &color, text, size);
610 s_addcharacter(name, id, tag, r);
614 void dumpSWF(SWF*swf)
616 TAG* tag = swf->firstTag;
617 printf("vvvvvvvvvvvvvvvvvvvvv\n");
619 printf("%8d %s\n", tag->len, swf_TagGetName(tag));
622 printf("^^^^^^^^^^^^^^^^^^^^^\n");
625 void s_font(char*name, char*filename)
630 f = open(filename,O_RDONLY|O_BINARY);
632 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
633 font = (SWFFONT*)malloc(sizeof(SWFFONT));
634 memset(font, 0, sizeof(SWFFONT));
635 dictionary_put2(&fonts, name, font);
639 if (swf_ReadSWF(f,&swf)>=0) {
640 swf_FontExtract(&swf, 0x4e46, &font);
645 syntaxerror("File \"%s\" isn't a valid rfxswf font file", filename);
650 /* fix the layout. Only needed for old fonts */
652 for(t=0;t<font->numchars;t++) {
653 font->glyph[t].advance = 0;
656 swf_FontCreateLayout(font);
660 tag = swf_InsertTag(tag, ST_DEFINEFONT2);
661 swf_FontSetDefine2(tag, font);
664 if(dictionary_lookup(&fonts, name))
665 syntaxerror("font %s defined twice", name);
666 dictionary_put2(&fonts, name, font);
669 typedef struct _sound_t
675 void s_sound(char*name, char*filename)
677 struct WAV wav, wav2;
682 if(!readWAV(filename, &wav)) {
683 warning("Couldn't read wav file \"%s\"", filename);
687 convertWAV2mono(&wav, &wav2, 44100);
688 samples = (U16*)wav2.data;
689 numsamples = wav2.size/2;
693 tag = swf_InsertTag(tag, ST_DEFINESOUND);
694 swf_SetU16(tag, id); //id
695 swf_SetSoundDefine(tag, samples, numsamples);
697 sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
701 if(dictionary_lookup(&sounds, name))
702 syntaxerror("sound %s defined twice", name);
703 dictionary_put2(&sounds, name, sound);
711 void s_playsound(char*name, int loops, int nomultiple, int stop)
713 sound_t* sound = dictionary_lookup(&sounds, name);
716 syntaxerror("Don't know anything about sound \"%s\"", name);
718 tag = swf_InsertTag(tag, ST_STARTSOUND);
719 swf_SetU16(tag, sound->id); //id
720 memset(&info, 0, sizeof(info));
723 info.nomultiple = nomultiple;
724 swf_SetSoundInfo(tag, &info);
727 void s_shape(char*name, char*filename)
735 U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
736 f = open(filename,O_RDONLY);
738 warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
739 s_box(name, 0, 0, black, 20, black, 0);
742 if (swf_ReadSWF(f,&swf)<0) {
743 warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
744 s_box(name, 0, 0, black, 20, black, 0);
749 /* FIXME: The following sets the bounding Box for the character.
750 It is wrong for two reasons:
751 a) It may be too small (in case objects in the movie clip at the borders)
752 b) it may be too big (because the poor movie never got autocropped)
756 s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
760 swf_Relocate(&swf, idmap);
766 for(t=0;t<sizeof(cutout)/sizeof(cutout[0]);t++)
767 if(cutout[t] == ftag->id) {
771 if(ftag->id == ST_DEFINESPRITE && !swf_IsFolded(ftag))
773 if(ftag->id == ST_END)
777 /* We simply dump all tags right after the sprite
778 header, relying on the fact that swf_OptimizeTagOrder() will
779 sort things out for us later.
780 We also rely on the fact that the imported SWF is well-formed.
782 tag = swf_InsertTag(tag, ftag->id);
783 swf_SetBlock(tag, ftag->data, ftag->len);
787 syntaxerror("Included file %s contains errors", filename);
788 tag = swf_InsertTag(tag, ST_END);
792 s_addcharacter(name, id, tag, r);
795 SRECT s_getCharBBox(char*name)
797 character_t* c = dictionary_lookup(&characters, name);
798 if(!c) syntaxerror("character '%s' unknown(2)", name);
801 SRECT s_getInstanceBBox(char*name)
803 instance_t * i = dictionary_lookup(&instances, name);
805 if(!i) syntaxerror("instance '%s' unknown(4)", name);
807 if(!c) syntaxerror("internal error(5)");
810 parameters_t s_getParameters(char*name)
812 instance_t * i = dictionary_lookup(&instances, name);
813 if(!i) syntaxerror("instance '%s' unknown(10)", name);
814 return i->parameters;
816 void s_startclip(char*instance, char*character, parameters_t p)
818 character_t* c = dictionary_lookup(&characters, character);
822 syntaxerror("character %s not known", character);
824 i = s_addinstance(instance, c, currentdepth);
826 m = s_instancepos(i, &p);
828 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
829 /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
830 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
832 i->lastFrame= currentframe;
834 stack[stackpos].tag = tag;
835 stack[stackpos].type = 2;
844 swf_SetTagPos(stack[stackpos].tag, 0);
845 swf_GetPlaceObject(stack[stackpos].tag, &p);
846 p.clipdepth = currentdepth;
847 swf_ClearTag(stack[stackpos].tag);
848 swf_SetPlaceObject(stack[stackpos].tag, &p);
852 void s_put(char*instance, char*character, parameters_t p)
854 character_t* c = dictionary_lookup(&characters, character);
858 syntaxerror("character %s not known (in .put %s=%s)", character, instance, character);
861 i = s_addinstance(instance, c, currentdepth);
863 m = s_instancepos(i, &p);
865 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
866 swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
868 i->lastFrame = currentframe;
872 void s_jump(char*instance, parameters_t p)
874 instance_t* i = dictionary_lookup(&instances, instance);
877 syntaxerror("instance %s not known", instance);
881 m = s_instancepos(i, &p);
883 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
884 swf_ObjectMove(tag, i->depth, &m, &p.cxform);
886 i->lastFrame = currentframe;
889 parameters_t s_interpolate(parameters_t*p1, parameters_t*p2, int pos, int num)
895 ratio = (float)pos/(float)num;
897 p.x = (p2->x-p1->x)*ratio + p1->x;
898 p.y = (p2->y-p1->y)*ratio + p1->y;
899 p.scalex = (p2->scalex-p1->scalex)*ratio + p1->scalex;
900 p.scaley = (p2->scaley-p1->scaley)*ratio + p1->scaley;
901 p.rotate = (p2->rotate-p1->rotate)*ratio + p1->rotate;
902 p.shear = (p2->shear-p1->shear)*ratio + p1->shear;
904 p.cxform.r0 = ((float)p2->cxform.r0-(float)p1->cxform.r0)*ratio + p1->cxform.r0;
905 p.cxform.g0 = ((float)p2->cxform.g0-(float)p1->cxform.g0)*ratio + p1->cxform.g0;
906 p.cxform.b0 = ((float)p2->cxform.b0-(float)p1->cxform.b0)*ratio + p1->cxform.b0;
907 p.cxform.a0 = ((float)p2->cxform.a0-(float)p1->cxform.a0)*ratio + p1->cxform.a0;
909 p.cxform.r1 = (p2->cxform.r1-p1->cxform.r1)*ratio + p1->cxform.r1;
910 p.cxform.g1 = (p2->cxform.g1-p1->cxform.g1)*ratio + p1->cxform.g1;
911 p.cxform.b1 = (p2->cxform.b1-p1->cxform.b1)*ratio + p1->cxform.b1;
912 p.cxform.a1 = (p2->cxform.a1-p1->cxform.a1)*ratio + p1->cxform.a1;
914 p.pivot.x = (p2->pivot.x-p1->pivot.x)*ratio + p1->pivot.x;
915 p.pivot.y = (p2->pivot.y-p1->pivot.y)*ratio + p1->pivot.y;
916 p.pin.x = (p2->pin.x-p1->pin.x)*ratio + p1->pin.x;
917 p.pin.y = (p2->pin.y-p1->pin.y)*ratio + p1->pin.y;
921 void s_change(char*instance, parameters_t p2)
923 instance_t* i = dictionary_lookup(&instances, instance);
927 int frame, allframes;
929 syntaxerror("instance %s not known", instance);
933 allframes = currentframe - i->lastFrame - 1;
935 warning(".change ignored. can only .put/.change an object once per frame.");
939 m = s_instancepos(i, &p2);
940 tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
941 swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
944 /* o.k., we got the start and end point set. Now iterate though all the
945 tags in between, inserting object changes after each new frame */
948 if(!t) syntaxerror("internal error(6)");
950 while(frame < allframes) {
951 if(t->id == ST_SHOWFRAME) {
956 p = s_interpolate(&p1, &p2, frame, allframes);
957 m = s_instancepos(i, &p); //needed?
958 lt = swf_InsertTag(t, ST_PLACEOBJECT2);
959 i->lastFrame = currentframe;
960 swf_ObjectMove(lt, i->depth, &m, &p.cxform);
962 if(frame == allframes)
967 syntaxerror("internal error(8) (frame=%d/%d)", frame, allframes);
971 void s_delinstance(char*instance)
973 instance_t* i = dictionary_lookup(&instances, instance);
975 syntaxerror("instance %s not known", instance);
977 tag = swf_InsertTag(tag, ST_REMOVEOBJECT2);
978 swf_SetU16(tag, i->depth);
979 dictionary_del(&instances, instance);
982 void s_qchange(char*instance, parameters_t p)
989 syntaxerror(".end unexpected");
990 if(stack[stackpos-1].type == 0)
992 else if(stack[stackpos-1].type == 1)
994 else if(stack[stackpos-1].type == 2)
996 else syntaxerror("internal error 1");
999 // ------------------------------------------------------------------------
1001 typedef int command_func_t(map_t*args);
1003 SRECT parseBox(char*str)
1006 float xmin, xmax, ymin, ymax;
1007 char*x = strchr(str, 'x');
1009 if(!strcmp(str, "autocrop")) {
1010 r.xmin = r.ymin = r.xmax = r.ymax = 0;
1014 d1 = strchr(x+1, ':');
1016 d2 = strchr(d1+1, ':');
1018 if(sscanf(str, "%fx%f", &xmax, &ymax) < 2)
1022 else if(d1 && !d2) {
1023 if(sscanf(str, "%fx%f:%f", &xmax, &ymax, &xmin) < 3)
1029 if(sscanf(str, "%fx%f:%f:%f", &xmax, &ymax, &xmin, &ymin) < 4)
1034 r.xmin = (SCOORD)(xmin*20);
1035 r.ymin = (SCOORD)(ymin*20);
1036 r.xmax = (SCOORD)(xmax*20);
1037 r.ymax = (SCOORD)(ymax*20);
1040 syntaxerror("expression %s is not a valid bound Box.\nE.g. 1024x768 or 1024x768:30:30 would have been valid bounding Boxes.", str);
1043 float parseFloat(char*str)
1047 int parseInt(char*str)
1052 if(str[0]=='+' || str[0]=='-')
1056 if(str[t]<'0' || str[t]>'9')
1057 syntaxerror("Not an Integer: \"%s\"", str);
1060 int parseTwip(char*str)
1064 if(str[0]=='+' || str[0]=='-') {
1069 dot = strchr(str, '.');
1073 return sign*parseInt(str)*20;
1075 int l=strlen(++dot);
1077 for(s=str;s<dot-1;s++)
1078 if(*s<'0' || *s>'9')
1079 syntaxerror("Not a coordinate: \"%s\"", str);
1081 if(*s<'0' || *s>'9')
1082 syntaxerror("Not a coordinate: \"%s\"", str);
1084 if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) {
1085 warning("precision loss: %s converted to twip", str);
1090 return sign*atoi(str)*20;
1092 return sign*atoi(str)*20+atoi(dot)*2;
1094 return sign*atoi(str)*20+atoi(dot)/5;
1099 int isPoint(char*str)
1101 if(strchr(str, '('))
1107 SPOINT parsePoint(char*str)
1111 int l = strlen(str);
1112 char*comma = strchr(str, ',');
1113 if(str[0]!='(' || str[l-1]!=')' || !comma || l>70)
1114 syntaxerror("\"%s\" is not a valid point of the form (x,y)", str);
1115 strncpy(tmp, str+1, comma-(str+1));tmp[comma-(str+1)]=0;
1116 p.x = parseTwip(tmp);
1117 strncpy(tmp, comma+1, l-1-(comma+1-str));tmp[l-1-(comma+1-str)]=0;
1118 p.y = parseTwip(tmp);
1122 int parseColor2(char*str, RGBA*color)
1124 int l = strlen(str);
1128 struct {unsigned char r,g,b;char*name;} colors[] =
1129 {{255,250,250,"snow"},{220,220,220,"gainsboro"},{250,240,230,"linen"},{255,228,196,"bisque"},
1130 {255,228,181,"moccasin"},{255,248,220,"cornsilk"},{255,255,240,"ivory"},{255,245,238,"seashell"},
1131 {240,255,240,"honeydew"},{240,255,255,"azure"},{230,230,250,"lavender"},{255,255,255,"white"},
1132 {0,0,0,"black"},{190,190,190,"gray"},{190,190,190,"grey"},{0,0,128,"navy"},{0,0,255,"blue"},
1133 {64,224,208,"turquoise"},{0,255,255,"cyan"},{127,255,212,"aquamarine"}, {0,255,0,"green"},
1134 {127,255,0,"chartreuse"},{240,230,140,"khaki"},{255,255,0,"yellow"},
1135 {255,215,0,"gold"},{218,165,32,"goldenrod"},{160,82,45,"sienna"},{205,133,63,"peru"},
1136 {222,184,135,"burlywood"},{245,245,220,"beige"},{245,222,179,"wheat"},{210,180,140,"tan"},
1137 {210,105,30,"chocolate"},{178,34,34,"firebrick"},{165,42,42,"brown"},{250,128,114,"salmon"},
1138 {255,165,0,"orange"},{255,127,80,"coral"},{255,99,71,"tomato"},{255,0,0,"red"},
1139 {255,192,203,"pink"},{176,48,96,"maroon"},{255,0,255,"magenta"},{238,130,238,"violet"},
1140 {221,160,221,"plum"},{218,112,214,"orchid"},{160,32,240,"purple"},{216,191,216,"thistle"}};
1144 if(str[0]=='#' && (l==7 || l==9)) {
1145 if(l == 7 && !(sscanf(str, "#%02x%02x%02x", &r, &g, &b)))
1147 if(l == 9 && !(sscanf(str, "#%02x%02x%02x%02x", &r, &g, &b, &a)))
1149 color->r = r; color->g = g; color->b = b; color->a = a;
1152 for(t=0;t<sizeof(colors)/sizeof(colors[0]);t++)
1153 if(!strcmp(str, colors[t].name)) {
1158 color->r = r; color->g = g; color->b = b; color->a = a;
1164 RGBA parseColor(char*str)
1167 if(!parseColor2(str, &c))
1168 syntaxerror("Expression '%s' is not a color", str);
1172 typedef struct _muladd {
1177 MULADD parseMulAdd(char*str)
1180 char* str2 = (char*)malloc(strlen(str)+5);
1187 if(sscanf(str2, "%f%f %d", &mul, &add, &i)==2+1) { add/=256.0; i=1;}
1188 else if(sscanf(str2, "%f%%%f %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=256.0; i=2;}
1189 else if(sscanf(str2, "%f%f%% %d", &mul, &add, &i)==2+1) { add/=100.0; i=3;}
1190 else if(sscanf(str2, "%f%%%f%% %d", &mul, &add, &i)==2+1) { mul/=100.0; add/=100.0; i=4;}
1191 else if(sscanf(str2, "+%f%% %d", &add, &i)==1+1) { mul=1.0;add/=100.0; i=5;}
1192 else if(sscanf(str2, "+%f %d", &add, &i)==1+1) { mul=1.0;add/=256.0; i=6;}
1193 else if(sscanf(str2, "-%f%% %d", &add, &i)==1+1) { mul=1.0;add/=-100.0; i=7;}
1194 else if(sscanf(str2, "-%f %d", &add, &i)==1+1) { mul=1.0;add/=-256.0; i=8;}
1195 else if(sscanf(str2, "%f%% %d", &mul, &i)==1+1) { mul/=100.0;add=0; i=9;}
1196 else if(sscanf(str2, "%f %d", &mul, &i)==1+1) { add=0; i=10;}
1198 syntaxerror("'%s' is not a valid color transform expression", str);
1200 m.add = (int)(add*256);
1201 m.mul = (int)(mul*256);
1206 MULADD mergeMulAdd(MULADD m1, MULADD m2)
1208 int a = (int)((double)m2.add+((double)m1.add*(double)m2.mul)/256.0);
1209 double m = ((double)m1.mul*(double)m2.mul)/256.0;
1211 if(a<-32768) a=-32768;
1212 if(a>32767) a=32767;
1213 if(m<-32768) m=-32768;
1214 if(m>32767) m=32767;
1220 float parsePercent(char*str)
1222 int l = strlen(str);
1226 return atoi(str)/100.0;
1228 syntaxerror("Expression '%s' is not a percentage", str);
1231 int isPercent(char*str)
1233 return str[strlen(str)-1]=='%';
1235 int parseNewSize(char*str, int size)
1238 return parsePercent(str)*size;
1240 return (int)(atof(str)*20);
1243 int isColor(char*str)
1246 return parseColor2(str, &c);
1249 static char* lu(map_t* args, char*name)
1251 char* value = map_lookup(args, name);
1253 map_dump(args, stdout, "");
1254 syntaxerror("internal error 2: value %s should be set", name);
1259 static int c_swf(map_t*args)
1261 char* name = lu(args, "name");
1262 char* compressstr = lu(args, "compress");
1263 SRECT bbox = parseBox(lu(args, "bbox"));
1264 int version = parseInt(lu(args, "version"));
1265 int fps = (int)(parseFloat(lu(args, "fps"))*256);
1267 RGBA color = parseColor(lu(args, "background"));
1268 if(!strcmp(name, "!default!") || override_outputname)
1271 if(!strcmp(compressstr, "default"))
1272 compress = version==6;
1273 else if(!strcmp(compressstr, "yes") || !strcmp(compressstr, "compress"))
1275 else if(!strcmp(compressstr, "no"))
1277 else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
1279 s_swf(name, bbox, version, fps, compress, color);
1282 int isRelative(char*str)
1284 return !strncmp(str, "<plus>", 6) ||
1285 !strncmp(str, "<minus>", 7);
1287 char* getOffset(char*str)
1289 if(!strncmp(str, "<plus>", 6))
1291 if(!strncmp(str, "<minus>", 7))
1293 syntaxerror("internal error (347)");
1296 int getSign(char*str)
1298 if(!strncmp(str, "<plus>", 6))
1300 if(!strncmp(str, "<minus>", 7))
1302 syntaxerror("internal error (348)");
1305 static dictionary_t points;
1306 static mem_t mpoints;
1307 int points_initialized = 0;
1309 SPOINT getPoint(SRECT r, char*name)
1312 if(!strcmp(name, "center")) {
1314 p.x = (r.xmin + r.xmax)/2;
1315 p.y = (r.ymin + r.ymax)/2;
1319 if(points_initialized)
1320 l = (int)dictionary_lookup(&points, name);
1322 syntaxerror("Invalid point: \"%s\".", name);
1325 return *(SPOINT*)&mpoints.buffer[l];
1327 static int c_gradient(map_t*args)
1331 static int c_point(map_t*args)
1333 char*name = lu(args, "name");
1337 if(!points_initialized) {
1338 dictionary_init(&points);
1340 points_initialized = 1;
1342 p.x = parseTwip(lu(args, "x"));
1343 p.y = parseTwip(lu(args, "y"));
1344 pos = mem_put(&mpoints, &p, sizeof(p));
1345 string_set(&s1, name);
1347 dictionary_put(&points, s1, (void*)pos);
1350 static int c_play(map_t*args)
1352 char*name = lu(args, "sound");
1353 char*loop = lu(args, "loop");
1354 char*nomultiple = lu(args, "nomultiple");
1356 if(!strcmp(nomultiple, "nomultiple"))
1359 nm = parseInt(nomultiple);
1361 s_playsound(name, parseInt(loop), nm, 0);
1365 static int c_stop(map_t*args)
1367 char*name = lu(args, "sound");
1368 s_playsound(name, 0,0,1);
1372 static int c_placement(map_t*args, int type)
1374 char*instance = lu(args, (type==0||type==4)?"instance":"name");
1377 char* luminancestr = lu(args, "luminance");
1378 char* scalestr = lu(args, "scale");
1379 char* scalexstr = lu(args, "scalex");
1380 char* scaleystr = lu(args, "scaley");
1381 char* rotatestr = lu(args, "rotate");
1382 char* shearstr = lu(args, "shear");
1383 char* xstr="", *pivotstr="";
1384 char* ystr="", *anglestr="";
1385 char*above = lu(args, "above"); /*FIXME*/
1386 char*below = lu(args, "below");
1387 char* rstr = lu(args, "red");
1388 char* gstr = lu(args, "green");
1389 char* bstr = lu(args, "blue");
1390 char* astr = lu(args, "alpha");
1391 char* pinstr = lu(args, "pin");
1400 pivotstr = lu(args, "pivot");
1401 anglestr = lu(args, "angle");
1403 xstr = lu(args, "x");
1404 ystr = lu(args, "y");
1407 luminance = parseMulAdd(luminancestr);
1410 luminance.mul = 256;
1414 if(scalexstr[0]||scaleystr[0])
1415 syntaxerror("scalex/scaley and scale cannot both be set");
1416 scalexstr = scaleystr = scalestr;
1419 if(type == 0 || type == 4) {
1421 character = lu(args, "character");
1422 parameters_clear(&p);
1424 p = s_getParameters(instance);
1429 if(isRelative(xstr)) {
1430 if(type == 0 || type == 4)
1431 syntaxerror("relative x values not allowed for initial put or startclip");
1432 p.x += parseTwip(getOffset(xstr))*getSign(xstr);
1434 p.x = parseTwip(xstr);
1438 if(isRelative(ystr)) {
1439 if(type == 0 || type == 4)
1440 syntaxerror("relative y values not allowed for initial put or startclip");
1441 p.y += parseTwip(getOffset(ystr))*getSign(ystr);
1443 p.y = parseTwip(ystr);
1447 /* scale, scalex, scaley */
1449 oldbbox = s_getCharBBox(character);
1451 oldbbox = s_getInstanceBBox(instance);
1453 oldwidth = oldbbox.xmax - oldbbox.xmin;
1454 oldheight = oldbbox.ymax - oldbbox.ymin;
1456 if(oldwidth==0) p.scalex = 1.0;
1459 p.scalex = (float)(parseNewSize(scalexstr, oldwidth))/oldwidth;
1463 if(oldheight==0) p.scaley = 1.0;
1466 p.scaley = (float)(parseNewSize(scaleystr, oldheight))/oldheight;
1472 if(isRelative(rotatestr)) {
1473 p.rotate += parseFloat(getOffset(rotatestr))*getSign(rotatestr);
1475 p.rotate = parseFloat(rotatestr);
1481 if(isRelative(shearstr)) {
1482 p.shear += parseFloat(getOffset(shearstr))*getSign(shearstr);
1484 p.shear = parseFloat(shearstr);
1489 if(isPoint(pivotstr))
1490 p.pivot = parsePoint(pivotstr);
1492 p.pivot = getPoint(oldbbox, pivotstr);
1496 p.pin = parsePoint(pinstr);
1498 p.pin = getPoint(oldbbox, pinstr);
1501 /* color transform */
1503 if(rstr[0] || luminancestr[0]) {
1506 r = parseMulAdd(rstr);
1508 r.add = p.cxform.r0;
1509 r.mul = p.cxform.r1;
1511 r = mergeMulAdd(r, luminance);
1512 p.cxform.r0 = r.mul;p.cxform.r1 = r.add;
1514 if(gstr[0] || luminancestr[0]) {
1517 g = parseMulAdd(gstr);
1519 g.add = p.cxform.g0;
1520 g.mul = p.cxform.g1;
1522 g = mergeMulAdd(g, luminance);
1523 p.cxform.g0 = g.mul;p.cxform.g1 = g.add;
1525 if(bstr[0] || luminancestr[0]) {
1528 b = parseMulAdd(bstr);
1530 b.add = p.cxform.b0;
1531 b.mul = p.cxform.b1;
1533 b = mergeMulAdd(b, luminance);
1534 p.cxform.b0 = b.mul;p.cxform.b1 = b.add;
1537 MULADD a = parseMulAdd(astr);
1538 p.cxform.a0 = a.mul;p.cxform.a1 = a.add;
1542 s_put(instance, character, p);
1544 s_change(instance, p);
1546 s_qchange(instance, p);
1548 s_jump(instance, p);
1550 s_startclip(instance, character, p);
1553 static int c_put(map_t*args)
1555 c_placement(args, 0);
1558 static int c_change(map_t*args)
1560 c_placement(args, 1);
1563 static int c_qchange(map_t*args)
1565 c_placement(args, 2);
1568 static int c_arcchange(map_t*args)
1570 c_placement(args, 2);
1573 static int c_jump(map_t*args)
1575 c_placement(args, 3);
1578 static int c_startclip(map_t*args)
1580 c_placement(args, 4);
1583 static int c_del(map_t*args)
1585 char*instance = lu(args, "name");
1586 s_delinstance(instance);
1589 static int c_end(map_t*args)
1594 static int c_sprite(map_t*args)
1596 char* name = lu(args, "name");
1600 static int c_frame(map_t*args)
1602 char*framestr = lu(args, "n");
1604 if(isRelative(framestr)) {
1605 frame = s_getframe();
1606 if(getSign(framestr)<0)
1607 syntaxerror("relative frame expressions must be positive");
1608 frame += parseInt(getOffset(framestr));
1611 frame = parseInt(framestr);
1612 if(s_getframe() >= frame
1613 && !(frame==0 && s_getframe()==frame)) // equality is o.k. for frame 0
1614 syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
1619 static int c_primitive(map_t*args)
1621 char*name = lu(args, "name");
1622 char*command = lu(args, "commandname");
1623 int width=0, height=0, r=0;
1624 int linewidth = parseTwip(lu(args, "line"));
1625 char*colorstr = lu(args, "color");
1626 RGBA color = parseColor(colorstr);
1627 char*fillstr = lu(args, "fill");
1633 if(!strcmp(command, "circle"))
1635 else if(!strcmp(command, "textshape"))
1639 width = parseTwip(lu(args, "width"));
1640 height = parseTwip(lu(args, "height"));
1641 } else if (type==1) {
1642 r = parseTwip(lu(args, "r"));
1643 } else if (type==2) {
1644 text = lu(args, "text");
1645 font = lu(args, "font");
1648 if(!strcmp(fillstr, "fill"))
1650 if(!strcmp(fillstr, "none"))
1652 if(width<0 || height<0 || linewidth<0 || r<0)
1653 syntaxerror("values width, height, line, r must be positive");
1654 if(!dofill || isColor(fillstr)) {
1656 fill = parseColor(fillstr);
1658 /* FIXME - texture fill */
1659 fill.r = fill.g = 0;
1660 fill.b = fill.a = 255;
1661 warning("texture fill not supported yet. Filling with black.");
1663 if(type == 0) s_box(name, width, height, color, linewidth, fill, dofill);
1664 else if(type==1) s_circle(name, r, color, linewidth, fill, dofill);
1665 else if(type==2) s_textshape(name, font, text, color, linewidth, fill, dofill);
1669 static int c_shape(map_t*args)
1671 char*name = lu(args, "name");
1672 char*filename = lu(args, "filename");
1673 s_shape(name, filename);
1677 static int c_font(map_t*args)
1679 char*name = lu(args, "name");
1680 char*filename = lu(args, "filename");
1681 s_font(name, filename);
1685 static int c_sound(map_t*args)
1687 char*name = lu(args, "name");
1688 char*filename = lu(args, "filename");
1689 s_sound(name, filename);
1693 static int c_text(map_t*args)
1695 char*name = lu(args, "name");
1696 char*text = lu(args, "text");
1697 char*font = lu(args, "font");
1698 float size = parsePercent(lu(args, "size"));
1699 RGBA color = parseColor(lu(args, "color"));
1700 s_text(name, font, text, (int)(size*100), color);
1704 static int c_soundtrack(map_t*args)
1709 int fakechar(map_t*args)
1711 char*name = lu(args, "name");
1712 s_box(name, 0, 0, black, 20, black, 0);
1716 static int c_egon(map_t*args) {return fakechar(args);}
1717 static int c_button(map_t*args) {return fakechar(args);}
1718 static int c_edittext(map_t*args) {return fakechar(args);}
1720 static int c_morphshape(map_t*args) {return fakechar(args);}
1721 static int c_image(map_t*args) {return fakechar(args);}
1722 static int c_movie(map_t*args) {return fakechar(args);}
1724 static int c_buttonsounds(map_t*args) {return 0;}
1725 static int c_buttonput(map_t*args) {return 0;}
1726 static int c_texture(map_t*args) {return 0;}
1727 static int c_action(map_t*args) {return 0;}
1731 command_func_t* func;
1734 {{"swf", c_swf, "bbox=autocrop background=black version=5 fps=50 name=!default! @compress=default"},
1735 {"frame", c_frame, "n=<plus>1"},
1737 // "import" type stuff
1738 {"shape", c_shape, "name filename"},
1739 {"morphshape", c_morphshape, "name start end"},
1740 {"jpeg", c_image, "name filename quality=80%"},
1741 {"png", c_image, "name filename"},
1742 {"movie", c_movie, "name filename"},
1743 {"sound", c_sound, "name filename"},
1744 {"font", c_font, "name filename"},
1745 {"soundtrack", c_soundtrack, "filename"},
1747 // generators of primitives
1749 {"point", c_point, "name x=0 y=0"},
1750 {"gradient", c_gradient, "name"},
1752 // character generators
1753 {"box", c_primitive, "name width height color=white line=1 @fill=none"},
1754 {"circle", c_primitive, "name r color=white line=1 @fill=none"},
1755 {"textshape", c_primitive, "name text font color=white line=1 @fill=none"},
1756 {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
1757 {"button", c_button, "name shape over=*shape press=*shape area=*shape"},
1758 {"text", c_text, "name text font size=100% color=white"},
1759 {"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"},
1761 {"buttonsounds", c_buttonsounds, "name press=0 release=0 enter=0 leave=0"},
1764 {"play", c_play, "sound loop=0 @nomultiple=0"},
1765 {"stop", c_stop, "sound"},
1767 // object placement tags
1768 {"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="},
1769 {"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="},
1770 {"change", c_change, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1771 {"arcchange", c_arcchange, "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1772 {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1773 {"jump", c_jump, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
1774 {"del", c_del, "name"},
1775 // virtual object placement
1776 {"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="},
1777 {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
1779 // commands which start a block
1780 //startclip (see above)
1781 {"sprite", c_sprite, "name"},
1782 {"action", c_action, ""},
1788 static map_t parseArguments(char*command, char*pattern)
1804 string_set(&t1, "commandname");
1805 string_set(&t2, command);
1806 map_put(&result, t1, t2);
1808 if(!pattern || !*pattern)
1815 if(!strncmp("<i> ", x, 3)) {
1817 if(type == COMMAND || type == LABEL) {
1819 syntaxerror("character name expected");
1821 name[pos].str = "instance";
1823 value[pos].str = text;
1824 value[pos].len = strlen(text);
1828 if(type == ASSIGNMENT)
1831 name[pos].str = "character";
1833 value[pos].str = text;
1834 value[pos].len = strlen(text);
1842 isboolean[pos] = (x[0] =='@');
1855 name[pos].len = d-x;
1860 name[pos].len = e-x;
1861 value[pos].str = e+1;
1862 value[pos].len = d-e-1;
1870 /* for(t=0;t<len;t++) {
1871 printf("(%d) %s=%s %s\n", t, strdup_n(name[t], namelen[t]), strdup_n(value[t], valuelen[t]),
1872 isboolean[t]?"(boolean)":"");
1877 if(type == LABEL || type == COMMAND) {
1882 // first, search for boolean arguments
1883 for(pos=0;pos<len;pos++)
1885 if(!set[pos] && isboolean[pos] && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) {
1887 if(type == ASSIGNMENT)
1889 value[pos].str = text;
1890 value[pos].len = strlen(text);
1891 /*printf("setting boolean parameter %s (to %s)\n",
1892 strdup_n(name[pos], namelen[pos]),
1893 strdup_n(value[pos], valuelen[pos]));*/
1898 // second, search for normal arguments
1900 for(pos=0;pos<len;pos++)
1902 if((type == ASSIGNMENT && !strncmp(name[pos].str, text, name[pos].len>textlen?name[pos].len:textlen)) ||
1903 (type != ASSIGNMENT && !set[pos])) {
1905 syntaxerror("value %s set twice (old value:%s)", text, strdup_n(value[pos].str, value[pos].len));
1907 if(type == ASSIGNMENT)
1910 value[pos].str = text;
1911 value[pos].len = strlen(text);
1913 printf("setting parameter %s (to %s)\n",
1914 strdup_n(name[pos].str, name[pos].len),
1915 strdup_n(value[pos].str, value[pos].len));
1921 syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
1925 for(t=0;t<len;t++) {
1926 printf("%s=%s\n", strdup_n(name[t].str, name[t].len), strdup_n(value[t].str, value[t].len));
1929 for(t=0;t<len;t++) {
1930 if(value[t].str && value[t].str[0] == '*') {
1931 //relative default- take value from some other parameter
1933 for(s=0;s<len;s++) {
1934 if(value[s].len == value[t].len-1 &&
1935 !strncmp(&value[t].str[1], value[s].str, value[s].len))
1936 value[t].str = value[s].str;
1939 if(value[t].str == 0) {
1941 syntaxerror("value for parameter %s missing (no default)", strdup_n(name[t].str, name[t].len));
1945 /* ok, now construct the dictionary from the parameters */
1949 map_put(&result, name[t], value[t]);
1953 static void parseArgumentsForCommand(char*command)
1958 for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
1959 if(!strcmp(arguments[t].command, command)) {
1960 args = parseArguments(command, arguments[t].arguments);
1965 syntaxerror("command %s not known", command);
1968 printf(".%s\n", command);fflush(stdout);
1969 map_dump(&args, stdout, "\t");fflush(stdout);
1972 (*arguments[nr].func)(&args);
1974 if(!strcmp(command, "button") ||
1975 !strcmp(command, "action")) {
1978 if(type == COMMAND) {
1979 if(!strcmp(text, "end"))
1993 int main (int argc,char ** argv)
1996 processargs(argc, argv);
1997 initLog(0,-1,0,0,-1,verbose);
2000 args_callback_usage(argv[0]);
2003 file = generateTokens(filename);
2005 printf("parser returned error.\n");
2012 while(!noMoreTokens()) {
2015 syntaxerror("command expected");
2016 parseArgumentsForCommand(text);