implemented .texture and enhanced gradients.
[swftools.git] / src / swfc.c
index f57a98e..3bf8a73 100644 (file)
@@ -28,6 +28,7 @@
 #include <math.h>
 #include "../config.h"
 #include "../lib/rfxswf.h"
+#include "../lib/drawer.h"
 #include "../lib/log.h"
 #include "../lib/args.h"
 #include "../lib/q.h"
 static char * filename = 0;
 static char * outputname = "output.swf";
 static int verbose = 2;
+static int optimize = 0;
 static int override_outputname = 0;
 
-static struct options_t options[] =
-{
- {"o","output"},
- {"v","verbose"},
- {"V","version"},
- {0,0}
+static struct options_t options[] = {
+{"h", "help"},
+{"V", "version"},
+{"v", "verbose"},
+{"o", "output"},
+{"O", "optimize"},
+{0,0}
 };
     
 int args_callback_option(char*name,char*val)
@@ -60,6 +63,10 @@ int args_callback_option(char*name,char*val)
        override_outputname = 1;
        return 1;
     }
+    else if(!strcmp(name, "O")) {
+       optimize = 1;
+       return 0;
+    }
     else if(!strcmp(name, "v")) {
        verbose ++;
        return 0;
@@ -74,12 +81,16 @@ int args_callback_longoption(char*name,char*val)
 {
     return args_long2shortoption(options, name, val);
 }
-void args_callback_usage(char*name)
+void args_callback_usage(char *name)
 {
-    printf("Usage: %s [-o filename] file.wav\n", name);
-    printf("\t-v , --verbose\t\t\t Be more verbose\n");
-    printf("\t-o , --output filename\t\t set output filename (default: output.swf)\n");
-    printf("\t-V , --version\t\t\t Print program version and exit\n");
+    printf("\n");
+    printf("Usage: %s [-o file.swf] file.sc\n", name);
+    printf("\n");
+    printf("-h , --help                    Print short help message and exit\n");
+    printf("-V , --version                 Print version info and exit\n");
+    printf("-v , --verbose                 Increase verbosity. \n");
+    printf("-o , --output <filename>       Set output file to <filename>.\n");
+    printf("\n");
 }
 int args_callback_command(char*name,char*val)
 {
@@ -120,7 +131,7 @@ static void warning(char*format, ...)
     va_end(arglist);
     printf("\"%s\", line %d column %d: warning- %s\n", filename, line, column, buf);
 }
-   
+
 static void readToken()
 {
     type = file[pos].type;
@@ -160,7 +171,7 @@ static int noMoreTokens()
 struct _character;
 static struct level
 {
-   int type; //0=swf, 1=sprite, 2=clip
+   int type; //0=swf, 1=sprite, 2=clip, 3=button
 
    /* for swf (0): */
    SWF*swf;
@@ -174,11 +185,16 @@ static struct level
    int oldframe;
    dictionary_t oldinstances;
    SRECT oldrect;
+   TAG* cut;
 
 } stack[256];
 static int stackpos = 0;
 
 static dictionary_t characters;
+static dictionary_t images;
+static dictionary_t textures;
+static dictionary_t outlines;
+static dictionary_t gradients;
 static char idmap[65536];
 static TAG*tag = 0; //current tag
 
@@ -214,6 +230,21 @@ typedef struct _instance {
     U16 lastFrame; //frame lastTag is in
 } instance_t;
 
+typedef struct _outline {
+    SHAPE* shape;
+    SRECT bbox;
+} outline_t;
+
+typedef struct _gradient {
+    GRADIENT gradient;
+    char radial;
+    int rotate;
+} gradient_t;
+
+typedef struct _texture {
+    FILLSTYLE fs;
+} texture_t;
+
 static void character_init(character_t*c)
 {
     memset(c, 0, sizeof(character_t));
@@ -265,6 +296,17 @@ static void s_addcharacter(char*name, U16 id, TAG*ctag, SRECT r)
     swf_SetU16(tag, id);
     swf_SetString(tag, name);
 }
+static void s_addimage(char*name, U16 id, TAG*ctag, SRECT r)
+{
+    character_t* c = character_new();
+    c->definingTag = ctag;
+    c->id = id;
+    c->size = r;
+
+    if(dictionary_lookup(&images, name))
+       syntaxerror("image %s defined twice", name);
+    dictionary_put2(&images, name, c);
+}
 static instance_t* s_addinstance(char*name, character_t*c, U16 depth)
 {
     instance_t* i = instance_new();
@@ -290,7 +332,8 @@ static void parameters_clear(parameters_t*p)
 {
     p->x = 0; p->y = 0; 
     p->scalex = 1.0; p->scaley = 1.0;
-    p->pin.x = 1; p->pin.y = 0;
+    p->pin.x = 0;  //1??
+    p->pin.y = 0;
     p->pivot.x = 0; p->pivot.y = 0;
     p->rotate = 0; 
     p->shear = 0; 
@@ -317,18 +360,18 @@ static void makeMatrix(MATRIX*m, parameters_t*p)
     m->sy = (int)(sy*65536+0.5);
 
     m->tx = m->ty = 0;
-
+   
     h = swf_TurnPoint(p->pin, m);
     m->tx = p->x - h.x;
     m->ty = p->y - h.y;
 }
 
-static MATRIX s_instancepos(instance_t*i, parameters_t*p)
+static MATRIX s_instancepos(SRECT rect, parameters_t*p)
 {
     MATRIX m;
     SRECT r;
     makeMatrix(&m, p);
-    r = swf_TurnRect(i->character->size, &m);
+    r = swf_TurnRect(rect, &m);
     if(currentrect.xmin == 0 && currentrect.ymin == 0 && 
        currentrect.xmax == 0 && currentrect.ymax == 0)
        currentrect = r;
@@ -351,11 +394,15 @@ void s_swf(char*name, SRECT r, int version, int fps, int compress, RGBA backgrou
     swf->firstTag = tag = swf_InsertTag(0, ST_SETBACKGROUNDCOLOR);
     swf->compressed = compress;
     swf_SetRGB(tag,&background);
-    
+
     if(stackpos==sizeof(stack)/sizeof(stack[0]))
        syntaxerror("too many levels of recursion");
     
     dictionary_init(&characters);
+    dictionary_init(&images);
+    dictionary_init(&textures);
+    dictionary_init(&outlines);
+    dictionary_init(&gradients);
     dictionary_init(&instances);
     dictionary_init(&fonts);
     dictionary_init(&sounds);
@@ -402,9 +449,170 @@ void s_sprite(char*name)
     incrementid();
 }
 
+typedef struct _buttonrecord
+{
+    U16 id;
+    MATRIX matrix;
+    CXFORM cxform;
+    char set;
+} buttonrecord_t;
+
+typedef struct _button
+{
+    int endofshapes;
+    int nr_actions;
+    buttonrecord_t records[4];
+} button_t;
+
+static button_t mybutton;
+
+void s_button(char*name)
+{
+    tag = swf_InsertTag(tag, ST_DEFINEBUTTON2);
+    swf_SetU16(tag, id); //id
+    swf_ButtonSetFlags(tag, 0); //menu=no
+
+    memset(&mybutton, 0, sizeof(mybutton));
+
+    memset(&stack[stackpos], 0, sizeof(stack[0]));
+    stack[stackpos].type = 3;
+    stack[stackpos].tag = tag;
+    stack[stackpos].id = id;
+    stack[stackpos].name = strdup(name);
+    stack[stackpos].oldrect = currentrect;
+    memset(&currentrect, 0, sizeof(currentrect));
+
+    stackpos++;
+    incrementid();
+}
+void s_buttonput(char*character, char*as, parameters_t p)
+{
+    character_t* c = dictionary_lookup(&characters, character);
+    MATRIX m;
+    int flags = 0;
+    char*o = as,*s = as;
+    buttonrecord_t r;
+    if(!stackpos || (stack[stackpos-1].type != 3))  {
+       syntaxerror(".show may only appear in .button");
+    }
+    if(!c) {
+       syntaxerror("character %s not known (in .shape %s)", character, character);
+    }
+    if(mybutton.endofshapes) {
+       syntaxerror("a .do may not precede a .show", character, character);
+    }
+   
+    m = s_instancepos(c->size, &p);
+
+    r.id = c->id;
+    r.matrix = m;
+    r.cxform = p.cxform;
+    r.set = 1;
+
+    while(1) {
+       if(*s==',' || *s==0) {
+           if(!strncmp(o,"idle",s-o)) {mybutton.records[0]=r;o=s+1;}
+           else if(!strncmp(o,"shape",s-o)) {mybutton.records[0]=r;o=s+1;}
+           else if(!strncmp(o,"hover",s-o)) {mybutton.records[1]=r;o=s+1;}
+           else if(!strncmp(o,"pressed",s-o)) {mybutton.records[2]=r;o=s+1;}
+           else if(!strncmp(o,"area",s-o)) {mybutton.records[3]=r;o=s+1;}
+           else syntaxerror("unknown \"as\" argument: \"%s\"", strdup_n(o,s-o));
+       }
+       if(!*s)
+           break;
+       s++;
+    }
+}
+static void setbuttonrecords(TAG*tag)
+{
+    int flags[] = {BS_UP,BS_OVER,BS_DOWN,BS_HIT};
+    if(!mybutton.endofshapes) {
+       int t;
+               
+       if(!mybutton.records[3].set) {
+           memcpy(&mybutton.records[3], &mybutton.records[0], sizeof(buttonrecord_t));
+       }
+
+       for(t=0;t<4;t++) {
+           if(mybutton.records[t].set) {
+               swf_ButtonSetRecord(tag,flags[t],mybutton.records[t].id,1,&mybutton.records[t].matrix,&mybutton.records[t].cxform);
+           }
+       }
+       swf_SetU8(tag,0); // end of button records
+       mybutton.endofshapes = 1;
+    }
+}
+
+void s_buttonaction(int flags, char*action)
+{
+    ActionTAG* a = 0;
+    if(flags==0) {
+       return;
+    }
+    setbuttonrecords(stack[stackpos-1].tag);
+    
+    a = swf_ActionCompile(text, stack[0].swf->fileVersion);
+    if(!a) {
+       syntaxerror("Couldn't compile ActionScript");
+    }
+
+    swf_ButtonSetCondition(stack[stackpos-1].tag, flags);
+    swf_ActionSet(stack[stackpos-1].tag, a);
+    mybutton.nr_actions++;
+
+    swf_ActionFree(a);
+}
+
+static void setactionend(TAG*tag)
+{
+    if(!mybutton.nr_actions) {
+       /* no actions means we didn't have an actionoffset,
+          which means we can't signal the end of the
+          buttonaction records, so, *sigh*, we have
+          to insert a dummy record */
+       swf_SetU16(tag, 0); //offset
+       swf_SetU16(tag, 0); //condition
+       swf_SetU8(tag, 0); //action
+    }
+}
+
+static void s_endButton()
+{
+    SRECT r;
+    setbuttonrecords(stack[stackpos-1].tag);
+    setactionend(stack[stackpos-1].tag);
+    stackpos--;
+      
+    swf_ButtonPostProcess(stack[stackpos].tag, mybutton.nr_actions);
+
+    r = currentrect;
+
+    tag = stack[stackpos].tag;
+    currentrect = stack[stackpos].oldrect;
+
+    s_addcharacter(stack[stackpos].name, stack[stackpos].id, stack[stackpos].tag, r);
+    free(stack[stackpos].name);
+}
+
+TAG* removeFromTo(TAG*from, TAG*to)
+{
+    TAG*save = from->prev;
+    while(from!=to) {
+       TAG*next = from->next;
+       swf_DeleteTag(from);
+       from = next;
+    }
+    save->next = 0;
+    return save;
+}
+
 static void s_endSprite()
 {
     SRECT r = currentrect;
+    
+    if(stack[stackpos].cut)
+       tag = removeFromTo(stack[stackpos].cut, tag);
+
     stackpos--;
    
     /* TODO: before clearing, prepend "<spritename>." to names and
@@ -415,6 +623,8 @@ static void s_endSprite()
     currentrect = stack[stackpos].oldrect;
     currentdepth = stack[stackpos].olddepth;
     instances = stack[stackpos].oldinstances;
+
+    tag = swf_InsertTag(tag, ST_SHOWFRAME);
     tag = swf_InsertTag(tag, ST_END);
 
     tag = stack[stackpos].tag;
@@ -431,24 +641,37 @@ static void s_endSWF()
     int fi;
     SWF* swf;
     char*filename;
-    stackpos--;
+    
+    if(stack[stackpos].cut)
+       tag = removeFromTo(stack[stackpos].cut, tag);
 
+    stackpos--;
+   
     swf = stack[stackpos].swf;
     filename = stack[stackpos].filename;
-    
+  
+    //if(tag->prev && tag->prev->id != ST_SHOWFRAME)
+    //    tag = swf_InsertTag(tag, ST_SHOWFRAME);
     tag = swf_InsertTag(tag, ST_SHOWFRAME);
+
     tag = swf_InsertTag(tag, ST_END);
 
     swf_OptimizeTagOrder(swf);
-
-    if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin))
+   
+    if(optimize) {
+       swf_Optimize(swf);
+    }
+    
+    if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
        swf->movieSize = currentrect; /* "autocrop" */
+    }
     
     if(!(swf->movieSize.xmax-swf->movieSize.xmin) || !(swf->movieSize.ymax-swf->movieSize.ymin)) {
        swf->movieSize.xmax += 20; /* 1 by 1 pixels */
        swf->movieSize.ymax += 20;
+       warning("Empty bounding box for movie");
     }
-
+    
     fi = open(filename, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644);
     if(fi<0) {
        syntaxerror("couldn't create output file %s", filename);
@@ -462,6 +685,10 @@ static void s_endSWF()
     
     dictionary_clear(&instances);
     dictionary_clear(&characters);
+    dictionary_clear(&images);
+    dictionary_clear(&textures);
+    dictionary_clear(&outlines);
+    dictionary_clear(&gradients);
     dictionary_clear(&fonts);
     dictionary_clear(&sounds);
 
@@ -469,11 +696,12 @@ static void s_endSWF()
     free(swf);
     free(filename);
 }
+
 void s_close()
 {
     if(stackpos) {
        if(stack[stackpos-1].type == 0)
-           syntaxerror("End of file encountered in .swf block");
+           syntaxerror("End of file encountered in .flash block");
        if(stack[stackpos-1].type == 1)
            syntaxerror("End of file encountered in .sprite block");
        if(stack[stackpos-1].type == 2)
@@ -483,34 +711,111 @@ void s_close()
 
 int s_getframe()
 {
-    return currentframe;
+    return currentframe+1;
 }
 
-void s_frame(int nr)
+void s_frame(int nr, int cut, char*name)
 {
     int t;
+    TAG*now = tag;
+
+    if(nr<1) 
+       syntaxerror("Illegal frame number");
+    nr--; // internally, frame 1 is frame 0
+
     for(t=currentframe;t<nr;t++) {
        tag = swf_InsertTag(tag, ST_SHOWFRAME);
+       if(t==nr-1 && name && *name) {
+           tag = swf_InsertTag(tag, ST_FRAMELABEL);
+           swf_SetString(tag, name);
+       }
+    }
+    if(nr == 0 && currentframe == 0 && name) {
+        tag = swf_InsertTag(tag, ST_FRAMELABEL);
+        swf_SetString(tag, name);
     }
+
+    if(cut) {
+       if(now == tag) {
+           syntaxerror("Can't cut, frame empty");
+       }
+       stack[stackpos].cut = tag;
+    }
+
     currentframe = nr;
 }
+
+int parseColor2(char*str, RGBA*color);
+
+int addFillStyle(SHAPE*s, SRECT*r, char*name)
+{
+    RGBA color;
+    character_t*image;
+    gradient_t*gradient;
+    texture_t*texture;
+    if(name[0] == '#') {
+       parseColor2(name, &color);
+       return swf_ShapeAddSolidFillStyle(s, &color);
+    } else if ((texture = dictionary_lookup(&textures, name))) {
+       return swf_ShapeAddFillStyle2(s, &texture->fs);
+    } else if((image = dictionary_lookup(&images, name))) {
+       MATRIX m;
+       swf_GetMatrix(0, &m);
+       m.sx = 65536.0*20.0*(r->xmax - r->xmin)/image->size.xmax;
+       m.sy = 65536.0*20.0*(r->ymax - r->ymin)/image->size.ymax;
+       m.tx = r->xmin;
+       m.ty = r->ymin;
+       return swf_ShapeAddBitmapFillStyle(s, &m, image->id, 0);
+    }  else if ((gradient = dictionary_lookup(&gradients, name))) {
+       SRECT r2;
+       MATRIX rot,m;
+       double ccos,csin;
+       swf_GetMatrix(0, &rot);
+       ccos = cos(-gradient->rotate*2*3.14159265358979/360);
+       csin = sin(-gradient->rotate*2*3.14159265358979/360);
+       rot.sx =  ccos*65536;
+       rot.r1 = -csin*65536;
+       rot.r0 =  csin*65536;
+       rot.sy =  ccos*65536;
+       r2 = swf_TurnRect(*r, &rot);
+       swf_GetMatrix(0, &m);
+       m.sx =  (r2.xmax - r2.xmin)*2*ccos;
+       m.r1 = -(r2.xmax - r2.xmin)*2*csin;
+       m.r0 =  (r2.ymax - r2.ymin)*2*csin;
+       m.sy =  (r2.ymax - r2.ymin)*2*ccos;
+       m.tx = r->xmin + (r->xmax - r->xmin)/2;
+       m.ty = r->ymin + (r->ymax - r->ymin)/2;
+       return swf_ShapeAddGradientFillStyle(s, &m, &gradient->gradient, gradient->radial);
+    }  else if (parseColor2(name, &color)) {
+       return swf_ShapeAddSolidFillStyle(s, &color);
+    } else {
+       syntaxerror("not a color/fillstyle: %s", name);
+       return 0;
+    }
+}
        
 RGBA black={r:0,g:0,b:0,a:0};
-void s_box(char*name, int width, int height, RGBA color, int linewidth, RGBA fill, int dofill)
+void s_box(char*name, int width, int height, RGBA color, int linewidth, char*texture)
 {
-    SRECT r;
+    SRECT r,r2;
     SHAPE* s;
-    int ls1,fs1=0;
-    tag = swf_InsertTag(tag, ST_DEFINESHAPE);
+    int ls1=0,fs1=0;
+    r2.xmin = 0;
+    r2.ymin = 0;
+    r2.xmax = width;
+    r2.ymax = height;
+    tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
     swf_ShapeNew(&s);
-    ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
-    if(dofill)
-       fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
+    if(linewidth)
+        ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
+    if(texture)
+       fs1 = addFillStyle(s, &r2, texture);
+
     swf_SetU16(tag,id);
-    r.xmin = -linewidth-linewidth/2;
-    r.ymin = -linewidth-linewidth/2;
-    r.xmax = width+linewidth+linewidth/2;
-    r.ymax = height+linewidth+linewidth/2;
+    r.xmin = r2.xmin-linewidth-linewidth/2;
+    r.ymin = r2.ymin-linewidth-linewidth/2;
+    r.xmax = r2.xmax+linewidth+linewidth/2;
+    r.ymax = r2.ymax+linewidth+linewidth/2;
     swf_SetRect(tag,&r);
     swf_SetShapeHeader(tag,s);
     swf_ShapeSetAll(tag,s,0,0,ls1,fs1,0);
@@ -525,21 +830,64 @@ void s_box(char*name, int width, int height, RGBA color, int linewidth, RGBA fil
     incrementid();
 }
 
-void s_circle(char*name, int r, RGBA color, int linewidth, RGBA fill, int dofill)
+void s_filled(char*name, char*outlinename, RGBA color, int linewidth, char*texture)
 {
-    SRECT rect;
+    SRECT rect,r2;
     SHAPE* s;
     int ls1,fs1=0;
-    tag = swf_InsertTag(tag, ST_DEFINESHAPE);
+    outline_t* outline;
+    outline = dictionary_lookup(&outlines, outlinename);
+    if(!outline) {
+       syntaxerror("outline %s not defined", outlinename);
+    }
+    r2 = outline->bbox;
+
+    tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
+    swf_ShapeNew(&s);
+    if(linewidth)
+        ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
+    if(texture)
+       fs1 = addFillStyle(s, &r2, texture);
+    
+    swf_SetU16(tag,id);
+    rect.xmin = r2.xmin-linewidth-linewidth/2;
+    rect.ymin = r2.ymin-linewidth-linewidth/2;
+    rect.xmax = r2.xmax+linewidth+linewidth/2;
+    rect.ymax = r2.ymax+linewidth+linewidth/2;
+
+    swf_SetRect(tag,&rect);
+    swf_SetShapeStyles(tag, s);
+    swf_ShapeCountBits(s,0,0);
+    swf_RecodeShapeData(outline->shape->data, outline->shape->bitlen, 1,            1, 
+                        &s->data,             &s->bitlen,             s->bits.fill, s->bits.line);
+    swf_SetShapeBits(tag, s);
+    swf_SetBlock(tag, s->data, (s->bitlen+7)/8);
+    swf_ShapeFree(s);
+
+    s_addcharacter(name, id, tag, rect);
+    incrementid();
+}
+
+void s_circle(char*name, int r, RGBA color, int linewidth, char*texture)
+{
+    SRECT rect,r2;
+    SHAPE* s;
+    int ls1=0,fs1=0;
+    r2.xmin = r2.ymin = 0;
+    r2.xmax = 2*r;
+    r2.ymax = 2*r;
+
+    tag = swf_InsertTag(tag, ST_DEFINESHAPE3);
     swf_ShapeNew(&s);
-    ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
-    if(dofill)
-       fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
+    if(linewidth)
+        ls1 = swf_ShapeAddLineStyle(s,linewidth>=20?linewidth-20:0,&color);
+    if(texture)
+       fs1 = addFillStyle(s, &r2, texture);
     swf_SetU16(tag,id);
-    rect.xmin = -linewidth-linewidth/2;
-    rect.ymin = -linewidth-linewidth/2;
-    rect.xmax = 2*r+linewidth+linewidth/2;
-    rect.ymax = 2*r+linewidth+linewidth/2;
+    rect.xmin = r2.xmin-linewidth-linewidth/2;
+    rect.ymin = r2.ymin-linewidth-linewidth/2;
+    rect.xmax = r2.xmax+linewidth+linewidth/2;
+    rect.ymax = r2.ymax+linewidth+linewidth/2;
 
     swf_SetRect(tag,&rect);
     swf_SetShapeHeader(tag,s);
@@ -552,48 +900,48 @@ void s_circle(char*name, int r, RGBA color, int linewidth, RGBA fill, int dofill
     incrementid();
 }
 
-void s_textshape(char*name, char*fontname, char*_text, RGBA color, int linewidth, RGBA fill, int dofill)
+void s_textshape(char*name, char*fontname, float size, char*_text)
 {
-    SRECT rect;
-    SHAPE* s;
-    int ls1,fs1=0;
     int g;
     U8*text = (U8*)_text;
+    outline_t* outline;
 
     SWFFONT*font;
     font = dictionary_lookup(&fonts, fontname);
     if(!font)
        syntaxerror("font \"%s\" not known!", fontname);
-    if(!dofill)
-       syntaxerror("textshapes must be filled", fontname);
-
+    
     if(text[0] >= font->maxascii || font->ascii2glyph[text[0]]<0) {
        warning("no character 0x%02x (%c) in font \"%s\"", text[0], text[0], fontname);
-       s_box(name, 0, 0, black, 20, black, 0);
+       s_box(name, 0, 0, black, 20, 0);
        return;
     }
     g = font->ascii2glyph[text[0]];
-    rect = font->layout->bounds[g];
 
-    swf_ShapeNew(&s);
-    ls1 = swf_ShapeAddLineStyle(s,linewidth,&color);
-    if(dofill)
-       fs1 = swf_ShapeAddSolidFillStyle(s,&fill);
-     
-    tag = swf_InsertTag(tag, ST_DEFINESHAPE);
-    swf_SetU16(tag,id);
-    swf_SetRect(tag, &rect);
-    swf_SetShapeStyles(tag, s);
-    swf_SetSimpleShape(tag, font->glyph[g].shape);
-    swf_ShapeFree(s);
+    outline = malloc(sizeof(outline_t));
+    memset(outline, 0, sizeof(outline_t));
+    outline->shape = font->glyph[g].shape;
+    outline->bbox = font->layout->bounds[g];
     
-    s_addcharacter(name, id, tag, rect);
-    incrementid();
+    {
+       drawer_t draw;
+       swf_Shape11DrawerInit(&draw, 0);
+       swf_DrawText(&draw, font, (int)(size*100), _text);
+       draw.finish(&draw);
+       outline->shape = swf_ShapeDrawerToShape(&draw);
+       outline->bbox = swf_ShapeDrawerGetBBox(&draw);
+       draw.dealloc(&draw);
+    }
+
+    if(dictionary_lookup(&outlines, name))
+       syntaxerror("outline %s defined twice", name);
+    dictionary_put2(&outlines, name, outline);
 }
+
 void s_text(char*name, char*fontname, char*text, int size, RGBA color)
 {
     SRECT r;
-
+    MATRIX _m,*m=0;
     SWFFONT*font;
     font = dictionary_lookup(&fonts, fontname);
     if(!font)
@@ -602,7 +950,7 @@ void s_text(char*name, char*fontname, char*text, int size, RGBA color)
     tag = swf_InsertTag(tag, ST_DEFINETEXT2);
     swf_SetU16(tag, id);
     if(!font->numchars) {
-       s_box(name, 0, 0, black, 20, black, 0);
+       s_box(name, 0, 0, black, 20, 0);
        return;
     }
     r = swf_SetDefineText(tag, font, &color, text, size);
@@ -611,6 +959,158 @@ void s_text(char*name, char*fontname, char*text, int size, RGBA color)
     incrementid();
 }
 
+void s_quicktime(char*name, char*url)
+{
+    SRECT r;
+    MATRIX _m,*m=0;
+
+    memset(&r, 0, sizeof(r));
+    
+    tag = swf_InsertTag(tag, ST_DEFINEMOVIE);
+    swf_SetU16(tag, id);
+    swf_SetString(tag, url);
+    
+    s_addcharacter(name, id, tag, r);
+    incrementid();
+}
+
+void s_edittext(char*name, char*fontname, int size, int width, int height, char*text, RGBA*color, int maxlength, char*variable, int flags)
+{
+    SWFFONT*font = 0;
+    EditTextLayout layout;
+    SRECT r;
+
+    if(fontname && *fontname) {
+       flags |= ET_USEOUTLINES;
+       font = dictionary_lookup(&fonts, fontname);
+       if(!font)
+           syntaxerror("font \"%s\" not known!", fontname);
+    }
+    tag = swf_InsertTag(tag, ST_DEFINEEDITTEXT);
+    swf_SetU16(tag, id);
+    layout.align = 0;
+    layout.leftmargin = 0;
+    layout.rightmargin = 0;
+    layout.indent = 0;
+    layout.leading = 0;
+    r.xmin = 0;
+    r.ymin = 0;
+    r.xmax = width;
+    r.ymax = height;
+    
+    swf_SetEditText(tag, flags, r, text, color, maxlength, font?font->id:0, size, &layout, variable);
+
+    s_addcharacter(name, id, tag, r);
+    incrementid();
+}
+
+/* type: either "jpeg" or "png"
+ */
+void s_image(char*name, char*type, char*filename, int quality)
+{
+    /* an image is actually two folded: 1st bitmap, 2nd character.
+       Both of them can be used separately */
+    
+    /* step 1: the bitmap */
+    SRECT r;
+    int imageID = id;
+    int width, height;
+    if(type=="png") {
+       warning("image type \"png\" not supported yet!");
+       s_box(name, 0, 0, black, 20, 0);
+       return;
+    }
+    if(type=="jpeg") {
+#ifndef HAVE_LIBJPEG
+       warning("no jpeg support compiled in");
+       s_box(name, 0, 0, black, 20, 0);
+       return;
+#else
+       tag = swf_InsertTag(tag, ST_DEFINEBITSJPEG2);
+       swf_SetU16(tag, imageID);
+
+       if(swf_SetJPEGBits(tag, filename, quality) < 0) {
+           syntaxerror("Image \"%s\" not found, or contains errors", filename);
+       }
+
+       swf_GetJPEGSize(filename, &width, &height);
+
+       r.xmin = 0;
+       r.ymin = 0;
+       r.xmax = width*20;
+       r.ymax = height*20;
+
+       s_addimage(name, id, tag, r);
+       incrementid();
+#endif
+    }
+
+    /* step 2: the character */
+    tag = swf_InsertTag(tag, ST_DEFINESHAPE); // todo: should be defineshape2/3 once images can be transparent.(?)
+    swf_SetU16(tag, id);
+    swf_ShapeSetBitmapRect(tag, imageID, width, height);
+
+    s_addcharacter(name, id, tag, r);
+    incrementid();
+}
+
+void s_getBitmapSize(char*name, int*width, int*height)
+{
+    character_t* image = dictionary_lookup(&images, name);
+    gradient_t* gradient = dictionary_lookup(&gradients,name);
+    if(image) {
+       *width = image->size.xmax;
+       *height = image->size.ymax;
+       return;
+    }
+    if(gradient) {
+       /* internal SWF gradient size */
+       if(gradient->radial) {
+           *width = 16384;
+           *height = 16384;
+       } else {
+           *width = 32768;
+           *height = 32768;
+       }
+       return;
+    }
+    syntaxerror("No such bitmap/gradient: %s", name);
+}
+
+void s_texture(char*name, char*object, int x, int y, float scalex, float scaley, float rotate, float shear)
+{
+    gradient_t* gradient = dictionary_lookup(&gradients, object);
+    character_t* bitmap = dictionary_lookup(&images, object);
+    texture_t* texture = (texture_t*)rfx_calloc(sizeof(texture_t));
+    parameters_t p;
+    FILLSTYLE*fs = &texture->fs;
+
+    if(bitmap) {
+       fs->type = FILL_TILED;
+       fs->id_bitmap = bitmap->id;
+    } else if(gradient) {
+       fs->type = gradient->radial?FILL_RADIAL:FILL_LINEAR;
+       fs->gradient = gradient->gradient;
+    }
+    p.x = x;p.y = y;p.scalex = scalex;p.scaley = scaley;p.rotate=rotate;p.shear=shear;
+    makeMatrix(&fs->m, &p);
+    if(gradient && !gradient->radial) {
+       MATRIX m = fs->m;
+       SPOINT p1,p2;
+       m.tx = 0;
+       m.ty = 0;
+       p1.x = 16384;
+       p1.y = 16384;
+       p2 = swf_TurnPoint(p1, &m);
+       fs->m.tx += p2.x;
+       fs->m.ty += p2.y;
+    }
+
+    if(dictionary_lookup(&textures, name))
+       syntaxerror("texture %s defined twice", name);
+    dictionary_put2(&textures, name, texture);
+}
+
 void dumpSWF(SWF*swf)
 {
     TAG* tag = swf->firstTag;
@@ -624,26 +1124,16 @@ void dumpSWF(SWF*swf)
     
 void s_font(char*name, char*filename)
 {
-    int f;
-    SWF swf;
     SWFFONT* font;
-    f = open(filename,O_RDONLY|O_BINARY);
-    if (f<0) { 
-       warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
+    font = swf_LoadFont(filename);
+   
+    if(font == 0) {
+       warning("Couldn't open font file \"%s\"", filename);
        font = (SWFFONT*)malloc(sizeof(SWFFONT));
        memset(font, 0, sizeof(SWFFONT));
        dictionary_put2(&fonts, name, font);
        return;
     }
-    font = 0;
-    if (swf_ReadSWF(f,&swf)>=0) { 
-       swf_FontExtract(&swf, 0x4e46, &font);
-       swf_FreeTags(&swf);
-    }
-    close(f);
-    if (font==0) { 
-       syntaxerror("File \"%s\" isn't a valid rfxswf font file", filename);
-    }
 
     if(0)
     {
@@ -655,6 +1145,8 @@ void s_font(char*name, char*filename)
        font->layout = 0;
        swf_FontCreateLayout(font);
     }
+    /* just in case this thing is used in .edittext later on */
+    swf_FontPrepareForEditText(font);
 
     font->id = id;
     tag = swf_InsertTag(tag, ST_DEFINEFONT2);
@@ -666,6 +1158,8 @@ void s_font(char*name, char*filename)
     dictionary_put2(&fonts, name, font);
 }
 
+
+
 typedef struct _sound_t
 {
     U16 id;
@@ -678,6 +1172,7 @@ void s_sound(char*name, char*filename)
     sound_t* sound;
     U16*samples;
     int numsamples;
+    int t;
 
     if(!readWAV(filename, &wav)) {
        warning("Couldn't read wav file \"%s\"", filename);
@@ -688,6 +1183,12 @@ void s_sound(char*name, char*filename)
        samples = (U16*)wav2.data;
        numsamples = wav2.size/2;
        free(wav.data);
+#ifdef WORDS_BIGENDIAN
+       /* swap bytes */
+       for(t=0;t<numsamples;t++) {
+           samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
+       }
+#endif
     }
 
     tag = swf_InsertTag(tag, ST_DEFINESOUND);
@@ -708,12 +1209,146 @@ void s_sound(char*name, char*filename)
        free(samples);
 }
 
-void s_playsound(char*name, int loops, int nomultiple, int stop)
+static char* gradient_getToken(const char**p)
+{
+    const char*start;
+    char*result;
+    while(**p && strchr(" \t\n\r", **p)) {
+       (*p)++;
+    } 
+    start = *p;
+    while(**p && !strchr(" \t\n\r", **p)) {
+       (*p)++;
+    }
+    result = malloc((*p)-start+1);
+    memcpy(result,start,(*p)-start+1);
+    result[(*p)-start] = 0;
+    return result;
+}
+
+float parsePercent(char*str);
+RGBA parseColor(char*str);
+
+GRADIENT parseGradient(const char*str)
+{
+    GRADIENT gradient;
+    int lastpos = -1;
+    const char* p = str;
+    memset(&gradient, 0, sizeof(GRADIENT));
+    while(*p) {
+       char*posstr,*colorstr;
+       int pos;
+       RGBA color;
+       posstr = gradient_getToken(&p);
+       if(!*posstr)
+           break;
+       pos = (int)(parsePercent(posstr)*255.0);
+       if(pos == lastpos)
+           pos++;
+       if(!*p) syntaxerror("Error in shape data: Color expected after %s", posstr);
+       colorstr = gradient_getToken(&p);
+       color = parseColor(colorstr);
+       if(gradient.num == sizeof(gradient.ratios)/sizeof(gradient.ratios[0])) {
+           warning("gradient record too big- max size is 8, rest ignored");
+           break;
+       }
+       gradient.ratios[gradient.num] = pos;
+       gradient.rgba[gradient.num] = color;
+       gradient.num++;
+       free(posstr);
+       free(colorstr);
+       lastpos = pos;
+    }
+    return gradient;
+}
+
+void s_gradient(char*name, const char*text, int radial, int rotate)
+{
+    gradient_t* gradient;
+    gradient = malloc(sizeof(gradient_t));
+    memset(gradient, 0, sizeof(gradient_t));
+    gradient->gradient = parseGradient(text);
+    gradient->radial = radial;
+    gradient->rotate = rotate;
+
+    if(dictionary_lookup(&gradients, name))
+       syntaxerror("gradient %s defined twice", name);
+    dictionary_put2(&gradients, name, gradient);
+}
+
+void s_action(const char*text)
+{
+    ActionTAG* a = 0;
+    a = swf_ActionCompile(text, stack[0].swf->fileVersion);
+    if(!a) {
+       syntaxerror("Couldn't compile ActionScript");
+    }
+
+    tag = swf_InsertTag(tag, ST_DOACTION);
+
+    swf_ActionSet(tag, a);
+
+    swf_ActionFree(a);
+}
+
+int s_swf3action(char*name, char*action)
 {
-    sound_t* sound = dictionary_lookup(&sounds, name);
+    ActionTAG* a = 0;
+    instance_t* object = 0;
+    if(name) 
+       dictionary_lookup(&instances, name);
+    if(!object && name && *name) {
+       /* we have a name, but couldn't find it. Abort. */
+       return 0;
+    }
+    a = action_SetTarget(0, name);
+    if(!strcmp(action, "nextframe")) a = action_NextFrame(a);
+    else if(!strcmp(action, "previousframe")) a = action_PreviousFrame(a);
+    else if(!strcmp(action, "stop")) a = action_Stop(a);
+    else if(!strcmp(action, "play")) a = action_Play(a);
+    a = action_SetTarget(a, "");
+    a = action_End(a);
+
+    tag = swf_InsertTag(tag, ST_DOACTION);
+    swf_ActionSet(tag, a);
+    swf_ActionFree(a);
+    return 1;
+}
+
+void s_outline(char*name, char*format, char*source)
+{
+    outline_t* outline;
+
+    drawer_t draw;
+    SHAPE* shape;
+    SHAPE2* shape2;
+    SRECT bounds;
+    
+    swf_Shape11DrawerInit(&draw, 0);
+    draw_string(&draw, source);
+    draw.finish(&draw);
+    shape = swf_ShapeDrawerToShape(&draw);
+    bounds = swf_ShapeDrawerGetBBox(&draw);
+    draw.dealloc(&draw);
+    
+    outline = (outline_t*)rfx_calloc(sizeof(outline_t));
+    outline->shape = shape;
+    outline->bbox = bounds;
+    
+    if(dictionary_lookup(&outlines, name))
+       syntaxerror("outline %s defined twice", name);
+    dictionary_put2(&outlines, name, outline);
+}
+
+int s_playsound(char*name, int loops, int nomultiple, int stop)
+{
+    sound_t* sound;
     SOUNDINFO info;
+    if(!name)
+       return 0;
+    sound = dictionary_lookup(&sounds, name);
     if(!sound)
-       syntaxerror("Don't know anything about sound \"%s\"", name);
+       return 0;
 
     tag = swf_InsertTag(tag, ST_STARTSOUND);
     swf_SetU16(tag, sound->id); //id
@@ -722,9 +1357,10 @@ void s_playsound(char*name, int loops, int nomultiple, int stop)
     info.loops = loops;
     info.nomultiple = nomultiple;
     swf_SetSoundInfo(tag, &info);
+    return 1;
 }
 
-void s_shape(char*name, char*filename)
+void s_includeswf(char*name, char*filename)
 {
     int f;
     SWF swf;
@@ -733,15 +1369,15 @@ void s_shape(char*name, char*filename)
     TAG* s;
     int level = 0;
     U16 cutout[] = {ST_SETBACKGROUNDCOLOR, ST_PROTECT, ST_FREEALL, ST_REFLEX};
-    f = open(filename,O_RDONLY);
+    f = open(filename,O_RDONLY|O_BINARY);
     if (f<0) { 
        warning("Couldn't open file \"%s\": %s", filename, strerror(errno));
-       s_box(name, 0, 0, black, 20, black, 0);
+       s_box(name, 0, 0, black, 20, 0);
        return;
     }
     if (swf_ReadSWF(f,&swf)<0) { 
        warning("Only SWF files supported in .shape for now. File \"%s\" wasn't SWF.", filename);
-       s_box(name, 0, 0, black, 20, black, 0);
+       s_box(name, 0, 0, black, 20, 0);
        return;
     }
     close(f);
@@ -755,7 +1391,7 @@ void s_shape(char*name, char*filename)
     
     s = tag = swf_InsertTag(tag, ST_DEFINESPRITE);
     swf_SetU16(tag, id);
-    swf_SetU16(tag, 0);
+    swf_SetU16(tag, swf.frameCount);
 
     swf_Relocate(&swf, idmap);
 
@@ -823,7 +1459,7 @@ void s_startclip(char*instance, char*character, parameters_t p)
     }
     i = s_addinstance(instance, c, currentdepth);
     i->parameters = p;
-    m = s_instancepos(i, &p);
+    m = s_instancepos(i->character->size, &p);
     
     tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
     /* TODO: should be ObjectPlaceClip, with clipdepth backpatched */
@@ -844,6 +1480,7 @@ void s_endClip()
     swf_SetTagPos(stack[stackpos].tag, 0);
     swf_GetPlaceObject(stack[stackpos].tag, &p);
     p.clipdepth = currentdepth;
+    p.name = 0;
     swf_ClearTag(stack[stackpos].tag);
     swf_SetPlaceObject(stack[stackpos].tag, &p);
     currentdepth++;
@@ -860,7 +1497,7 @@ void s_put(char*instance, char*character, parameters_t p)
     
     i = s_addinstance(instance, c, currentdepth);
     i->parameters = p;
-    m = s_instancepos(i, &p);
+    m = s_instancepos(i->character->size, &p);
     
     tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
     swf_ObjectPlace(tag, c->id, currentdepth, &m, &p.cxform, instance);
@@ -878,7 +1515,7 @@ void s_jump(char*instance, parameters_t p)
     }
 
     i->parameters = p;
-    m = s_instancepos(i, &p);
+    m = s_instancepos(i->character->size, &p);
 
     tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
     swf_ObjectMove(tag, i->depth, &m, &p.cxform);
@@ -936,7 +1573,7 @@ void s_change(char*instance, parameters_t p2)
        return;
     }
     
-    m = s_instancepos(i, &p2);
+    m = s_instancepos(i->character->size, &p2);
     tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
     swf_ObjectMove(tag, i->depth, &m, &p2.cxform);
     i->parameters = p2;
@@ -954,7 +1591,7 @@ void s_change(char*instance, parameters_t p2)
            TAG*lt;
            frame ++;
            p = s_interpolate(&p1, &p2, frame, allframes);
-           m = s_instancepos(i, &p); //needed?
+           m = s_instancepos(i->character->size, &p); //needed?
            lt = swf_InsertTag(t, ST_PLACEOBJECT2);
            i->lastFrame = currentframe;
            swf_ObjectMove(lt, i->depth, &m, &p.cxform);
@@ -993,6 +1630,8 @@ void s_end()
        s_endSprite();
     else if(stack[stackpos-1].type == 2)
        s_endClip();
+    else if(stack[stackpos-1].type == 3)
+       s_endButton();
     else syntaxerror("internal error 1");
 }
 
@@ -1081,8 +1720,8 @@ int parseTwip(char*str)
            if(*s<'0' || *s>'9')
                syntaxerror("Not a coordinate: \"%s\"", str);
        }
-       if(l>2 || (l==2 && (dot[1]!='0' || dot[1]!='5'))) {
-           warning("precision loss: %s converted to twip", str);
+       if(l>2 || (l==2 && (dot[1]!='0' && dot[1]!='5'))) {
+           warning("precision loss: %s converted to twip: %s", str, dot);
            dot[2] = 0;
            l=2;
        }
@@ -1217,6 +1856,19 @@ MULADD mergeMulAdd(MULADD m1, MULADD m2)
     return r;
 }
 
+float parsePxOrPercent(char*fontname, char*str)
+{
+    int l = strlen(str);
+    if(strchr(str, '%'))
+       return parsePercent(str);
+    if(l>2 && str[l-2]=='p' && str[l-1]=='t') {
+       float p = atof(str);
+       return p/64.0; /*64 = FT_SUBPIXELS- see ../lib/modules/swffont.c */
+    }
+    syntaxerror("Expression '%s' is neither a point size (?pt) nor a percentage (?%)", str);
+    return 0;
+}
+
 float parsePercent(char*str)
 {
     int l = strlen(str);
@@ -1256,17 +1908,29 @@ static char* lu(map_t* args, char*name)
     return value;
 }
 
-static int c_swf(map_t*args) 
+static int c_flash(map_t*args) 
 {
-    char* name = lu(args, "name");
+    char* filename = map_lookup(args, "filename");
     char* compressstr = lu(args, "compress");
     SRECT bbox = parseBox(lu(args, "bbox"));
     int version = parseInt(lu(args, "version"));
     int fps = (int)(parseFloat(lu(args, "fps"))*256);
     int compress = 0;
     RGBA color = parseColor(lu(args, "background"));
-    if(!strcmp(name, "!default!") || override_outputname)
-       name = outputname;
+
+    if(!filename || !*filename) {
+       /* for compatibility */
+       filename = map_lookup(args, "name");
+       if(!filename || !*filename) {
+           filename = 0;
+       } else {
+           //msg("<warning> line %d: .flash name=... is deprecated, use .flash filename=...", line);
+           msg("<notice> line %d: .flash name=... is deprecated, use .flash filename=...", line);
+       }
+    }
+
+    if(!filename || override_outputname)
+       filename = outputname;
     
     if(!strcmp(compressstr, "default"))
        compress = version==6;
@@ -1276,7 +1940,7 @@ static int c_swf(map_t*args)
        compress = 0;
     else syntaxerror("value \"%s\" not supported for the compress argument", compressstr);
 
-    s_swf(name, bbox, version, fps, compress, color);
+    s_swf(filename, bbox, version, fps, compress, color);
     return 0;
 }
 int isRelative(char*str)
@@ -1324,8 +1988,94 @@ SPOINT getPoint(SRECT r, char*name)
     l--;
     return *(SPOINT*)&mpoints.buffer[l];
 }
+
+static int texture2(char*name, char*object, map_t*args, int errors) 
+{
+    SPOINT pos,size;
+    char*xstr = map_lookup(args, "x");
+    char*ystr = map_lookup(args, "y");
+    char*widthstr = map_lookup(args, "width");
+    char*heightstr = map_lookup(args, "height");
+    char*scalestr = map_lookup(args, "scale");
+    char*scalexstr = map_lookup(args, "scalex");
+    char*scaleystr = map_lookup(args, "scaley");
+    char*rotatestr = map_lookup(args, "rotate");
+    char* shearstr = map_lookup(args, "shear");
+    char* radiusstr = map_lookup(args, "r");
+    float x=0,y=0;
+    float scalex = 1.0, scaley = 1.0;
+    float rotate=0, shear=0;
+    float r = 0;
+    if(!*xstr && !*ystr) {
+       if(errors)
+           syntaxerror("x and y must be set");
+       return 0;
+    }
+    if(*scalestr && (*scalexstr || *scaleystr)) {
+       syntaxerror("scale and scalex/scaley can't both be set");
+       return 0;
+    }
+    if((*widthstr || *heightstr) && *radiusstr) {
+       syntaxerror("width/height and radius can't both be set");
+    }
+    if(*radiusstr) {
+       widthstr = radiusstr;
+       heightstr = radiusstr;
+    }
+    if(!*xstr) xstr="0";
+    if(!*ystr) ystr="0";
+    if(!*rotatestr) rotatestr="0";
+    if(!*shearstr) shearstr="0";
+
+    if(*scalestr) {
+       scalex = scaley = parsePercent(scalestr);
+    } else if(*scalexstr || *scaleystr) {
+       if(scalexstr) scalex = parsePercent(scalexstr);
+       if(scaleystr) scaley = parsePercent(scaleystr);
+    } else if(*widthstr || *heightstr) {
+       int width=0;
+       int height=0;
+       s_getBitmapSize(object, &width, &height);
+       if(*widthstr)
+           scalex = (float)parseTwip(widthstr)/(float)width;
+       if(*heightstr)
+           scaley = (float)parseTwip(heightstr)/(float)height;
+    }
+    x = parseTwip(xstr);
+    y = parseTwip(ystr);
+    rotate = parseFloat(rotatestr);
+    shear = parseFloat(shearstr);
+
+    s_texture(name, object, x,y,scalex,scaley,rotate, shear);
+
+    return 0;
+}
+
+static int c_texture(map_t*args) 
+{
+    char*name = lu(args, "instance");
+    char*object = lu(args, "character");
+    return texture2(name, object, args, 1);
+}
+
 static int c_gradient(map_t*args) 
 {
+    char*name = lu(args, "name");
+    int radial= strcmp(lu(args, "radial"), "radial")?0:1;
+    int rotate = parseInt(lu(args, "rotate"));
+
+    readToken();
+    if(type != RAWDATA)
+       syntaxerror("colon (:) expected");
+
+    s_gradient(name, text, radial, rotate);
+
+    /* check whether we also have placement information,
+       which would make this a positioned gradient.
+       If there is placement information, texture2() will
+       add a texture, which has priority over the gradient.
+     */
+    texture2(name, name, args, 0);
     return 0;
 }
 static int c_point(map_t*args) 
@@ -1349,7 +2099,7 @@ static int c_point(map_t*args)
 }
 static int c_play(map_t*args) 
 {
-    char*name = lu(args, "sound");
+    char*name = lu(args, "name");
     char*loop = lu(args, "loop");
     char*nomultiple = lu(args, "nomultiple");
     int nm = 0;
@@ -1358,14 +2108,46 @@ static int c_play(map_t*args)
     else
        nm = parseInt(nomultiple);
 
-    s_playsound(name, parseInt(loop), nm, 0);
+    if(s_playsound(name, parseInt(loop), nm, 0)) {
+       return 0;
+    } else if(s_swf3action(name, "play")) {
+       return 0;
+    }
     return 0;
 }
 
 static int c_stop(map_t*args) 
 {
-    char*name = lu(args, "sound");
-    s_playsound(name, 0,0,1);
+    char*name = map_lookup(args, "name");
+
+    if(s_playsound(name, 0,0,1)) {
+       return 0;
+    } else if(s_swf3action(name, "stop")) {
+       return 0;
+    }
+    syntaxerror("I don't know anything about sound/movie \"%s\"", name);
+    return 0;
+}
+
+static int c_nextframe(map_t*args) 
+{
+    char*name = lu(args, "name");
+
+    if(s_swf3action(name, "nextframe")) {
+       return 0;
+    }
+    syntaxerror("I don't know anything about movie \"%s\"", name);
+    return 0;
+}
+
+static int c_previousframe(map_t*args) 
+{
+    char*name = lu(args, "name");
+
+    if(s_swf3action(name, "previousframe")) {
+       return 0;
+    }
+    syntaxerror("I don't know anything about movie \"%s\"", name);
     return 0;
 }
 
@@ -1389,6 +2171,7 @@ static int c_placement(map_t*args, int type)
     char* bstr = lu(args, "blue");
     char* astr = lu(args, "alpha");
     char* pinstr = lu(args, "pin");
+    char* as = map_lookup(args, "as");
     MULADD r,g,b,a;
     float oldwidth;
     float oldheight;
@@ -1396,7 +2179,7 @@ static int c_placement(map_t*args, int type)
     MULADD luminance;
     parameters_t p;
 
-    if(type==5) {
+    if(type==9) { // (?) .rotate  or .arcchange
        pivotstr = lu(args, "pivot");
        anglestr = lu(args, "angle");
     } else {
@@ -1420,6 +2203,10 @@ static int c_placement(map_t*args, int type)
        // put or startclip
        character = lu(args, "character");
        parameters_clear(&p);
+    } else if (type == 5) {
+       character = lu(args, "name");
+       parameters_clear(&p);
+       // button's show
     } else {
        p = s_getParameters(instance);
     }
@@ -1540,14 +2327,21 @@ static int c_placement(map_t*args, int type)
 
     if(type == 0)
        s_put(instance, character, p);
-    if(type == 1)
+    else if(type == 1)
        s_change(instance, p);
-    if(type == 2)
+    else if(type == 2)
        s_qchange(instance, p);
-    if(type == 3)
+    else if(type == 3)
        s_jump(instance, p);
-    if(type == 4)
+    else if(type == 4)
        s_startclip(instance, character, p);
+    else if(type == 5) {
+       if(as && as[0]) {
+           s_buttonput(character, as, p);
+       } else {
+           s_buttonput(character, "shape", p);
+       }
+    }
     return 0;
 }
 static int c_put(map_t*args) 
@@ -1580,6 +2374,11 @@ static int c_startclip(map_t*args)
     c_placement(args, 4);
     return 0;
 }
+static int c_show(map_t*args) 
+{
+    c_placement(args, 5);
+    return 0;
+}
 static int c_del(map_t*args) 
 {
     char*instance = lu(args, "name");
@@ -1600,7 +2399,12 @@ static int c_sprite(map_t*args)
 static int c_frame(map_t*args) 
 {
     char*framestr = lu(args, "n");
+    char*cutstr = lu(args, "cut");
+    char*name = lu(args, "name");
     int frame;
+    int cut = 0;
+    if(strcmp(cutstr, "no"))
+       cut = 1;
     if(isRelative(framestr)) {
        frame = s_getframe();
        if(getSign(framestr)<0)
@@ -1610,10 +2414,10 @@ static int c_frame(map_t*args)
     else {
        frame = parseInt(framestr);
        if(s_getframe() >= frame
-               && !(frame==0 && s_getframe()==frame)) // equality is o.k. for frame 0
+               && !(frame==1 && s_getframe()==frame)) // equality is o.k. for frame 0
            syntaxerror("frame expression must be >%d (is:%s)", s_getframe(), framestr);
     }
-    s_frame(frame);
+    s_frame(frame, cut, name);
     return 0;
 }
 static int c_primitive(map_t*args) 
@@ -1629,10 +2433,11 @@ static int c_primitive(map_t*args)
     int type=0;
     char* font;
     char* text;
+    char* outline=0;
     RGBA fill;
     if(!strcmp(command, "circle"))
        type = 1;
-    else if(!strcmp(command, "textshape"))
+    else if(!strcmp(command, "filled"))
        type = 2;
    
     if(type==0) {
@@ -1641,36 +2446,41 @@ static int c_primitive(map_t*args)
     } else if (type==1) {
        r = parseTwip(lu(args, "r"));
     } else if (type==2) {
-       text = lu(args, "text");
-       font = lu(args, "font");
+       outline = lu(args, "outline");
     }
 
     if(!strcmp(fillstr, "fill"))
        fillstr = colorstr;
     if(!strcmp(fillstr, "none"))
-       dofill = 0;
+       fillstr = 0;
     if(width<0 || height<0 || linewidth<0 || r<0)
        syntaxerror("values width, height, line, r must be positive");
-    if(!dofill || isColor(fillstr)) {
-       if(dofill) 
-           fill = parseColor(fillstr);
-    } else {
-       /* FIXME - texture fill */
-       fill.r = fill.g = 0;
-       fill.b = fill.a = 255;
-       warning("texture fill not supported yet. Filling with black.");
-    }
-    if(type == 0) s_box(name, width, height, color, linewidth, fill, dofill);
-    else if(type==1) s_circle(name, r, color, linewidth, fill, dofill);
-    else if(type==2) s_textshape(name, font, text, color, linewidth, fill, dofill);
+    
+    if(type == 0) s_box(name, width, height, color, linewidth, fillstr);
+    else if(type==1) s_circle(name, r, color, linewidth, fillstr);
+    else if(type==2) s_filled(name, outline, color, linewidth, fillstr);
     return 0;
 }
 
-static int c_shape(map_t*args) 
+static int c_textshape(map_t*args) 
+{
+    char*name = lu(args, "name");
+    char*text = lu(args, "text");
+    char*font = lu(args, "font");
+    float size = parsePxOrPercent(font, lu(args, "size"));
+
+    s_textshape(name, font, size, text);
+    return 0;
+}
+
+static int c_swf(map_t*args) 
 {
     char*name = lu(args, "name");
     char*filename = lu(args, "filename");
-    s_shape(name, filename);
+    char*command = lu(args, "commandname");
+    if(!strcmp(command, "shape"))
+       warning("Please use .swf instead of .shape");
+    s_includeswf(name, filename);
     return 0;
 }
 
@@ -1695,7 +2505,7 @@ static int c_text(map_t*args)
     char*name = lu(args, "name");
     char*text = lu(args, "text");
     char*font = lu(args, "font");
-    float size = parsePercent(lu(args, "size"));
+    float size = parsePxOrPercent(font, lu(args, "size"));
     RGBA color = parseColor(lu(args, "color"));
     s_text(name, font, text, (int)(size*100), color);
     return 0;
@@ -1706,80 +2516,299 @@ static int c_soundtrack(map_t*args)
     return 0;
 }
 
+static int c_quicktime(map_t*args) 
+{
+    char*name = lu(args, "name");
+    char*url = lu(args, "url");
+    s_quicktime(name, url);
+    return 0;
+}
+
+static int c_image(map_t*args) 
+{
+    char*command = lu(args, "commandname");
+    char*name = lu(args, "name");
+    char*filename = lu(args, "filename");
+    if(!strcmp(command,"jpeg")) {
+       int quality = (int)(parsePercent(lu(args, "quality"))*100);
+       s_image(name, "jpeg", filename, quality);
+    } else {
+       s_image(name, "png", filename, 0);
+    }
+    return 0;
+}
+
+static int c_outline(map_t*args) 
+{
+    char*name = lu(args, "name");
+    char*format = lu(args, "format");
+
+    readToken();
+    if(type != RAWDATA)
+       syntaxerror("colon (:) expected");
+
+    s_outline(name, format, text);
+    return 0;
+}
+
 int fakechar(map_t*args)
 {
     char*name = lu(args, "name");
-    s_box(name, 0, 0, black, 20, black, 0);
+    s_box(name, 0, 0, black, 20, 0);
     return 0;
 }
 
 static int c_egon(map_t*args) {return fakechar(args);}
-static int c_button(map_t*args) {return fakechar(args);}
-static int c_edittext(map_t*args) {return fakechar(args);}
+static int c_button(map_t*args) {
+    char*name = lu(args, "name");
+    s_button(name);
+    return 0;
+}
+static int current_button_flags = 0;
+static int c_on_press(map_t*args)
+{
+    char*position = lu(args, "position");
+    char*action = "";
+    if(!strcmp(position, "inside")) {
+       current_button_flags |= BC_OVERUP_OVERDOWN;
+    } else if(!strcmp(position, "outside")) {
+       //current_button_flags |= BC_IDLE_OUTDOWN;
+       syntaxerror("IDLE_OVERDOWN not supported by SWF");
+    } else if(!strcmp(position, "anywhere")) {
+       current_button_flags |= /*BC_IDLE_OUTDOWN|*/BC_OVERUP_OVERDOWN|BC_IDLE_OVERDOWN;
+    }
+    readToken();
+    if(type == RAWDATA) {
+       action = text;
+       s_buttonaction(current_button_flags, action);
+       current_button_flags = 0;
+    }
+    else
+       pushBack();
+    return 0;
+}
+static int c_on_release(map_t*args)
+{
+    char*position = lu(args, "position");
+    char*action = "";
+    if(!strcmp(position, "inside")) {
+       current_button_flags |= BC_OVERDOWN_OVERUP;
+    } else if(!strcmp(position, "outside")) {
+       current_button_flags |= BC_OUTDOWN_IDLE;
+    } else if(!strcmp(position, "anywhere")) {
+       current_button_flags |= BC_OVERDOWN_OVERUP|BC_OUTDOWN_IDLE|BC_OVERDOWN_IDLE;
+    }
+    readToken();
+    if(type == RAWDATA) {
+       action = text;
+       s_buttonaction(current_button_flags, action);
+       current_button_flags = 0;
+    }
+    else
+       pushBack();
+    return 0;
+}
+static int c_on_move_in(map_t*args)
+{
+    char*position = lu(args, "state");
+    char*action = "";
+    if(!strcmp(position, "pressed")) {
+       current_button_flags |= BC_OUTDOWN_OVERDOWN;
+    } else if(!strcmp(position, "not_pressed")) {
+       current_button_flags |= BC_IDLE_OVERUP;
+    } else if(!strcmp(position, "any")) {
+       current_button_flags |= BC_OUTDOWN_OVERDOWN|BC_IDLE_OVERUP|BC_IDLE_OVERDOWN;
+    }
+    readToken();
+    if(type == RAWDATA) {
+       action = text;
+       s_buttonaction(current_button_flags, action);
+       current_button_flags = 0;
+    }
+    else
+       pushBack();
+    return 0;
+}
+static int c_on_move_out(map_t*args)
+{
+    char*position = lu(args, "state");
+    char*action = "";
+    if(!strcmp(position, "pressed")) {
+       current_button_flags |= BC_OVERDOWN_OUTDOWN;
+    } else if(!strcmp(position, "not_pressed")) {
+       current_button_flags |= BC_OVERUP_IDLE;
+    } else if(!strcmp(position, "any")) {
+       current_button_flags |= BC_OVERDOWN_OUTDOWN|BC_OVERUP_IDLE|BC_OVERDOWN_IDLE;
+    }
+    readToken();
+    if(type == RAWDATA) {
+       action = text;
+       s_buttonaction(current_button_flags, action);
+       current_button_flags = 0;
+    }
+    else
+       pushBack();
+    return 0;
+}
+static int c_on_key(map_t*args)
+{
+    char*key = lu(args, "key");
+    char*action = "";
+    if(strlen(key)==1) {
+       /* ascii */
+       if(key[0]>=32) {
+           current_button_flags |= 0x4000 + (key[0]*0x200);
+       } else {
+           syntaxerror("invalid character: %c"+key[0]);
+           return 1;
+       }
+    } else {
+       /* TODO: 
+          <ctrl-x> = 0x200*(x-'a')
+          esc = = 0x3600
+          space = = 0x4000;
+       */
+       syntaxerror("invalid key: %s",key);
+    }
+    readToken();
+    if(type == RAWDATA) {
+       action = text;
+       s_buttonaction(current_button_flags, action);
+       current_button_flags = 0;
+    }
+    else
+       pushBack();
+    return 0;
+}
+
+static int c_edittext(map_t*args) 
+{
+ //"name font size width height text="" color=black maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0"},
+    char*name = lu(args, "name");
+    char*font = lu(args, "font");
+    int size = (int)(1024*parsePxOrPercent(font, lu(args, "size")));
+    int width = parseTwip(lu(args, "width"));
+    int height = parseTwip(lu(args, "height"));
+    char*text  = lu(args, "text");
+    RGBA color = parseColor(lu(args, "color"));
+    int maxlength = parseInt(lu(args, "maxlength"));
+    char*variable = lu(args, "variable");
+    char*passwordstr = lu(args, "password");
+    char*wordwrapstr = lu(args, "wordwrap");
+    char*multilinestr = lu(args, "multiline");
+    char*htmlstr = lu(args, "html");
+    char*noselectstr = lu(args, "noselect");
+    char*readonlystr = lu(args, "readonly");
+    char*borderstr = lu(args, "border");
+
+    int flags = 0;
+    if(!strcmp(passwordstr, "password")) flags |= ET_PASSWORD;
+    if(!strcmp(wordwrapstr, "wordwrap")) flags |= ET_WORDWRAP;
+    if(!strcmp(multilinestr, "multiline")) flags |= ET_MULTILINE;
+    if(!strcmp(readonlystr, "readonly")) flags |= ET_READONLY;
+    if(!strcmp(htmlstr, "html")) flags |= ET_HTML;
+    if(!strcmp(noselectstr, "noselect")) flags |= ET_NOSELECT;
+    if(!strcmp(borderstr, "border")) flags |= ET_BORDER;
+
+    s_edittext(name, font, size, width, height, text, &color, maxlength, variable, flags);
+    return 0;
+}
 
 static int c_morphshape(map_t*args) {return fakechar(args);}
-static int c_image(map_t*args) {return fakechar(args);}
 static int c_movie(map_t*args) {return fakechar(args);}
 
-static int c_buttonsounds(map_t*args) {return 0;}
-static int c_buttonput(map_t*args) {return 0;}
-static int c_texture(map_t*args) {return 0;}
-static int c_action(map_t*args) {return 0;}
+static int c_action(map_t*args) 
+{
+    char* filename  = map_lookup(args, "filename");
+    if(!filename ||!*filename) {
+       readToken();
+       if(type != RAWDATA) {
+           syntaxerror("colon (:) expected");
+       }
+       s_action(text);
+    } else {
+       FILE*fi = fopen(filename, "rb");
+       int l;
+       char*text;
+       if(!fi) 
+           syntaxerror("Couldn't find file %s: %s", filename, strerror(errno));
+       fseek(fi, 0, SEEK_END);
+       l = ftell(fi);
+       fseek(fi, 0, SEEK_SET);
+       text = rfx_alloc(l+1);
+       fread(text, l, 1, fi);
+       text[l]=0;
+       fclose(fi);
+
+       s_action(text);
+    }
+   
+    return 0;
+}
 
 static struct {
     char*command;
     command_func_t* func;
     char*arguments;
 } arguments[] =
-{{"swf", c_swf, "bbox=autocrop background=black version=5 fps=50 name=!default! @compress=default"},
- {"frame", c_frame, "n=<plus>1"},
-
-    // "import" type stuff
- {"shape", c_shape, "name filename"},
- {"morphshape", c_morphshape, "name start end"},
+{{"flash", c_flash, "bbox=autocrop background=black version=6 fps=50 name= filename= @compress=default"},
+ {"frame", c_frame, "n=<plus>1 name= @cut=no"},
+ // "import" type stuff
+ {"swf", c_swf, "name filename"},
+ {"shape", c_swf, "name filename"},
  {"jpeg", c_image, "name filename quality=80%"},
  {"png", c_image, "name filename"},
  {"movie", c_movie, "name filename"},
  {"sound", c_sound, "name filename"},
  {"font", c_font, "name filename"},
  {"soundtrack", c_soundtrack, "filename"},
+ {"quicktime", c_quicktime, "url"},
 
     // generators of primitives
 
  {"point", c_point, "name x=0 y=0"},
- {"gradient", c_gradient, "name"},
+ {"gradient", c_gradient, "name @radial=0 rotate=0 scale= scalex= scaley= x= y= width= height= r= shear="}, //extra parameters like .texture
+ {"outline", c_outline, "name format=simple"},
+ {"textshape", c_textshape, "name font size=100% text"},
 
     // character generators
  {"box", c_primitive, "name width height color=white line=1 @fill=none"},
  {"circle", c_primitive, "name r color=white line=1 @fill=none"},
- {"textshape", c_primitive, "name text font color=white line=1 @fill=none"},
+ {"filled", c_primitive, "name outline color=white line=1 @fill=none"},
+
  {"egon", c_egon, "name vertices color=white line=1 @fill=none"},
- {"button", c_button, "name shape over=*shape press=*shape area=*shape"},
  {"text", c_text, "name text font size=100% color=white"},
- {"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"},
+ {"edittext", c_edittext, "name font= size=100% width height text="" color=white maxlength=0 variable="" @password=0 @wordwrap=0 @multiline=0 @html=0 @noselect=0 @readonly=0 @border=0"},
+ {"morphshape", c_morphshape, "name start end"},
+ {"button", c_button, "name"},
+    {"show", c_show,             "name x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below= as="},
+    {"on_press", c_on_press, "position=inside"},
+    {"on_release", c_on_release, "position=anywhere"},
+    {"on_move_in", c_on_move_in, "state=not_pressed"},
+    {"on_move_out", c_on_move_out, "state=not_pressed"},
+    {"on_key", c_on_key, "key=any"},
  
- {"buttonsounds", c_buttonsounds, "name press=0 release=0 enter=0 leave=0"},
-
     // control tags
- {"play", c_play, "sound loop=0 @nomultiple=0"},
- {"stop", c_stop, "sound"},
+ {"play", c_play, "name loop=0 @nomultiple=0"},
+ {"stop", c_stop, "name= "},
+ {"nextframe", c_nextframe, "name"},
+ {"previousframe", c_previousframe, "name"},
 
     // object placement tags
- {"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="},
- {"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="},
- {"change", c_change,   "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
- {"arcchange", c_arcchange,   "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
- {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
- {"jump", c_jump,       "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= above= below="},
+ {"put", c_put,             "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
+ {"startclip", c_startclip, "<i> x=0 y=0 red=+0 green=+0 blue=+0 alpha=+0 luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
+ {"change", c_change,   "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
+ {"arcchange", c_arcchange,   "name pivot= angle= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
+ {"qchange", c_qchange, "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
+ {"jump", c_jump,       "name x= y= red= green= blue= alpha= luminance= scale= scalex= scaley= pivot= pin= shear= rotate= ratio= above= below="},
  {"del", c_del, "name"},
     // virtual object placement
- {"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="},
- {"texture", c_texture, "<i> x=0 y=0 scale= scalex=100% scaley=100% shear=0 rotate=0"},
+ {"texture", c_texture, "<i> x=0 y=0 width= height= scale= scalex= scaley= r= shear= rotate="},
 
     // commands which start a block
 //startclip (see above)
  {"sprite", c_sprite, "name"},
- {"action", c_action, ""},
+ {"action", c_action, "filename="},
 
  {"end", c_end, ""}
 };
@@ -1814,7 +2843,7 @@ static map_t parseArguments(char*command, char*pattern)
 
     if(!strncmp("<i> ", x, 3)) {
        readToken();
-       if(type == COMMAND || type == LABEL) {
+       if(type == COMMAND || type == RAWDATA) {
            pushBack();
            syntaxerror("character name expected");
        }
@@ -1874,7 +2903,7 @@ static map_t parseArguments(char*command, char*pattern)
 
     while(1) {
        readToken();
-       if(type == LABEL || type == COMMAND) {
+       if(type == RAWDATA || type == COMMAND) {
            pushBack();
            break;
        }
@@ -1918,7 +2947,7 @@ static map_t parseArguments(char*command, char*pattern)
            }
        }
        if(pos==len) {
-           syntaxerror("don't know what to do with \"%s\". (All parameters for .%s already set)", text, command);
+           syntaxerror("Illegal argument \"%s\" to .%s", text, command);
        }
     }
 #if 0//def DEBUG
@@ -1955,14 +2984,32 @@ static void parseArgumentsForCommand(char*command)
     int t;
     map_t args;
     int nr = -1;
+    msg("<verbose> parse Command: %s (line %d)", command, line);
+
     for(t=0;t<sizeof(arguments)/sizeof(arguments[0]);t++) {
        if(!strcmp(arguments[t].command, command)) {
+
+           /* ugly hack- will be removed soon (once documentation and .sc generating
+              utilities have been changed) */
+           if(!strcmp(command, "swf") && !stackpos) {
+               warning("Please use .flash instead of .swf- this will be mandatory soon");      
+               command = "flash";
+               t = 0;
+           }
+
            args = parseArguments(command, arguments[t].arguments);
            nr = t;
+           break;
        }
     }
     if(nr<0)
        syntaxerror("command %s not known", command);
+   
+    // catch missing .flash directives at the beginning of a file
+    if(strcmp(command, "flash") && !stackpos)
+    {
+       syntaxerror("No movie defined- use .flash first");
+    }
 
 #ifdef DEBUG
     printf(".%s\n", command);fflush(stdout);
@@ -1971,7 +3018,7 @@ static void parseArgumentsForCommand(char*command)
 
     (*arguments[nr].func)(&args);
 
-    if(!strcmp(command, "button") ||
+    /*if(!strcmp(command, "button") ||
        !strcmp(command, "action")) {
        while(1) {
            readToken();
@@ -1984,7 +3031,7 @@ static void parseArgumentsForCommand(char*command)
                }
            }
        }
-    }
+    }*/
 
     map_clear(&args);
     return;
@@ -2000,13 +3047,13 @@ int main (int argc,char ** argv)
        args_callback_usage(argv[0]);
        exit(1);
     }
+    
     file = generateTokens(filename);
     if(!file) {
        printf("parser returned error.\n");
        return 1;
     }
     pos=0;
-
     t=0;
 
     while(!noMoreTokens()) {