Example #1
0
static void
add_define(char *name, int nargs, char *exps)
{
    struct defn *p;
    unsigned int h;

    if ((p = lookup_define(name)) != NULL)
    {
	if (nargs != p->nargs || strcmp(exps, p->exps) != 0)
	{
	    lexerror("Redefinition of #define %s", name);
	}
	return;
    }
    p = (struct defn *)xalloc(sizeof(struct defn));
    p->name = xalloc(strlen(name)+1);
    (void)strcpy(p->name, name);
    p->undef = 0;
    p->nargs = nargs;
    p->exps = xalloc(strlen(exps)+1);
    (void)strcpy(p->exps, exps);
    h = defhash(name);
    p->next = defns[h];
    defns[h] = p;
    /*(void)fprintf(stderr, "define '%s' %d '%s'\n", name, nargs, exps);*/
}
Example #2
0
static int
yylex1(void)
{
    register char *yyp;
    register int c;
    register int c1, c2;
    
    for (;;)
    {
	if (lex_fatal)
	{
	    return -1;
	}
	switch(c = mygetc())
	{
	case EOF:
	    if (inctop)
	    {
		struct incstate *p;
		p = inctop;
		(void)fclose(yyin);
		/*(void)fprintf(stderr, "popping to %s\n", p->file);*/
		free(current_file);
		nexpands = 0;
		current_file = p->file;
		current_line = p->line + 1;
		current_incfile = p->incfnum;
		pragma_strict_types = p->pragma_strict_types;
		yyin = p->yyin;
		slast = p->slast;
		lastchar = p->lastchar;
		inctop = p->next;
		
		if (p->nbuf)
		{
		    nbuf = p->nbuf;
		    outp = defbuf + DEFMAX - nbuf;
		    memcpy(outp, p->outp, nbuf);
		    free((char *)p->outp);
		}
		else
		{
		    nbuf = 0;
		    outp = defbuf + DEFMAX;
		}
		
		store_line_number_info(current_incfile, current_line);
		incdepth--;
		
		free((char *)p);
		break;
	    }
	    if (iftop)
	    {
		struct ifstate *p = iftop;
		lexerror(p->state == EXPECT_ENDIF ? "Missing #endif" : "Missing #else");
		while (iftop)
		{
		    p = iftop;
		    iftop = p->next;
		    free((char *)p);
		}
	    }
	    return -1;
	case '\n':
	{
	    nexpands=0;
	    store_line_number_info(current_incfile, current_line);
	    current_line++;
	    total_lines++;
	}
        /* FALLTHROUGH */
	case ' ':
	case '\t':
	case '\f':
	case '\v':
	    break;
	case '+':
	    TRY('+', F_INC);
	    TRY('=', F_ADD_EQ);
	    return c;
	case '-':
	    TRY('>', F_ARROW);
	    TRY('-', F_DEC);
	    TRY('=', F_SUB_EQ);
	    return c;
	case '&':
	    TRY('&', F_LAND);
	    TRY('=', F_AND_EQ);
	    return c;
	case '|':
	    TRY('|', F_LOR);
	    TRY('=', F_OR_EQ);
	    return c;
	case '^':
	    TRY('=', F_XOR_EQ);
	    return c;
	case '<':
	    if (gobble('<')) {
		TRY('=', F_LSH_EQ);
		return F_LSH;
	    }
	    TRY('=', F_LE);
	    return c;
	case '>':
	    if (gobble('>'))
	    {
		TRY('=', F_RSH_EQ);
		return F_RSH;
	    }
	    TRY('=', F_GE);
	    return c;
	case '*':
	    TRY('=', F_MULT_EQ);
	    return c;
	case '%':
	    TRY('=', F_MOD_EQ);
	    return F_MOD;
	case '/':
	    if (gobble('*'))
	    {
		skip_comment();
		break;
	    }
	    else if (gobble('/'))
	    {
		skip_comment2();
		break;
	    }
	    TRY('=', F_DIV_EQ);
	    return c;
	case '=':
	    TRY('=', F_EQ);
	    return c;
	case ';':
	case '(':
	case ')':
	case ',':
	case '{':
	case '}':
	case '~':
	case '[':
	case ']':
	case '?':
	case '@':
	    return c;
	case '!':
	    TRY('=', F_NE);
	    return F_NOT;
	case ':':
	    TRY(':', F_COLON_COLON);
	    return ':';
	case '.':
	    if (gobble('.'))
	    {
		if (gobble('.'))
		    return F_VARARG;
		else
		    return F_RANGE;
	    }
	    return c;
	case '#':
	    if (lastchar == '\n') 
	    {
		char *ssp = 0;
		int quote;
		
		yyp = yytext;
		do 
		{
		    c = mygetc();
		} while (isspace(c));
		
		for (quote = 0;;) 
		{
		    if (c == '"')
			quote ^= 1;
		    
		    /*gc - handle comments cpp-like! 1.6.91 @@@*/
		    while (!quote && c == '/')  
		    {
			if (gobble('*')) 
			{ 
			    skip_comment();
			    c = mygetc();
			}
			else 
			    break;
		    }
		    
		    if (!ssp && isspace(c))
			ssp = yyp;
		    if (c == '\n' || c == EOF)
			break;
		    SAVEC;
		    c = mygetc();
		}
		if (ssp) 
		{
		    *ssp++ = 0;
		    while (isspace(*ssp))
			ssp++;
		} 
		else 
		{
		    ssp = yyp;
		}
		*yyp = 0;
		if (strcmp("define", yytext) == 0) 
		{
		    handle_define(ssp);
		} 
		else if (strcmp("if", yytext) == 0) 
		{
#if 0
		    short int nega=0; /*@@@ allow #if !VAR gc 1.6.91*/
		    if (*ssp=='!'){ ssp++; nega=1;}
		    if (isdigit(*ssp))
		    {
			char *p;
			long l;
			l = strtol(ssp, &p, 10);
			while (isspace(*p))
			    p++;
			if (*p)
			    lexerror("Condition too complex in #if");
			else
			    handle_cond(nega ? !(int)l : (int)l);
		    }
		    else if (isalunum(*ssp))
		    {
			char *p = ssp;
			while (isalunum(*p))
			    p++;
			if (*p)
			{
			    *p++ = 0;
			    while (isspace(*p))
				p++;
			}
			if (*p)
			    lexerror("Condition too complex in #if");
			else
			{
			    struct defn *d;
			    d = lookup_define(ssp);
			    if (d)
			    {
				handle_cond(nega ? !atoi(d->exps) : atoi(d->exps));/* a hack! */
			    }
			    else
			    {
				handle_cond(nega?1:0); /* cpp-like gc*/
			    }
			}
		    }
		    else
			lexerror("Condition too complex in #if");
#else
		    int cond;
            
		    myungetc(0);
		    add_input(ssp);
		    cond = cond_get_exp(0);
		    if (mygetc()) 
		    {
			lexerror("Condition too complex in #if");
			while (mygetc())
			    ;
		    }
		    else
			handle_cond(cond);
#endif
		}
		else if (strcmp("ifdef", yytext) == 0) 
		{
		    deltrail(ssp);
		    handle_cond(lookup_define(ssp) != 0);
		}
		else if (strcmp("ifndef", yytext) == 0)
		{
		    deltrail(ssp);
		    handle_cond(lookup_define(ssp) == 0);
		} 
		else if (strcmp("else", yytext) == 0) 
		{
		    if (iftop && iftop->state == EXPECT_ELSE) 
		    {
			struct ifstate *p = iftop;
			
			/*(void)fprintf(stderr, "found else\n");*/
			iftop = p->next;
			free((char *)p);
			(void)skip_to("endif", (char *)0);
			store_line_number_info(current_incfile, current_line);
			current_line++;
			total_lines++;
		    }
		    else
		    {
			lexerror("Unexpected #else");
		    }
		} 
		else if (strcmp("endif", yytext) == 0) 
		{
		    if (iftop && (iftop->state == EXPECT_ENDIF ||
				  iftop->state == EXPECT_ELSE)) 
		    {
			struct ifstate *p = iftop;
			
			/*(void)fprintf(stderr, "found endif\n");*/
			iftop = p->next;
			free((char *)p);
		    } 
		    else 
		    {
			lexerror("Unexpected #endif");
		    }
		} 
		else if (strcmp("undef", yytext) == 0) 
		{
		    struct defn *d;
		    
		    deltrail(ssp);
		    if ((d = lookup_define(ssp)) != NULL )
			d->undef++;
		} 
		else if (strcmp("echo", yytext) == 0) 
		{
		    (void)fprintf(stderr, "%s\n", ssp);
		} 
		else if (strcmp("include", yytext) == 0) 
		{
		    /*(void)fprintf(stderr, "including %s\n", ssp);     */
		    handle_include(ssp, 0);
		}
		else if (strcmp("pragma", yytext) == 0)
		{
		    deltrail(ssp);
		    handle_pragma(ssp);
		} 
		else if (strcmp("error", yytext) == 0)
		{
		    handle_exception(ERROR, ssp);
		}
		else if (strcmp("warning", yytext) == 0)
		{
		    handle_exception(WARNING, ssp);
		}
		else 
		{
		    lexerror("Unrecognised # directive");
		}
		myungetc('\n');
		break;
	    }
	    else
		goto badlex;
	case '\'':
	    yylval.number = mygetc();
	    if (yylval.number == '\\')
	    {
		int tmp = mygetc();
		switch (tmp)
		{
		case 'n': yylval.number = '\n'; break;
		case 't': yylval.number = '\t'; break;
		case 'b': yylval.number = '\b'; break;
		case 'a': yylval.number = '\a'; break;
		case 'v': yylval.number = '\v'; break;
		case '\'':
		case '\\':
		case '"':
		    yylval.number = tmp; break;
		default:
		    lexwarning("Bad character escape sequence");
		    yylval.number = tmp;
		    break;
		}
	    }
	    if (!gobble('\''))
		lexerror("Illegal character constant");
	    return F_NUMBER;
	case '"':
	    yyp = yytext;
	    *yyp++ = c;
	    for (;;)
	    {
		c = mygetc();
		if (c == EOF)
		{
		    lexerror("End of file in string");
		    return string("\"\"");
		}
		else if (c == '\n')
		{
		    lexerror("Newline in string");
		    return string("\"\"");
		}
		SAVEC;
		if (c == '"')
		    break;
		if (c == '\\')
		{
		    c = mygetc();
		    if ( c == '\n' )
		    {
			yyp--;
			store_line_number_info(current_incfile, current_line);
			current_line++;
			total_lines++;
		    } 
		    else if ( c == EOF ) 
		    {
			/* some operating systems give EOF only once */
			myungetc(c); 
		    } 
		    else
			*yyp++ = c;
		}
	    }
	    *yyp = 0;
	    return string(yytext);

	case '0':
	    c = mygetc();
	    if ( c == 'X' || c == 'x' || c == 'o') 
	    {
                char *endptr;
                long long value;
                int base = 16;
                if (c == 'o')
                    base = 8;

                
		yyp = yytext;

		for (;;) 
		{
		    c = mygetc();
		    if (!isxdigit(c))
			break;
                    SAVEC;
		}
		myungetc(c);
                *yyp = '\0';
                
                value = strtoll(yytext, &endptr, base);
                if (*endptr != '\0')
                {
                    fprintf(stderr, "%s\n", yytext);
                    lexwarning("Invalid digits in octal number number");
                }
                
                return number(value);
	    }
	    myungetc(c);
	    c = '0';
	    /* FALLTHROUGH */
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
	    yyp = yytext;
	    *yyp++ = c;
	    for (;;)
	    {
		c = mygetc();
		if (!isdigit(c))
		    break;
		SAVEC;
	    }
	    if (c == '.')
	    {
		if (isdigit(c1 = mygetc()))
		{
		    SAVEC;
		    c = c1;
		    SAVEC;
		    for (c = mygetc(); isdigit(c); c = mygetc())
			SAVEC;
		    if (c == 'e' || c == 'E')
		    {
			c1 = mygetc();
			if (c1 == '-' || c1 == '+')
			{
			    c2 = mygetc();
			    if (isdigit(c2))
			    {
				SAVEC;
				c = c1;
				SAVEC;
				c = c2;
				SAVEC;
				for (c = mygetc(); isdigit(c); c = mygetc())
				    SAVEC;
			    }
			    else
			    {
				myungetc(c2);
				myungetc(c1);
			    }
			}
			else if (isdigit(c1))
			{
			    SAVEC;
			    c = c1;
			    SAVEC;
			    for (c = mygetc(); isdigit(c); c = mygetc())
				SAVEC;
			}
			else
			    myungetc(c1);
		    }
		    myungetc(c);
		    *yyp = 0;
		    return real(strtod(yytext, NULL));
		}
		myungetc(c1);
	    }
	    myungetc(c);
	    *yyp = 0;
	    if (*yytext == '0')
            {
                /* OCTALS */
                char *endptr;
                long long value;

                value = strtoll(yytext, &endptr, 010);

                if (*endptr != '\0')
                    lexwarning("Invalid digits in octal number");

                if (value != 0)
                    lexwarning("Obsolete octal format used. Use 0o111 syntax");
                
		return number(value);
            }
	    return number(atoll(yytext));
	default:
	    if (isalpha(c) || c == '_') {
		int r;
		
		yyp = yytext;
		*yyp++ = c;
		for (;;)
		{
		    c = mygetc();
		    if (!isalunum(c))
			break;
		    SAVEC;
		}
		*yyp = 0;
		
		myungetc(c);
		if (!expand_define())
		{
		    r = lookup_resword(yytext);
		    if (r >= 0)
		    {
			return r;
		    }
		    else
			return ident(yytext);
		}
		break;
	    }
	    goto badlex;
	}
    }
  badlex:
    {
	lexerror("Illegal character (hex %02x) '%c'", c, c);
        return ' '; 
    }
}
Example #3
0
int
handle_include(char *name, int ignore_errors)
{
    char *p;
    char buf[1024];
    FILE *f;
    struct incstate *is;
    int delim;

    if (*name != '"' && *name != '<')
    {
	struct defn *d;
	if ((d = lookup_define(name)) && d->nargs == -1)
	{
	    char *q;
	    q = d->exps;
	    while (isspace(*q))
		q++;
	    return handle_include(q, ignore_errors);
	}
	else
	{
            if (!ignore_errors)
	        lexerror("Missing leading \" or < in #include");
            return 0;
	}
    }
    delim = *name++ == '"' ? '"' : '>';
    for (p = name; *p && *p != delim; p++)
	;
    if (!*p)
    {
        if (!ignore_errors)
	    lexerror("Missing trailing \" or > in #include");
	return 0;
    }
    if (strlen(name) > sizeof(buf) - 100)
    { 
        if (!ignore_errors)
	    lexerror("Include name too long.");
	return 0;
    }
    *p = 0;
    
    if ((f = inc_open(buf, sizeof(buf), name)) == NULL)
    {
        if (!ignore_errors) {
	    lexerror("Cannot #include %s\n", name);
        }

        return 0;
    }

    is = (struct incstate *)xalloc(sizeof(struct incstate));
    is->yyin = yyin;
    is->line = current_line;
    is->file = current_file;
    is->incfnum = current_incfile;
    is->slast = slast;
    is->lastchar = lastchar;
    is->next = inctop;
    is->pragma_strict_types = pragma_strict_types;

    if (nbuf)
    {
        memcpy(is->outp = (char *)xalloc(nbuf + 1), outp, nbuf);
        is->nbuf = nbuf;
        nbuf = 0;
        outp = defbuf + DEFMAX;
    }
    else
    {
        is->nbuf = 0;
        is->outp = NULL;
    }

    pragma_strict_types = 0;
    inctop = is;
    current_line = 1;
    current_file = xalloc(strlen(buf)+1);
    current_incfile = ++num_incfiles;
    (void)strcpy(current_file, buf);
    slast = lastchar = '\n';
    yyin = f;
    incdepth++;
    return 1;
}
Example #4
0
/* Stuff to evaluate expression.  I havn't really checked it. /LA
** Written by "J\"orn Rennecke" <*****@*****.**>
*/
static int
exgetc(void)
{
    register char c, *yyp;
    
    c = mygetc();
    while (isalpha(c) || c == '_')
    {
	yyp = yytext;
	do
	{
	    SAVEC;
	    c = mygetc();
	} while (isalunum(c));
	myungetc(c);
	*yyp = '\0';
	if (strcmp(yytext, "defined") == 0)
	{
	    /* handle the defined "function" in #if */
	    do
		c = mygetc();
	    while (isspace(c));
	    
	    if (c != '(')
	    {
		lexerror("Missing ( in defined");
		continue;
	    }
	    do
		c = mygetc();
	    while (isspace(c));
	    
	    yyp = yytext;
	    while (isalunum(c))
	    {
		SAVEC;
		c = mygetc();
	    }
	    *yyp = '\0';
	    while (isspace(c))
		c = mygetc();
	    if (c != ')')
	    {
		lexerror("Missing ) in defined");
		continue;
	    }

	    /* Skip whitespace */
	    do
		c = mygetc();
	    while (isspace(c)); 
	    myungetc(c);

	    if (lookup_define(yytext))
		add_input(" 1 ");
	    else
		add_input(" 0 ");
	}
	else
	{
	    if (!expand_define()) add_input(" 0 ");
	}
	c = mygetc();
    }
    return c;
}
Example #5
0
/* Check if yytext is a macro and expand if it is. */
static int
expand_define(void)
{
    struct defn *p;
    char expbuf[DEFMAX];
    char *args[NARGS];
    char buf[DEFMAX];
    char *q, *e, *b;

    if (nexpands++ > EXPANDMAX)
    {
	lexerror("Too many macro expansions");
	return 0;
    }
    p = lookup_define(yytext);
    if (!p)
    {
	return 0;
    }
    if (p->nargs == -1)
    {
	add_input(p->exps);
    }
    else
    {
	int c, parcnt = 0, dquote = 0, squote = 0;
	int n;
	SKIPW;
	if (c != '(')
	{
	    lexerror("Missing '(' in macro call");
	    return 0;
	}
	SKIPW;
	if (c == ')')
	    n = 0;
	else
	{
	    q = expbuf;
	    args[0] = q;
	    for (n = 0; n < NARGS; )
	    {
		switch(c)
		{
		case '"':
		    if (!squote)
			dquote ^= 1;
		    break;
		case '\'':
		    if (!dquote)
			squote ^= 1;
		    break;
		case '(':
		    if (!squote && !dquote)
			parcnt++;
		    break;
		case ')':
		    if (!squote && !dquote)
			parcnt--;
		    break;
		case '\\':
		    if (squote || dquote)
		    {
			*q++ = c;
			c = mygetc();}
		    break;
		case '\n':
		    if (squote || dquote)
		    {
			lexerror("Newline in string");
			return 0;
		    }
		    break;
		}
		if (c == ',' && !parcnt && !dquote && !squote)
		{
		    *q++ = 0;
		    args[++n] = q;
		}
		else if (parcnt < 0)
		{
		    *q++ = 0;
		    n++;
		    break;
		}
		else
		{
		    if (c == EOF)
		    {
			lexerror("Unexpected end of file");
			return 0;
		    }
		    if (q >= expbuf + DEFMAX - 5)
		    {
			lexerror("Macro argument overflow");
			return 0;
		    }
		    else
		    {
			*q++ = c;
		    }
		}
		if (!squote && ! dquote)
		    c = cmygetc();
		else
		    c = mygetc();
	    }
	    if (n == NARGS)
	    {
		lexerror("Maximum macro argument count exceeded");
		return 0;
	    }
	}
	if (n != p->nargs)
	{
	    lexerror("Wrong number of macro arguments");
	    return 0;
	}
	/* Do expansion */
	b = buf;
	e = p->exps;
	while (*e)
	{
	    if (*e == MARKS)
	    {
		if (*++e == MARKS)
		    *b++ = *e++;
		else
		{
		    for (q = args[*e++ - MARKS - 1]; *q; )
		    {
			*b++ = *q++;
			if (b >= buf+DEFMAX)
			{
			    lexerror("Macro expansion overflow");
			    return 0;
			}
		    }
		}
	    }
	    else
	    {
		*b++ = *e++;
		if (b >= buf+DEFMAX)
		{
		    lexerror("Macro expansion overflow");
		    return 0;
		}
	    }
	}
	*b++ = 0;
	add_input(buf);
    }
    return 1;
}
Example #6
0
int
cmdline_main (int argc, char *argv[])
{
    guchar *output;
    int num_frames = 1;
#ifdef MOVIES
    int generate_movie = 0;
    quicktime_t *output_movie;
    guchar **rows;
#endif
    int antialiasing = 0, supersampling = 0;
    int img_width, img_height;
    char *generator = 0;
    userval_info_t *userval_info;
    int num_input_drawables = 0;
    gboolean size_is_set = FALSE;
    char *script = NULL;
    char *output_filename;
    gboolean htmldoc = FALSE;
    define_t *defines = NULL;
    int bench_render_count = 1;
    int render_num;
    gboolean bench_no_output = FALSE;
    gboolean bench_no_backend = FALSE;
    int compile_time_limit = DEFAULT_OPTIMIZATION_TIMEOUT;

    for (;;)
    {
	static struct option long_options[] =
	    {
		{ "version", no_argument, 0, OPTION_VERSION },
		{ "help", no_argument, 0, OPTION_HELP },
		{ "intersampling", no_argument, 0, 'i' },
		{ "oversampling", no_argument, 0, 'o' },
		{ "cache", required_argument, 0, 'c' },
		{ "generator", required_argument, 0, 'g' },
		{ "size", required_argument, 0, 's' },
		{ "script-file", required_argument, 0, 'f' },
		{ "htmldoc", no_argument, 0, OPTION_HTMLDOC },
		{ "bench-no-output", no_argument, 0, OPTION_BENCH_NO_OUTPUT },
		{ "bench-only-compile", no_argument, 0, OPTION_BENCH_ONLY_COMPILE },
		{ "bench-no-compile-time-limit", no_argument, 0, OPTION_BENCH_NO_COMPILE_TIME_LIMIT },
		{ "bench-no-backend", no_argument, 0, OPTION_BENCH_NO_BACKEND },
		{ "bench-render-count", required_argument, 0, OPTION_BENCH_RENDER_COUNT },
#ifdef MOVIES
		{ "frames", required_argument, 0, 'F' },
		{ "movie", required_argument, 0, 'M' },
#endif
		{ 0, 0, 0, 0 }
	    };

	int option, option_index;

	option = getopt_long(argc, argv, 
#ifdef MOVIES
			     "f:ioF:D:M:c:g:s:", 
#else
			     "f:ioD:c:g:s:",
#endif
			     long_options, &option_index);

	if (option == -1)
	    break;

	switch (option)
	{
	    case OPTION_VERSION :
		printf("MathMap " MATHMAP_VERSION "\n"
		       "\n"
		       "Copyright (C) 1997-2009 Mark Probst\n"
		       "\n"
		       "This program is free software; you can redistribute it and/or modify\n"
		       "it under the terms of the GNU General Public License as published by\n"
		       "the Free Software Foundation; either version 2 of the License, or\n"
		       "(at your option) any later version.\n"
		       "\n"
		       "This program is distributed in the hope that it will be useful,\n"
		       "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
		       "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
		       "GNU General Public License for more details.\n"
		       "\n"
		       "You should have received a copy of the GNU General Public License\n"
		       "along with this program; if not, write to the Free Software\n"
		       "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n");
		return 0;

	    case OPTION_HELP :
		usage();
		return 0;

	    case OPTION_HTMLDOC :
		htmldoc = TRUE;
		break;

	    case 'f' :
		if (!g_file_get_contents(optarg, &script, NULL, NULL))
		{
		    fprintf(stderr, _("Error: The script file `%s' could not be read.\n"), optarg);
		    return 1;
		}
		break;

	    case 'i' :
		antialiasing = 1;
		break;

	    case 'o' :
		supersampling = 1;
		break;

	    case 'c' :
		cache_size = atoi(optarg);
		assert(cache_size > 0);
		break;

	    case 'D' :
		append_define(optarg, &defines);
		break;

	    case 'I' :
		alloc_cmdline_image_input_drawable(optarg);
		break;

	    case 'g' :
		generator = optarg;
		break;

	    case 's' :
		if (!parse_image_size(optarg, &img_width, &img_height))
		{
		    fprintf(stderr, _("Error: Invalid image size.  Syntax is <width>x<height>.  Example: 1024x768.\n"));
		    exit(1);
		}
		size_is_set = 1;
		break;

	    case OPTION_BENCH_RENDER_COUNT :
		bench_render_count = atoi(optarg);
		break;

	    case OPTION_BENCH_ONLY_COMPILE :
		bench_render_count = 0;
		break;

	    case OPTION_BENCH_NO_OUTPUT :
		bench_no_output = TRUE;
		break;

	    case OPTION_BENCH_NO_COMPILE_TIME_LIMIT :
		compile_time_limit = -1;
		break;

	    case OPTION_BENCH_NO_BACKEND :
		bench_no_backend = TRUE;
		break;

#ifdef MOVIES
	    case 'F' :
		generate_movie = 1;
		num_frames = atoi(optarg);
		assert(num_frames > 0);
		break;

	    case 'M' :
		alloc_cmdline_movie_input_drawable(optarg);
		break;
#endif
	}
    }

    if (script != NULL)
    {
	if (argc - optind != 1)
	{
	    usage();
	    return 1;
	}

	output_filename = argv[optind];
    }
    else
    {
	if (argc - optind != 2)
	{
	    usage();
	    return 1;
	}

	script = argv[optind];
	output_filename = argv[optind + 1];
    }

    init_tags();
    init_builtins();
    init_macros();
    init_compiler();

    if (htmldoc)
    {
	mathmap_t *mathmap = parse_mathmap(script);
	filter_t *filter;
	FILE *out;

	if (mathmap == NULL)
	{
	    fprintf(stderr, _("Error: Could not read MathMap script: %s\n"), error_string);
	    return 1;
	}

	out = fopen(output_filename, "w");
	if (out == NULL)
	{
	    fprintf(stderr, _("Error: Cannot open file `%s' for writing: %s\n"),
		    output_filename, strerror(errno));
	    return 1;
	}

	for (filter = mathmap->filters; filter != NULL; filter = filter->next)
	{
	    if (filter->kind != FILTER_MATHMAP)
		continue;

	    if (!write_filter_html_doc(out, filter->v.mathmap.decl))
		return 1;
	}

	fclose(out);
    }
    else if (generator == 0)
    {
	char *support_paths[4];
	mathmap_t *mathmap;
	mathmap_invocation_t *invocation;
	int current_frame;

	support_paths[0] = g_strdup_printf("%s/mathmap", GIMPDATADIR);
	support_paths[1] = g_strdup_printf("%s/.gimp-2.6/mathmap", getenv("HOME"));
	support_paths[2] = g_strdup_printf("%s/.gimp-2.4/mathmap", getenv("HOME"));
	support_paths[3] = NULL;

	mathmap = compile_mathmap(script, support_paths, compile_time_limit, bench_no_backend);

	if (bench_no_backend)
	    return 0;

	if (mathmap == 0)
	{
	    fprintf(stderr, _("Error: %s\n"), error_string);
	    exit(1);
	}

	if (bench_render_count == 0)
	    return 0;

	if (!size_is_set)
	    for (userval_info = mathmap->main_filter->userval_infos;
		 userval_info != NULL;
		 userval_info = userval_info->next)
	    {
		define_t *define;
		unsigned char *image;

		if (userval_info->type != USERVAL_IMAGE)
		    continue;

		define = lookup_define(defines, userval_info->name);
		if (define == NULL)
		{
		    fprintf(stderr, _("Error: No value defined for input image `%s'.\n"), userval_info->name);
		    return 1;
		}

		image = read_image(define->value, &img_width, &img_height);
		if (image == NULL)
		{
		    fprintf(stderr, _("Error: Could not read input image `%s'.\n"), define->value);
		    return 1;
		}
		free(image);

		size_is_set = TRUE;

		break;
	    }

	if (!size_is_set)
	{
	    fprintf(stderr, _("Error: Image size not set and no input images given.\n"));
	    exit(1);
	}

	invocation = invoke_mathmap(mathmap, NULL, img_width, img_height, TRUE);

	for (userval_info = mathmap->main_filter->userval_infos;
	     userval_info != NULL;
	     userval_info = userval_info->next)
	{
	    userval_t *userval = &invocation->uservals[userval_info->index];
	    define_t *define = lookup_define(defines, userval_info->name);

	    if (define == NULL)
	    {
		if (userval_info->type == USERVAL_IMAGE)
		{
		    fprintf(stderr, _("Error: No value defined for input image `%s'.\n"), userval_info->name);
		    return 1;
		}
	    }
	    else
		switch (userval_info->type)
		{
		    case USERVAL_INT_CONST :
			userval->v.int_const = atoi(define->value);
			break;

		    case USERVAL_FLOAT_CONST :
			userval->v.float_const = g_ascii_strtod(define->value, NULL);
			break;

		    case USERVAL_BOOL_CONST :
			userval->v.bool_const = (float)atoi(define->value);
			break;

		    case USERVAL_IMAGE :
			assign_image_userval_drawable(userval_info, userval,
						      alloc_cmdline_image_input_drawable(define->value));
			++num_input_drawables;
			break;

		    default :
			fprintf(stderr, _("Error: Can only define user values for types int, float, bool and image.\n"));
			return 1;
		}
	}

	for (render_num = 0; render_num < bench_render_count; ++render_num)
	{
#ifdef MOVIES
	    for (i = 0; i < num_input_drawables; ++i)
		if (input_drawables[i].type == DRAWABLE_MOVIE)
		{
		    assert(quicktime_video_width(input_drawables[i].v.movie, 0) == img_width);
		    assert(quicktime_video_height(input_drawables[i].v.movie, 0) == img_height);
		}
#endif

	    invocation_set_antialiasing(invocation, antialiasing);
	    invocation->supersampling = supersampling;

	    invocation->output_bpp = 4;

	    output = (guchar*)malloc((long)invocation->output_bpp * (long)img_width * (long)img_height);
	    assert(output != 0);

#ifdef MOVIES
	    if (generate_movie)
	    {
		output_movie = quicktime_open(output_filename, 0, 1);
		assert(output_movie != 0);

		quicktime_set_video(output_movie, 1, img_width, img_height, 25, QUICKTIME_JPEG);
		assert(quicktime_supported_video(output_movie, 0));
		quicktime_seek_start(output_movie);

		rows = (guchar**)malloc(sizeof(guchar*) * img_height);
		for (i = 0; i < img_height; ++i)
		    rows[i] = output + img_width * invocation->output_bpp * i;
	    }
#endif

	    for (current_frame = 0; current_frame < num_frames; ++current_frame)
	    {
		float current_t = (float)current_frame / (float)num_frames;
		image_t *closure = closure_image_alloc(&invocation->mathfuncs,
						       NULL,
						       invocation->mathmap->main_filter->num_uservals,
						       invocation->uservals,
						       img_width, img_height);
		mathmap_frame_t *frame = invocation_new_frame(invocation, closure,
							      current_frame, current_t);

		call_invocation_parallel_and_join(frame, closure, 0, 0, img_width, img_height, output, 1);

		invocation_free_frame(frame);

#ifdef MOVIES
		if (generate_movie && !bench_no_output)
		{
		    fprintf(stderr, _("writing frame %d\n"), current_frame);
		    assert(quicktime_encode_video(output_movie, rows, 0) == 0);
		}
#endif

		closure_image_free(closure);
	    }

	    if (!bench_no_output)
	    {
#ifdef MOVIES
		if (generate_movie)
		    quicktime_close(output_movie);
		else
#endif
		    write_image(output_filename, img_width, img_height, output,
				invocation->output_bpp, img_width * invocation->output_bpp, IMAGE_FORMAT_PNG);
	    }

	    free(output);
	}
    }
    else
    {
	if (strcmp(generator, "blender") == 0)
	{
	    if (!blender_generate_plug_in(script, output_filename))
		return 1;
	}
	/*
	else if (strcmp(generator, "pixeltree") == 0)
	{
	    if (!pixeltree_generate_plug_in(argv[optind], argv[optind + 1]))
		return 1;
	}
	*/
	else
	{
	    fprintf(stderr, _("Unknown generator `%s'\n"), generator);
	    return 1;
	}
    }

    return 0;
}