grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Pre-alpha scripting engine


From: Serbinenko Vladimir
Subject: Pre-alpha scripting engine
Date: Fri, 14 Jan 2005 19:48:07 +0100
User-agent: Mozilla Thunderbird 1.0 (X11/20041206)

Pre-alpha version of my script engine is ready.
Use this version at your own risk: it's *pre-alpha* without any warrantee. Now it's for developpers and for discussions, not for end user I compiled it independetly from GRUB 2: I have it in ~/grub2mod and grub2 sources are under ~/grub2 but it's easy to integrate to grub2 source tree.
Known bugs:
buggy line counting and error handling. I'll fix it.
Function extentions support is not yet tested
---------------------------------------------------------
To compile execute
>make compile
To invoke
Testing under OS:
./script <script file>
With GRUB 2:
insmod <script module>
script <script file>
----------------------------------------------------------
Script syntax description:
I took PHP-syntax as a base
All variables must begin with $ e.g $var
For now all script files must be made of functions and nothing except functions. All other will be ignored. Function must be declared as: function [global] <function name>([$arg1[=defval1]][,$arg2[=defval2]][,...]){
   <function body here>
}
global means that function will be accessible from other scripts. Additional passed arguments will be ignored. Not passed arguments without default value will have value VOID(see below)
Function can return value with return:
   return [value];
if no return used or used return without value VOID is returned
At start of script function script_load is invoked
Function invoking:
First syntax
<function name>(<parameters>)
Second syntax $variable(<parameters>) will invoked function which name is contained in $variable
Printing is made with echo command
Loops:
Now for, while,do...while,break and continue keywords are supported(see PHP or C documentation)
Types:
No type control, automatic type conversion
Supported types:
int
bool can be TRUE or FALSE
str C-like unlimited string
void can be only VOID(NULL is an alias to VOID) It means uninitialized value
Vars:
vars must begin with $: $i means variable named "i"
There are three var scopes:local,global and superglobal
local means that it can be accessed only from same function, global only from same file, superglobal from any file.
to make var global or superglobal use:
   <global|superglobal> <var>[=value];
Expressions:
Now operators
{}, !, ~, ++, --, (bool), (str), (int), -(unary and binary), +(unary and binary), *, /, %, ., >>,<<,<=,<,>=,>, ===,!==, ==,!=,<>, & (binary only), ^, |, &&, ||, ? :, =, +=,-=,*=, /=,%=, &=, ^=,|=,>>=,<<=, .=,
and,xor,or, ","
are supported. For more information see PHP documentation.
Notes:
{} is not lvalue e.g: You can *not* use $var{$i}='x';
Spaces in (type) are not supported,
/ gives an int
String can be in single or double quotes ('string' or "string"). They are parsed like in PHP bu for now no variables in strings are supported.
Comments: /* */ and // are supported
-------------------------------------------------------------------------------
How to develop function extentions:
function extention must be grub2 module
You have to use script.h
Functions must be like
struct script_var* script_fn(struct script_args*args,struct script *scr,struct script_env*env); Where args are passed arguments, scr is current file,env is current local envinronment (see script.h) You must free all arguments passed that are marked with 1 in freeitarray. All variables are passed by link. Function must always return a value(if you not really need to do it return VOID var type ex:
   return script_create_var();
)
To create value use script_create_var, to free script_free_var, to create string script_newstr
--------------------------------------------------------------------------------
Please report bugs me back
Discussions:
Roadmap: what to do, priorities, ... (see TODO but I rhink that it will good idea if I'll develop it as I created it) Arrays:will it be good idea to use associative arrays. If yes what variable types can be used as indexes and type conversions e.g. is $array[0] and $array["0"] or $array[TRUE] and $array["TRUE"] the same thing, ... If you have any suggestions don't hesitate to tell it me. You can do it by email or at irc.gnu.org- I'm vovas
--------------example script: test.grb----------------------------------
//<?php
//hello
function hello($arg="me"){
   $a=2*3-5;
   $a++;
   $a.="
";
   return "Hello, ".$arg." ".$a;
}
function scndfnc(&$var,$fnc){
   $var=-5;
   $var*=3;
   echo "Function ".$fnc." passed\n";
   echo $fnc("from scndfunc");
   return;
}
function script_load(){
   {
       echo hello ("you");
       echo hello();
   }
   scndfnc($t,"hello");
   echo ( TRUE || ($t=3) )."\n";
   echo '$t='.$t."\ncorrect:".(($t==-15)?"Ok":"Script problem")."\n";
   if($t==-14)
       echo "works uncorrectly\n";
   elseif($t==-15)
       echo "All is ok!\n";
   else
       echo "if problem\n";
   echo "After if\n";
   $i=0;
   while($i<5){
       if($i%2)
           echo $i." is even\n";
       else
           echo $i." is odd\n";
       $i++;
   }
   echo "After while\n";
   for($i=2;$i<=9;$i++){
       for($j=2;$j<=9;$j++)
           echo $i."x".$j."=".$i*$j." ".(($i*$j<10)?" ":"");
       echo "\n";
   }
   echo "After for\n";
   while(1){
       echo "Break test\n";
       break;
   }
   for($i=0;$i<4;$i++){
       echo "continue test:\$i=".$i."\n";
       continue;
       echo "Must not reach here\n";
   }
   $i=0;
   do{
       echo "Do: \$i=".++$i."\n";
   }while ($i<6);
   echo "After do\n";
}
// ?>
/**************/
----------------------Header: script.h-------------------------------------
#ifndef SCRIPT_H
#define SCRIPT_H
#ifdef SCRIPT_EMU
#include <scriptemu.h>
#include <scriptemu.c>
#else
#include <grub/types.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/dl.h>
#include <grub/normal.h>
#include <grub/file.h>
#include <grub/err.h>
#define NULL 0
#endif

#define RES_FUNCS 40
#define MAX_GLOBFUNC 200

#define MAXFUNCNAMELEN 30
#define MAXVARNAMELEN 30

#define SCRIPT_ERR_UNEXPECTED 1
#define SCRIPT_ERR_INVALID_TYPE 2
#define SCRIPT_ERR_FUNCUNFOUND 3

struct script_function{
   int beg,end,argsfrom,argsto,namefrom,nameto;
};

struct funclink{
   char *name;
   struct script*insscr;
   int num;
};

enum script_var_type{SCRIPT_VAR_TYPE_INT,SCRIPT_VAR_TYPE_BOOL,SCRIPT_VAR_TYPE_STR,SCRIPT_VAR_TYPE_VOID};

struct script_var{
   union{
       int intval;
       char*strval;
   };
   enum script_var_type type;
};

struct script_env{
   int num_vars,sumlen;
   char *names;
   struct script_var**vars;
};

struct script {
   char*body;
   unsigned bodylen;
   unsigned numfuncs;
   unsigned curline;
   unsigned errno;
   struct script_function funcs[RES_FUNCS];
   struct funclink f_list[RES_FUNCS];
   struct script_env *globenv;
};



#define SCRIPT_BRACK 0
#define SCRIPT_LEFT 1
#define SCRIPT_RIGHT 2
#define SCRIPT_BIN 3
#define SCRIPT_TERN 4
#define SCRIPT_AND 5
#define SCRIPT_OR 6
#define SCRIPT_LEFTS SCRIPT_LEFT
#define SCRIPT_ARGPART 7
#define SCRIPT_LVALUE 8
#define SCRIPT_RASSOC 16
#define SCRIPT_NEEDLVALUEA 16

#define SCRIPT_STR_SIZE 256

#define MAX_ARGS 20

struct script_oper{
   int priority;
   char seq[6];
   int type;
struct script_var* (*func_do)(struct script_var*a,struct script_var*b,int opn,struct script *scr);
};

struct script_args {
   struct script_var* passed[MAX_ARGS];
   int number;
   char freeit[MAX_ARGS];
};

struct ext_func{
   char name[MAXFUNCNAMELEN];
struct script_var* (*script_fn)(struct script_args*,struct script *,struct script_env*);
};

enum script_retstatus {SCRIPT_NORM,SCRIPT_CONTINUE,SCRIPT_BREAK,SCRIPT_RET};

extern struct script_oper script_opers[];
extern struct funclink globfuncs[MAX_GLOBFUNC];
extern struct ext_func *script_exts;
extern struct script_env script_superglobenv;
extern unsigned globfunccount;
extern unsigned script_exts_count;

struct script_var *script_eval_expr(char*exp,struct script_env*env,int*mustfreed,struct script*scr);
struct script_var*script_create_var(void);
int script_find_pas(char cbeg,char cend,char *str);
int script_parse_func(struct script *scr, int i);
void script_init_var(struct script_var*var);
struct script_var* script_find_var(char* name, struct script_env*env,struct script*scr);
struct script_env* script_new_env(void);
void script_var_cpy(struct script_var*to,struct script_var*from);
unsigned long script_strtoul (const char *str, char **end, int base);
long script_strtol (const char *str, char **end, int base);
struct script_var* script_new_var(char* name, struct script_env*env,struct script*scr ); struct script_var* script_register_var(char* name,struct script_var*var, struct script_env*env,struct script*scr);
struct script_env* script_new_env(void);
int script_islexend(char c);
int script_get_strend(char*str);
struct script_var*script_get_int(char*exp,int *i);
void script_free_var(struct script_var*tofr);

struct script_var*script_toint(struct script_var*a, struct script *scr);
struct script_var*script_tobool(struct script_var*a, struct script *scr);
struct script_var*script_tostr(struct script_var*a,struct script *scr);

int script_var_cmp(struct script_var*a,struct script_var*b,struct script *scr);
struct script_var*script_newstr(void);
int script_find_oper(char*exp,int searchleft);
int script_get_var_name(char*wh,char*to,struct script_env*env,struct script *scr);
int script_get_operend(char*exp);
struct script_var* script_execute(struct script*scr,struct script_env*env,int beg,int end, enum script_retstatus*status);
void script_free_env(struct script_env*env,int skip);
void script_free_args(struct script_args*args);
struct script_args* script_parse_args(char*exp,int*i,struct script_env*env,struct script*scr); struct script_var *script_exec_func(char*fname,struct script_args*args,struct script *scr, struct script_env*env ); struct script_var*script_get_singlestring(char*from,int*i,struct script*scr); struct script_var*script_get_doublestring(char*from,int*i,struct script_env*env,struct script*scr); struct script_var*script_get_var(char*exp,int*i,struct script_env*lenv,struct script*scr);

grub_err_t script_launch(char*file);
int script_register_ext_func(char*name,struct script_var* (*fn)(struct script_args*,struct script *,struct script_env*));
int script_unregister_ext_func(char*name);
#endif

----------------------------under os: scriptemu.c-------------------------------
grub_err_t
grub_error (grub_err_t n, const char *fmt, ...)
{
 va_list ap;
 int s;

 va_start (ap, fmt);
 printf("Error %d:",n);
 vprintf ( fmt, ap);
 scanf("%i\n",&s);
 va_end (ap);

 return n;
}

----------------------------------------scriptemu.h------------------------------------------
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <grub/err.h>
#define grub_isspace isspace
#define grub_realloc realloc
#define grub_malloc malloc
#define grub_tolower tolower
#define grub_isalpha isalpha
#define grub_isdigit isdigit
#define grub_printf printf
#define grub_strcmp strcmp
#define grub_memcpy memcpy
#define grub_memcmp memcmp
#define grub_strlen strlen
#define grub_free free
#define grub_sprintf sprintf

----------------------------------Makefile----------------------------------------------------------
floppy: compile
   mount /mnt/floppy
   cp ./*.mod ./test.grb /mnt/floppy
   umount /mnt/floppy

compile:script.mod script
   echo "done"
script: script.c scriptemu.c scriptemu.h
   gcc ./script.c -DSCRIPT_EMU -I. -I../grub2/include/ -g -o ./script

%.mod: %.c
gcc -I. -Iinclude -I../grub2/include -W -Wall -Wmissing-prototypes -W -Wshadow -Wpointer-arith \ -Wundef -g -Os -falign-jumps=1 -falign-loops=1 -falign-functions=1 -fno-builtin -mrtd -mregparm=3 -c -o $<.o $<
   ld -r -o $@ $<.o
strip --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $@

----------------------main source file--------------------------------------------------------------
/* script.c - script engine */
/*
*  GRUB  --  GRand Unified Bootloader
*  Copyright (C) 2003  Free Software Foundation, Inc.
*  Copyright (C) 2003  NIIBE Yutaka <address@hidden>
*
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/* TODO:
alpha:
test extentions support
error handling and line numbers

beta:
control structures switch include
vars in ""
arrays
hooks
 constants
your suggestions?

gamma:
goto
{} as lvalue
variable variables
spaces support in (type) e.g. (   type  )=(type)
binary operators with strings
arithmetic with strings
float
classes
code clean up
Perhaps: make func(otherfunc) make equivalent to func("otherfunc")
Perhaps: operators sizeof , @, ` `
print and echo as operators
your suggestions?

Release:
your suggestions?
*/
#include <script.h>

struct funclink globfuncs[MAX_GLOBFUNC];
struct ext_func preexts[]={{.name="",.script_fn=NULL}};
struct ext_func *script_exts=preexts;
struct script_env script_superglobenv={.names="",.num_vars=0,.vars=NULL,.sumlen=0};

unsigned globfunccount=0;
unsigned script_exts_count=0;

struct script_var*script_create_var(){
   struct script_var*rtval=grub_malloc(sizeof(struct script_var));
   script_init_var(rtval);
   return rtval;
}

unsigned long
script_strtoul (const char *str, char **end, int base)
{
 unsigned long num = 0;
 int found = 0;

 /* Skip white spaces.  */
 while (*str && grub_isspace (*str))
   str++;

 /* Guess the base, if not specified. The prefix `0x' means 16, and
    the prefix `0' means 8.  */
 if (str[0] == '0')
   {
     if (str[1] == 'x')
   {
     if (base == 0 || base == 16)
       {
         base = 16;
         str += 2;
       }
   }
     else if (str[1] >= '0' && str[1] <= '7')
   base = 8;
   }

 if (base == 0)
   base = 10;

 while (*str)
   {
     unsigned long digit;
     digit = grub_tolower (*str) - '0';
     if(*str<'0')
         break;
     if (digit > 9)
   {
     digit += '0' - 'a' + 10;
     if (digit >= (unsigned long) base || *str<'a')
       break;
   }
   if (digit >= (unsigned long) base)
       break;
     found = 1;
if (num > (~0UL - digit) / base)
   {
     grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow is detected");
     return 0;
   }

     num = num * base + digit;
     str++;
   }

 if (! found)
   {
     grub_error (GRUB_ERR_BAD_NUMBER, "unrecognized number");
     return 0;
   }

 if (end)
   *end = (char *) str;

 return num;
}

static int script_isspace_wline(char c,struct script *scr){
   if(c=='\n')
       scr->curline++;
   return grub_isspace(c);
}

int script_islexend(char c){
   return !c || (!grub_isalpha(c) && !grub_isdigit(c) && c!='_');
}

int script_find_pas(char cbeg,char cend,char *str){
   int op=1,i;
   for(i=0;op&&str[i];i++){
       if(str[i]=='"' || str[i]=='\''){
           i+=script_get_strend(str+i);
           continue;
       }
       if(str[i]==cbeg)op++;
       if(str[i]==cend)op--;
   }
   return i-1;
}

int script_parse_func(struct script *scr, int i){
   int global=0,was_id=0;char c;
   do{
       was_id=0;
       while(script_isspace_wline(scr->body[i],scr))i++;
       scr->funcs[scr->numfuncs].namefrom=i;
while(!script_islexend(scr->body[i])){if(scr->body[i]=='\n')scr->curline++;i++;}
       c=scr->body[i];
       scr->body[i]=0;
if(!grub_strcmp(scr->body+scr->funcs[scr->numfuncs].namefrom,"global")){
           global=1;
           was_id=1;
       }
       scr->body[i]=c;
       scr->funcs[scr->numfuncs].nameto=i;
   }while(was_id);
   while(script_isspace_wline(scr->body[i],scr))i++;
   if(scr->body[i]!='('){
grub_error(GRUB_ERR_BAD_ARGUMENT,"Parse error: unexpected '%c', '(' expected on line %d ",scr->body[i],scr->curline);
       return scr->bodylen;
   }
   scr->body[i]=0;
   scr->funcs[scr->numfuncs].argsfrom=++i;
   i+=script_find_pas('(',')',scr->body+i);
   scr->funcs[scr->numfuncs].argsto=i;
   scr->body[i]=0;
   i++;
   while(script_isspace_wline(scr->body[i],scr))i++;
   if(scr->body[i]!='{'){
grub_error(GRUB_ERR_BAD_ARGUMENT,"Parse error: unexpected '%c', '{' expected on line %d",scr->body[i],scr->curline);
       return scr->bodylen;
   }
   scr->funcs[scr->numfuncs].beg=++i;
   i+=script_find_pas('{','}',scr->body+i);
scr->funcs[scr->numfuncs].end=i; scr->body[i]=0; scr->f_list[scr->numfuncs].name=scr->body+scr->funcs[scr->numfuncs].namefrom;
   scr->f_list[scr->numfuncs].insscr=scr;
   scr->f_list[scr->numfuncs].num=scr->numfuncs;
   if(global)
grub_memcpy(&(globfuncs[globfunccount++]),&(scr->f_list[scr->numfuncs]),sizeof(struct funclink));
   scr->numfuncs++;
   return ++i;
}

void script_init_var(struct script_var*var){
   var->intval=0;
   var->type=SCRIPT_VAR_TYPE_VOID;
}

struct script_var* script_find_var(char* name, struct script_env*env,struct script*scr __attribute__ ((unused))){
   int i;char*ptr=env->names;
   for(i=0;i<env->num_vars;i++)
       if(!grub_strcmp(ptr,name))
           break;
       else
           ptr+=grub_strlen(ptr)+1;
   if(i==env->num_vars)
       return NULL;
   return env->vars[i];
}

struct script_var* script_new_var(char* name, struct script_env*env,struct script*scr __attribute__ ((unused))){
   struct script_var*fnd=script_find_var(name,env,scr);int oldlen;
   if(fnd)
       return fnd;
   oldlen=env->sumlen;
   env->sumlen+=grub_strlen(name)+1;
   env->names=grub_realloc(env->names,env->sumlen);
   grub_memcpy(env->names+oldlen,name,env->sumlen-oldlen);
   env->num_vars++;
env->vars=grub_realloc(env->vars,env->num_vars*sizeof(struct script_var*));
   env->vars[env->num_vars-1]=script_create_var();
   return env->vars[env->num_vars-1];
}
struct script_var* script_register_var(char* name,struct script_var*var, struct script_env*env,struct script*scr __attribute__ ((unused))){
   struct script_var*fnd=script_find_var(name,env,scr);int oldlen;
   if(fnd)
       return fnd;
   oldlen=env->sumlen;
   env->sumlen+=grub_strlen(name)+1;
   env->names=grub_realloc(env->names,env->sumlen);
   grub_memcpy(env->names+oldlen,name,env->sumlen-oldlen);
   env->num_vars++;
env->vars=grub_realloc(env->vars,env->num_vars*sizeof(struct script_var*));
   env->vars[env->num_vars-1]=var;
   return env->vars[env->num_vars-1];
}

struct script_env* script_new_env(){
   struct script_env*rtval=grub_malloc(sizeof(struct script_env));
   rtval->num_vars=0;
   rtval->names=grub_malloc(1);
   rtval->names[0]=0;
   rtval->sumlen=0;
   rtval->vars=NULL;
   return rtval;
}

static void script_parse_funcs(struct script *scr){
 unsigned i;
 scr->numfuncs=0;
 scr->curline=1;
 scr->errno=0;
 scr->globenv=script_new_env();
 for(i=0;i<scr->bodylen-(sizeof("function")-1);i++){
     if(scr->body[i]=='\n')
       scr->curline++;
   if(!grub_memcmp(scr->body+i,"function",sizeof("function")-1) &&
( ( i==0|| script_islexend(scr->body[i-1]))&& script_islexend(scr->body[i+sizeof("function")-1]) ))
           i=script_parse_func(scr,i+sizeof("function"))-1;
 }
 scr->curline=1;
}

static void script_remove_comments(struct script *scr){
   unsigned i,j,delta=0,origlen=scr->bodylen,k,nlcount;
   for(i=0;i<scr->bodylen;i++,scr->body[i]=scr->body[i+delta]){
       if((scr->body[i]=='*')&&(i!=0)&&(scr->body[i-1]=='/')){
           nlcount=0;
for(j=i+delta+1;!(((scr->body[j]=='/') && (scr->body[j-1]=='*'))||(j>origlen));j++)
               if(scr->body[j]=='\n')nlcount++;
           i-=2;
           k=i+nlcount;
           for(;i<k;i++)
               scr->body[i]='\n';
           delta=j-i-nlcount;
           scr->bodylen=origlen-delta;
           continue;
       }
       if((scr->body[i]=='/')&&(i!=0)&&(scr->body[i-1]=='/')){
           nlcount=0;
           for(j=i+delta+1;!((scr->body[j]=='\n')||(j>origlen));j++)
               if(scr->body[j]=='\n')nlcount++;
           i-=2;
           k=i+nlcount;
           for(;i<k;i++)
               scr->body[i]='\n';
           delta=j-i-nlcount;
           scr->bodylen=origlen-delta;
           continue;
       }
   }
}

long script_strtol (const char *str, char **end, int base){
   unsigned i=0;
   while(grub_isspace(str[i]))i++;
   if(str[i]=='-')
       return -script_strtoul(str+i+1,end,base);
   else
       return script_strtoul(str+i,end,base);
}

struct script_var*script_get_int(char*exp,int *i){
   char*end;
   struct script_var*rtval=script_create_var();
   rtval->type=SCRIPT_VAR_TYPE_INT;
   rtval->intval=script_strtol(exp+*i,&end,0);
   *i=end-exp;
   return rtval;
}

void script_free_var(struct script_var*tofr){
   if(tofr->type==SCRIPT_VAR_TYPE_STR)
       grub_free(tofr->strval);
   tofr->type=SCRIPT_VAR_TYPE_VOID;
   grub_free(tofr);
}

struct script_var*script_toint(struct script_var*a, struct script *scr){
   char *end;
   struct script_var *rtval=script_create_var();
   grub_memcpy(rtval,a,sizeof(struct script_var));
   if(rtval->type==SCRIPT_VAR_TYPE_STR){
       rtval->intval=script_strtol(rtval->strval,&end,0);
       rtval->type=SCRIPT_VAR_TYPE_INT;
   }
   if(rtval->type==SCRIPT_VAR_TYPE_BOOL){
       rtval->intval=rtval->intval;
       rtval->type=SCRIPT_VAR_TYPE_INT;
   }
   if(rtval->type==SCRIPT_VAR_TYPE_VOID){
grub_printf("Warning: using uninitialized variable at line %d",scr->curline);
       rtval->intval=0;
rtval->type=SCRIPT_VAR_TYPE_INT; } return rtval; }

struct script_var*script_tobool(struct script_var*a, struct script *scr){
   struct script_var *rtval=script_create_var();
   grub_memcpy(rtval,a,sizeof(struct script_var));
   if(rtval->type==SCRIPT_VAR_TYPE_STR){
rtval->intval=!(!grub_strcmp(rtval->strval,"")||!grub_strcmp(rtval->strval,"FALSE")||!grub_strcmp(rtval->strval,"0"));
       rtval->type=SCRIPT_VAR_TYPE_BOOL;
   }
   if(rtval->type==SCRIPT_VAR_TYPE_INT){
       rtval->intval=!!rtval->intval;
       rtval->type=SCRIPT_VAR_TYPE_BOOL;
   }
   if(rtval->type==SCRIPT_VAR_TYPE_VOID){
grub_printf("Warning: using uninitialized variable at line %d",scr->curline);
       rtval->intval=0;
       rtval->type=SCRIPT_VAR_TYPE_BOOL;
   }
return rtval; }

static struct script_var*script_tointop( struct script_var*a,struct script_var*b __attribute__ ((unused)), int opn __attribute__ ((unused)),struct script *scr){
   return script_toint(a,scr);
}

static struct script_var*script_toboolop( struct script_var*a,struct script_var*b __attribute__ ((unused)), int opn __attribute__ ((unused)),struct script *scr){
   return script_tobool(a,scr);
}

struct script_var*script_newstr(){
   char *str=grub_malloc(SCRIPT_STR_SIZE);
   struct script_var *rtval=script_create_var();
   rtval->strval=str;
   rtval->type=SCRIPT_VAR_TYPE_STR;
   return rtval;
}

struct script_var*script_tostr(struct script_var*a,struct script *scr){
   char*tstr;
   struct script_var *rtval=script_newstr();
   if(a->type==SCRIPT_VAR_TYPE_STR)
       script_var_cpy(rtval,a);
   if(a->type==SCRIPT_VAR_TYPE_INT){
       tstr=rtval->strval;
       int tcnv=a->intval;
       if(tcnv<0){
           tcnv=-tcnv;
           tstr[0]='-';
           tstr++;
       }
       grub_sprintf(tstr,"%d",tcnv);
       rtval->type=SCRIPT_VAR_TYPE_STR;
   }
   if(a->type==SCRIPT_VAR_TYPE_BOOL){
       if(a->intval)
           grub_memcpy(rtval->strval,"TRUE",sizeof("TRUE"));
       else
           grub_memcpy(rtval->strval,"FALSE",sizeof("FALSE"));
       rtval->type=SCRIPT_VAR_TYPE_STR;
   }
   if(a->type==SCRIPT_VAR_TYPE_VOID){
grub_printf("Warning: using uninitialized variable at line %d",scr->curline);
       rtval->strval[0]=0;
       rtval->type=SCRIPT_VAR_TYPE_STR;
} return rtval; }

static struct script_var*script_tostrop( struct script_var*a,struct script_var*b __attribute__ ((unused)), int opn __attribute__ ((unused)),struct script *scr){
   return script_tostr(a,scr);
}

static struct script_var*script_elemarray(struct script_var*a,struct script_var*b,int opn __attribute__ ((unused)),struct script *scr){
}

static struct script_var*script_char_str(struct script_var*a,struct script_var*b,int opn __attribute__ ((unused)),struct script *scr){
   struct script_var*rtval=script_newstr(),*z=script_toint(b,scr);
   if(a->type!=SCRIPT_VAR_TYPE_STR){
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: can't use {} with a notstring at line %d",scr->curline);
       scr->errno=SCRIPT_ERR_INVALID_TYPE;
       return NULL;
   }
   rtval->strval[1]=0;
   if(z->intval<0 || (unsigned)z->intval>=grub_strlen(a->strval) )
       rtval->strval[0]=0;
   else
       rtval->strval[0]=a->strval[z->intval];
   script_free_var(z);
   return rtval;
}

static struct script_var* script_bool_not( struct script_var*a,struct script_var*b __attribute__ ((unused)),int opn __attribute__ ((unused)),
                           struct script *scr __attribute__ ((unused))){
   struct script_var *rtval=script_tobool(a,scr);
   if(rtval->type==SCRIPT_VAR_TYPE_BOOL)
       rtval->intval=!rtval->intval;
   return rtval;
}

static struct script_var* script_bin_not( struct script_var*a,struct script_var*b __attribute__ ((unused)),int opn __attribute__ ((unused)),
                           struct script *scr __attribute__ ((unused))){
   struct script_var *rtval=script_toint(a,scr);
   if(rtval->type==SCRIPT_VAR_TYPE_INT)
       rtval->intval=~rtval->intval;
   return rtval;
}
static struct script_var* script_neg( struct script_var*a,struct script_var*b __attribute__ ((unused)),int opn __attribute__ ((unused)),
                           struct script *scr __attribute__ ((unused))){
   struct script_var *rtval=script_toint(a,scr);
   if(rtval->type==SCRIPT_VAR_TYPE_INT)
       rtval->intval=-rtval->intval;
   return rtval;
}
static struct script_var* script_pos( struct script_var*a,struct script_var*b __attribute__ ((unused)),int opn __attribute__ ((unused)),
                           struct script *scr __attribute__ ((unused))){
   struct script_var *rtval=script_toint(a,scr);
   if(rtval->type==SCRIPT_VAR_TYPE_INT)
       rtval->intval=rtval->intval;
   return rtval;
}
static struct script_var* script_indecl(struct script_var*a,struct script_var*b __attribute__ ((unused)),int opn ,struct script *scr){
   if(a->type!=SCRIPT_VAR_TYPE_INT){
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: can't increment or decrement a not integer value at line %d",scr->curline);
       scr->errno=SCRIPT_ERR_INVALID_TYPE;
       return NULL;
   }
   switch(script_opers[opn].seq[0]){
   case '-':
       a->intval=a->intval--;
       break;
   case '+':
       a->intval=a->intval++;
       break;
   }
   struct script_var *rtval=script_create_var();
   script_var_cpy(rtval,a);
   return rtval;
}
static struct script_var* script_indecr(struct script_var*a,struct script_var*b __attribute__ ((unused)),int opn ,struct script *scr){
   if(a->type!=SCRIPT_VAR_TYPE_INT){
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: can't increment or decrement a not integer value at line %d",scr->curline);
       scr->errno=SCRIPT_ERR_INVALID_TYPE;
       return NULL;
   }
   struct script_var *rtval=script_create_var();
   script_var_cpy(rtval,a);
   switch(script_opers[opn].seq[0]){
   case '-':
       a->intval=a->intval--;
       break;
   case '+':
       a->intval=a->intval++;
       break;
   }
   return rtval;
}

static struct script_var* script_arith(struct script_var*a,struct script_var*b,int opn,struct script *scr){
   struct script_var *rtval=script_toint(a,scr);
   struct script_var *sc=script_toint(b,scr);
   switch(script_opers[opn].seq[0]){
   case '*':
       rtval->intval*=sc->intval;
       break;
   case '/':
       rtval->intval/=sc->intval;
       break;
   case '%':
       rtval->intval%=sc->intval;
       break;
   case '+':
       rtval->intval+=sc->intval;
       break;
   case '-':
       rtval->intval-=sc->intval;
       break;
   }
   script_free_var(sc);
   return rtval;
}
static struct script_var* script_concat(struct script_var*a,struct script_var*b,int opn __attribute__ ((unused)),struct script *scr){
   struct script_var *rtval=script_tostr(a,scr);
   struct script_var *sc=script_tostr(b,scr);
   int i;
   int delta=grub_strlen(rtval->strval);
   for(i=delta;sc->strval[i-delta];i++){
       if((i+1)%SCRIPT_STR_SIZE==0)
           rtval->strval=grub_realloc(rtval->strval,i+1+SCRIPT_STR_SIZE);
       rtval->strval[i]=sc->strval[i-delta];
   }
   rtval->strval[i]=0;
   script_free_var(sc);
   return rtval;
}
static struct script_var* script_binmove(struct script_var*a,struct script_var*b,int opn,struct script *scr){
   struct script_var *rtval=script_toint(a,scr);
   struct script_var *sc=script_toint(b,scr);
   switch(script_opers[opn].seq[0]){
   case '<':
       rtval->intval<<=sc->intval;
       break;
   case '>':
       rtval->intval>>=sc->intval;
       break;
   }
   script_free_var(sc);
   return rtval;
}
int script_var_cmp(struct script_var*a,struct script_var*b,struct script *scr){
   if(a->type==SCRIPT_VAR_TYPE_INT || b->type==SCRIPT_VAR_TYPE_INT){
       struct script_var *fst=script_toint(a,scr);
       struct script_var *sc=script_toint(b,scr);
       int rtval;
       rtval=fst->intval-sc->intval;
       script_free_var(fst);
       script_free_var(sc);
       return rtval;
   }
   if(a->type==SCRIPT_VAR_TYPE_STR && b->type==SCRIPT_VAR_TYPE_STR){
       return grub_strcmp(a->strval,b->strval);
   }
   {
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: incorrect types in comparsition %d",scr->curline);
       scr->errno=SCRIPT_ERR_INVALID_TYPE;
       return 0;
   }
}
static struct script_var* script_cmpop(struct script_var*a,struct script_var*b,int opn,struct script *scr){
   struct script_var*rtval=script_create_var();
   int cmpval=script_var_cmp(a,b,scr);
   rtval->type=SCRIPT_VAR_TYPE_BOOL;
   if(script_opers[opn].seq[1]=='=' && cmpval==0){
       rtval->intval=1;
       return rtval;
   }
   if(script_opers[opn].seq[0]=='<')
       rtval->intval=(cmpval<0);
   else
       rtval->intval=(cmpval>0);
   return rtval;
}
static struct script_var* script_eqop(struct script_var*a,struct script_var*b,int opn ,struct script *scr){
   struct script_var*rtval=script_create_var();
   int cnt=1;
   rtval->type=SCRIPT_VAR_TYPE_BOOL;
   if(script_opers[opn].seq[2]=='=' && a->type!=b->type)
       cnt=0;
   if(cnt && script_var_cmp(a,b,scr)!=0)
       cnt=0;
   if(script_opers[opn].seq[0]=='!' || script_opers[opn].seq[0]=='<')
       cnt=!cnt;
   rtval->intval=cnt;
   return rtval;
}
static struct script_var* script_bin(struct script_var*a,struct script_var*b,int opn,struct script *scr){
   struct script_var *rtval=script_toint(a,scr);
   struct script_var *sc=script_toint(b,scr);
   switch(script_opers[opn].seq[0]){
   case '^':
       rtval->intval^=sc->intval;
       break;
   case '|':
       rtval->intval|=sc->intval;
       break;
   case '&':
       rtval->intval&=sc->intval;
       break;
   }
   script_free_var(sc);
   return rtval;
}
static struct script_var* script_logicxor(struct script_var*a,struct script_var*b,int opn __attribute__ ((unused)),struct script *scr){
   struct script_var *rtval=script_tobool(a,scr);
   struct script_var *sc=script_tobool(b,scr);
   rtval->intval=(!((!rtval->intval)==(!sc->intval)));
   script_free_var(sc);
   return rtval;
}
static struct script_var* script_comma( struct script_var*a __attribute__ ((unused)),struct script_var*b, int opn __attribute__ ((unused)),struct script *scr __attribute__ ((unused))){
   struct script_var*rtval=script_create_var();
   script_var_cpy(rtval,b);
   return rtval;
}
static struct script_var* script_set( struct script_var*a, struct script_var*b,int opn __attribute__ ((unused)),
                           struct script *scr __attribute__ ((unused))){
   script_var_cpy(a,b);
   return a;
}
static struct script_var* script_setarith(struct script_var*a, struct script_var*b,int opn,struct script *scr){
   struct script_var*val=script_arith(a,b,opn,scr),*rtval;
   rtval=script_set(a,val,opn,scr);
   script_free_var(val);
   return rtval;
}
static struct script_var* script_setbin(struct script_var*a, struct script_var*b,int opn,struct script *scr){
   struct script_var*val=script_bin(a,b,opn,scr),*rtval;
   rtval=script_set(a,val,opn,scr);
   script_free_var(val);
   return rtval;
}
static struct script_var* script_setmove(struct script_var*a, struct script_var*b,int opn,struct script *scr){
   struct script_var*val=script_binmove(a,b,opn,scr),*rtval;
   rtval=script_set(a,val,opn,scr);
   script_free_var(val);
   return rtval;
}
static struct script_var* script_setconcat(struct script_var*a, struct script_var*b,int opn,struct script *scr){
   struct script_var*val=script_concat(a,b,opn,scr),*rtval;
   rtval=script_set(a,val,opn,scr);
   script_free_var(val);
   return rtval;
}
struct script_oper script_opers[]={
{.priority=190, .seq="[", .func_do=script_elemarray, .type=SCRIPT_BRACK|SCRIPT_LVALUE},
{.priority=190, .seq="{", .func_do=script_char_str, .type=SCRIPT_BRACK},
{.priority=180, .seq="!", .func_do=script_bool_not, .type=SCRIPT_LEFT|SCRIPT_RASSOC}, {.priority=180, .seq="~", .func_do=script_bin_not, .type=SCRIPT_LEFT|SCRIPT_RASSOC}, {.priority=180, .seq="++", .func_do=script_indecl, .type=SCRIPT_LEFT|SCRIPT_NEEDLVALUEA}, {.priority=180, .seq="++", .func_do=script_indecr, .type=SCRIPT_RIGHT|SCRIPT_NEEDLVALUEA}, {.priority=180, .seq="--", .func_do=script_indecl, .type=SCRIPT_LEFT|SCRIPT_NEEDLVALUEA|SCRIPT_RASSOC}, {.priority=180, .seq="--", .func_do=script_indecr, .type=SCRIPT_RIGHT|SCRIPT_NEEDLVALUEA|SCRIPT_RASSOC}, {.priority=180, .seq="(int)", .func_do=script_tointop, .type=SCRIPT_LEFT|SCRIPT_RASSOC}, {.priority=180, .seq="(str)", .func_do=script_tostrop, .type=SCRIPT_LEFT|SCRIPT_RASSOC}, {.priority=180, .seq="(bool)", .func_do=script_toboolop, .type=SCRIPT_LEFT|SCRIPT_RASSOC}, {.priority=180, .seq="-", .func_do=script_neg, .type=SCRIPT_LEFT|SCRIPT_RASSOC}, {.priority=180, .seq="+", .func_do=script_pos, .type=SCRIPT_LEFT|SCRIPT_RASSOC},
{.priority=170, .seq="*", .func_do=script_arith, .type=SCRIPT_BIN},
{.priority=170, .seq="/", .func_do=script_arith, .type=SCRIPT_BIN},
{.priority=170, .seq="%", .func_do=script_arith, .type=SCRIPT_BIN},
{.priority=160, .seq="+", .func_do=script_arith, .type=SCRIPT_BIN},
{.priority=160, .seq="-", .func_do=script_arith, .type=SCRIPT_BIN},
{.priority=160, .seq=".", .func_do=script_concat, .type=SCRIPT_BIN},
{.priority=150, .seq=">>", .func_do=script_binmove, .type=SCRIPT_BIN}, {.priority=150, .seq="<<", .func_do=script_binmove, .type=SCRIPT_BIN},
{.priority=140, .seq="<=", .func_do=script_cmpop, .type=SCRIPT_BIN},
{.priority=140, .seq="<", .func_do=script_cmpop, .type=SCRIPT_BIN},
{.priority=140, .seq=">=", .func_do=script_cmpop, .type=SCRIPT_BIN},
{.priority=140, .seq=">", .func_do=script_cmpop, .type=SCRIPT_BIN},
{.priority=130, .seq="===", .func_do=script_eqop, .type=SCRIPT_BIN},
{.priority=130, .seq="!==", .func_do=script_eqop, .type=SCRIPT_BIN},
{.priority=130, .seq="==", .func_do=script_eqop, .type=SCRIPT_BIN},
{.priority=130, .seq="!=", .func_do=script_eqop, .type=SCRIPT_BIN},
{.priority=130, .seq="<>", .func_do=script_eqop, .type=SCRIPT_BIN},
{.priority=120, .seq="&", .func_do=script_bin, .type=SCRIPT_BIN},
{.priority=110, .seq="^", .func_do=script_bin, .type=SCRIPT_BIN},
{.priority=100, .seq="|", .func_do=script_bin, .type=SCRIPT_BIN},
{.priority=90, .seq="&&", .func_do=NULL, .type=SCRIPT_AND},
{.priority=80, .seq="||", .func_do=NULL, .type=SCRIPT_OR},
{.priority=70, .seq="?", .func_do=NULL, .type=SCRIPT_TERN},//? :
{.priority=60, .seq="=", .func_do=script_set, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, {.priority=60, .seq="+=", .func_do=script_setarith, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, {.priority=60, .seq="-=", .func_do=script_setarith, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, {.priority=60, .seq="*=", .func_do=script_setarith, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, {.priority=60, .seq="/=", .func_do=script_setarith, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, {.priority=60, .seq="%=", .func_do=script_setarith, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, {.priority=60, .seq="&=", .func_do=script_setbin, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, {.priority=60, .seq="^=", .func_do=script_setbin, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, {.priority=60, .seq="|=", .func_do=script_setbin, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, {.priority=60, .seq=">>=", .func_do=script_setmove, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, {.priority=60, .seq="<<=", .func_do=script_setmove, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE}, {.priority=60, .seq=".=", .func_do=script_setconcat, .type=SCRIPT_BIN|SCRIPT_NEEDLVALUEA|SCRIPT_LVALUE},
{.priority=40, .seq="and", .func_do=NULL, .type=SCRIPT_AND},
{.priority=30, .seq="xor", .func_do=script_logicxor, .type=SCRIPT_BIN},
{.priority=20, .seq="or", .func_do=NULL, .type=SCRIPT_OR},
{.priority=10, .seq=",", .func_do=script_comma, .type=SCRIPT_BIN},
};

int script_find_oper(char*exp,int searchleft){
   unsigned i, lenfound=0;int foundn=-1;
   for(i=0;i<sizeof(script_opers)/sizeof(script_opers[0]);i++)
       if(grub_strlen(script_opers[i].seq)>lenfound &&
((searchleft==((script_opers[i].type&SCRIPT_ARGPART)==SCRIPT_LEFT)) || (searchleft==2)) && !grub_memcmp(script_opers[i].seq,exp,grub_strlen(script_opers[i].seq)) && (script_islexend(exp[grub_strlen(script_opers[i].seq)])||script_islexend(exp[grub_strlen(script_opers[i].seq)-1])))
               foundn=i,lenfound=grub_strlen(script_opers[i].seq);
   return foundn;
}

struct script_args* script_parse_args(char*exp,int*i,struct script_env*env,struct script*scr){
   int brack=0,z,last=*i+1,mustfreed=0;
   struct script_args*passed=grub_malloc(sizeof(struct script_args));
   struct script_var*t;
   passed->number=0;
   while(exp[*i]!=')'){
       brack=0;
       (*i)++;
       while((brack!=0||(exp[*i]!=',' && exp[*i]!=')'))){
           if(exp[*i]=='(' || (exp[*i]=='{' ||exp[*i]=='['))
               brack++;
           if(exp[*i]==')' || (exp[*i]=='}' ||exp[*i]==']'))
               brack--;
           if(brack<0){
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: unexpected '%c', expected '(' at line %d",exp[*i],scr->curline);
               scr->errno=SCRIPT_ERR_UNEXPECTED;
               return NULL;
           }
           if(exp[*i]==0){
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: unexpected ';', expected ')' at line %d",scr->curline);
               scr->errno=SCRIPT_ERR_UNEXPECTED;
               return NULL;
           }
           (*i)++;
       }
       z=exp[*i];
       exp[*i]=0;
       t=script_eval_expr(exp+last,env,&mustfreed,scr);
       exp[*i]=z;
       if(scr->errno)
           return NULL;
       if(t==NULL)
           return passed;
       passed->passed[passed->number]=t;
       passed->freeit[passed->number]=mustfreed;
       passed->number++;
       last=(*i)+1;
   }
   return passed;
}

int script_get_strend(char*str){
   char c=str[0];int i;
   for(i=1;str[i]!=c && str[i];i++)
       if(str[i]=='\\')
           i++;
   return i;
}

static int script_get_argend(char *argsstr,struct script*scr){
   int i,brack=0,str=0;
for(i=0;(brack!=0 || str!=0 ||(argsstr[i]!=',' && argsstr[i]!=0 && argsstr[i]!=';'));i++){
       if(argsstr[i]=='(' || argsstr[i]=='{' ||argsstr[i]=='[')
           brack++;
       if(argsstr[i]==')' || argsstr[i]=='}' ||argsstr[i]==']')
           brack--;
       if(argsstr[i]=='"' || argsstr[i]=='\''){
           i+=script_get_strend(argsstr+i);
           continue;
       }
       if(brack<0){
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: unexpected '%c', expected '(' at line %d",argsstr[i]?argsstr[i]:';',scr->curline);
           scr->errno=SCRIPT_ERR_UNEXPECTED;
           return 0;
       }
       if((brack!=0 || str!=0) && argsstr[i]==0){
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: unexpected end of expression at line %d",scr->curline);
           scr->errno=SCRIPT_ERR_UNEXPECTED;
           return 0;
       }
   }
   return i;
}

void script_var_cpy(struct script_var*to,struct script_var*from){
   if(from==NULL){
       to->type=SCRIPT_VAR_TYPE_VOID;
       return;
   }
   grub_memcpy(to,from,sizeof(struct script_var));
   if(to->type==SCRIPT_VAR_TYPE_STR){
       int i;
       to->strval=grub_malloc(SCRIPT_STR_SIZE);
       for(i=0;from->strval[i];i++){
           if((i+1)%SCRIPT_STR_SIZE==0)
               to->strval=grub_realloc(to->strval,i+1+SCRIPT_STR_SIZE);
           to->strval[i]=from->strval[i];
       }
       to->strval[i]=0;
   }
}

static void script_import_args(struct script_env*env,struct script_args*argspassed,char*argsstr,char*fname,int*argcnta,struct script*scr){
   int i=0,j,argcnt=0,makelink=0;char vrname[MAXVARNAMELEN];
   int allmustfreed[MAX_ARGS];
   (*argcnta)=0;
   struct script_var*vrptr;
   do{
       makelink=0;
       while(grub_isspace(argsstr[i]))i++;
       if(argsstr[i]==0)
           return;
       if(argsstr[i]=='&'){
           makelink=1;
           i++;
       }
       if(argsstr[i]!='$'){
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: unexpected '%c', expected '$' or '&' in argument list of '%s'",argsstr[i],fname);
           scr->errno=SCRIPT_ERR_UNEXPECTED;
           return ;
       }
       i++;
       for(j=0;grub_isalpha(argsstr[i]);i++)
           vrname[j++]=argsstr[i];
       vrname[j]=0;
       (*argcnta)++;
       while(grub_isspace(argsstr[i]))i++;
       if(argspassed->number>argcnt){
           if(makelink|| argspassed->freeit[argcnt])
script_register_var(vrname,argspassed->passed[argcnt],env,scr);
           else{
               vrptr=script_new_var(vrname,env,scr);
               script_var_cpy(vrptr,argspassed->passed[argcnt]);
           }
           i+=script_get_argend(argsstr+i,scr);
           if(argsstr[i]==',')i++;
           allmustfreed[argcnt]=argspassed->freeit[argcnt]|| !makelink;
       }else{
           vrptr=script_new_var(vrname,env,scr);
           if(argsstr[i]=='='){
               char*expr=argsstr+i+1,c;
               struct script_var*val;
               i+=script_get_argend(argsstr+i,scr);
               c=argsstr[i];
               argsstr[i]=0;
               val=script_eval_expr(expr,NULL,&allmustfreed[argcnt],scr);
               if(allmustfreed[argcnt]){
                   grub_memcpy(vrptr,val,sizeof(struct script_var));
                   grub_free(val);
               }else{
                   script_var_cpy(vrptr,val);
               }
               allmustfreed[argcnt]=1;
               argsstr[i]=c;
               if(argsstr[i]==',')i++;
           }
       }
       argcnt++;
       if(scr->errno)
           return;
   }while(argsstr[i]!=0);
}

int script_get_var_name(char*wh,char*to,struct script_env*env __attribute__ ((unused)),struct script *scr){
   int i=0;
   while(grub_isalpha(wh[i])||grub_isdigit(wh[i]))to[i]=wh[i],i++;
   to[i]=0;
   if(!i){
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: unexpected %c, expected '' at line %d",wh[0],scr->curline);
       scr->errno=SCRIPT_ERR_UNEXPECTED;
       return 0;
   }
   return i;
}
int script_get_operend(char*exp){
   int athop=0,i=0;
   while(1){
       if(grub_isspace(exp[i])){
           i++;
           continue;
       }
if(( !grub_memcmp(exp+i,"if",sizeof("if")-1) && script_islexend(exp[i+sizeof("if")-1]))){
               while(!script_islexend(exp[i]))i++;
               while(grub_isspace(exp[i]))i++;
               i++;
               i+=script_find_pas('(',')',exp+i)+1;
               athop++;
               continue;
       }
if(( !grub_memcmp(exp+i,"do",sizeof("do")-1) && script_islexend(exp[i+sizeof("do")-1]))){
           while(!script_islexend(exp[i]))i++;
           athop++;
           continue;
       }
if(( !grub_memcmp(exp+i,"while",sizeof("while")-1) && script_islexend(exp[i+sizeof("while")-1]))){
           while(!script_islexend(exp[i]))i++;
           continue;
       }
if(( !grub_memcmp(exp+i,"for",sizeof("for")-1) && script_islexend(exp[i+sizeof("for")-1]))){
           while(!script_islexend(exp[i]))i++;
           while(grub_isspace(exp[i]))i++;
           i++;
           i+=script_find_pas('(',')',exp+i)+1;
           continue;
       }
       if(exp[i]=='{'){
           i++;
           i+=script_find_pas('{','}',exp+i);
       }else
           for(;exp[i]!=';';i++)
               if(exp[i]=='"' || exp[i]=='\'')
                   i+=script_get_strend(exp+i);
       i++;
       if(!athop)
           break;
       while(grub_isspace(exp[i]))i++;
if(( !grub_memcmp(exp+i,"else",sizeof("else")-1) && script_islexend(exp[i+sizeof("else")-1]))){
           while(!script_islexend(exp[i]))i++;
           athop--;
           continue;
       }
if(( !grub_memcmp(exp+i,"elseif",sizeof("elseif")-1) && script_islexend(exp[i+sizeof("elseif")-1]))){
           while(!script_islexend(exp[i]))i++;
           i++;
           i+=script_find_pas('(',')',exp+i)+1;
           continue;
       }
if(( !grub_memcmp(exp+i,"while",sizeof("while")-1) && script_islexend(exp[i+sizeof("while")-1]))){
           while(!script_islexend(exp[i]))i++;
           athop--;
           continue;
       }
       break;
   }
   return i-1;
}

struct script_var* script_execute(struct script*scr,struct script_env*env,int beg,int end, enum script_retstatus*status){
   char tmp[256]; int apptr=0,c,execptr=beg;
   struct script_var*vrptr,*val,*val2;
   while(1){
       *status=SCRIPT_NORM;
while(script_isspace_wline(scr->body[execptr],scr) || scr->body[execptr]=='{' || scr->body[execptr]=='}')execptr++;
       if(execptr>=end)
           return NULL;
       apptr=0;
       while(!script_islexend(scr->body[execptr+apptr]))apptr++;
       c=scr->body[execptr+apptr];
       scr->body[execptr+apptr]=0;
       if(!grub_strcmp(scr->body+execptr,"if")){
           scr->body[execptr+apptr]=c;
           execptr+=apptr;
           while(script_isspace_wline(scr->body[execptr],scr))execptr++;
           execptr++;
           int z0=script_find_pas('(',')',scr->body+execptr),z,z2,z2t;
           int vl,mustfreed,j,execptr0=execptr;
           for(j=0;j<=z0;j++)
               if(scr->body[execptr+j]=='\n')
                   scr->curline++;
           execptr+=z0+1;
           c=(scr->body+execptr0)[z0];
           (scr->body+execptr0)[z0]=0;
           val=script_eval_expr(scr->body+execptr0,env,&mustfreed,scr);
           (scr->body+execptr0)[z0]=c;
           val2=script_tobool(val,scr);
           vl=val2->intval;
           script_free_var(val2);
           if(mustfreed)
               script_free_var(val);
           z=script_get_operend(scr->body+execptr)+1;
           while(script_isspace_wline(scr->body[execptr+z],scr))z++;
           z2=z;
           z2t=z2;
           while(1){
if(!grub_memcmp(scr->body+execptr+z2,"else",sizeof("else")-1) && script_islexend(scr->body[execptr+z2+sizeof("else")-1])){ z2+=script_get_operend(scr->body+execptr+z2+sizeof("else")-1)+sizeof("else");
                   z2t=z2;
while(script_isspace_wline(scr->body[execptr+z2],scr))z2++;
                   break;
               }
if(!grub_memcmp(scr->body+execptr+z2,"elseif",sizeof("else")-1) && script_islexend(scr->body[execptr+z2+sizeof("elseif")-1])){
                   z2+=sizeof("elseif")-1;
                   while(grub_isspace((scr->body+execptr)[z2]))z2++;
                   z2++;
                   z2+=script_find_pas('(',')',scr->body+execptr+z2)+1;
                   z2+=script_get_operend(scr->body+execptr+z2)+1;
                   z2t=z2;
while(script_isspace_wline(scr->body[execptr+z2],scr))z2++;
                   continue;
               }
               break;
           }
           z2=z2t-1;
           struct script_var*tm=NULL;
           if(vl)
               tm=script_execute(scr,env,execptr,execptr+z-2,status);
           if(!vl && z2!=z)
tm=script_execute(scr,env,execptr+z+sizeof("else")-1,execptr+z2,status);
           if(*status!=SCRIPT_NORM)
               return tm;
           execptr+=z2;
           continue;
       }
       if(!grub_strcmp(scr->body+execptr,"while")){
           scr->body[execptr+apptr]=c;
           execptr+=apptr;
           while(script_isspace_wline(scr->body[execptr],scr))execptr++;
           execptr++;
           int z0=script_find_pas('(',')',scr->body+execptr),z;
           int vl,mustfreed,j,execptr0=execptr;
           for(j=0;j<=z0;j++)
               if(scr->body[execptr+j]=='\n')
                   scr->curline++;
           execptr+=z0+1;
           z=script_get_operend(scr->body+execptr)+1;
           while(1){
               c=(scr->body+execptr0)[z0];
               (scr->body+execptr0)[z0]=0;
               val=script_eval_expr(scr->body+execptr0,env,&mustfreed,scr);
               (scr->body+execptr0)[z0]=c;
               val2=script_tobool(val,scr);
               vl=val2->intval;
               script_free_var(val2);
               if(mustfreed)
                   script_free_var(val);
               struct script_var*tm=NULL;
               if(!vl)
                   break;
               tm=script_execute(scr,env,execptr,execptr+z,status);
               if(*status==SCRIPT_CONTINUE){
                   *status=SCRIPT_NORM;
                   continue;
               }
               if(*status==SCRIPT_BREAK){
                   *status=SCRIPT_NORM;
                   break;
               }
               if(*status!=SCRIPT_NORM)
                   return tm;
           }
           execptr+=z;
           continue;
       }
       if(!grub_strcmp(scr->body+execptr,"do")){
           scr->body[execptr+apptr]=c;
           execptr+=apptr;
           while(script_isspace_wline(scr->body[execptr],scr))execptr++;
           int z;
           int vl,mustfreed,expbeg,expend;
           z=script_get_operend(scr->body+execptr)+1;
           expbeg=execptr+z;
           while(grub_isspace(scr->body[expbeg]))expbeg++;
           expbeg+=sizeof("while")-1;
           while(grub_isspace(scr->body[expbeg]))expbeg++;
           expbeg++;
           expend=expbeg+script_find_pas('(',')',scr->body+expbeg);
           while(1){
               struct script_var*tm=NULL;
               tm=script_execute(scr,env,execptr,execptr+z-2,status);
               c=scr->body[expend];
               scr->body[expend]=0;
               val=script_eval_expr(scr->body+expbeg,env,&mustfreed,scr);
               scr->body[expend]=c;
               val2=script_tobool(val,scr);
               vl=val2->intval;
               script_free_var(val2);
               if(mustfreed)
                   script_free_var(val);
if(!vl && (*status==SCRIPT_NORM || *status==SCRIPT_CONTINUE))
                   break;
               if(*status==SCRIPT_CONTINUE){
                   *status=SCRIPT_NORM;
                   continue;
               }
               if(*status==SCRIPT_BREAK){
                   *status=SCRIPT_NORM;
                   break;
               }
               if(*status!=SCRIPT_NORM)
                   return tm;
           }
           execptr+=z;
           continue;
       }
       if(!grub_strcmp(scr->body+execptr,"for")){
           scr->body[execptr+apptr]=c;
           execptr+=apptr;
           while(script_isspace_wline(scr->body[execptr],scr))execptr++;
           execptr++;
           int z,z0;
           int vl,mustfreed,j,execptr0=execptr,exp2,exp2end;
           for(;scr->body[execptr]!=';';execptr++)
               if(scr->body[execptr]=='"' || scr->body[execptr]=='\'')
                   execptr+=script_get_strend(scr->body+execptr);
           c=scr->body[execptr];
           scr->body[execptr]=0;
           val=script_eval_expr(scr->body+execptr0,env,&mustfreed,scr);
           if(mustfreed)
               script_free_var(val);
           scr->body[execptr]=c;
           for(j=execptr0;j<=execptr;j++)
               if(scr->body[execptr+j]=='\n')
                   scr->curline++;
           execptr++;
           execptr0=execptr;
           for(z0=0;scr->body[execptr+z0]!=';';z0++)
if(scr->body[execptr+z0]=='"' || scr->body[execptr+z0]=='\'')
                   z0+=script_get_strend(scr->body+execptr+z0);
           execptr+=z0+1;
           exp2=execptr;
           execptr+=script_find_pas('(',')',scr->body+execptr)+1;
           exp2end=execptr-1;
           z=script_get_operend(scr->body+execptr)+1;
           while(1){
               c=(scr->body+execptr0)[z0];
               (scr->body+execptr0)[z0]=0;
               val=script_eval_expr(scr->body+execptr0,env,&mustfreed,scr);
               (scr->body+execptr0)[z0]=c;
               val2=script_tobool(val,scr);
               vl=val2->intval;
               script_free_var(val2);
               if(mustfreed)
                   script_free_var(val);
               struct script_var*tm=NULL;
               if(!vl)
                   break;
               tm=script_execute(scr,env,execptr,execptr+z-2,status);
               if(*status==SCRIPT_BREAK){
                   *status=SCRIPT_NORM;
                   break;
               }
               if(*status!=SCRIPT_NORM && *status!=SCRIPT_CONTINUE)
                   return tm;
               c=scr->body[exp2end];
               scr->body[exp2end]=0;
               val=script_eval_expr(scr->body+exp2,env,&mustfreed,scr);
               scr->body[exp2end]=c;
               if(mustfreed)
                   script_free_var(val);
               if(*status==SCRIPT_CONTINUE){
                   *status=SCRIPT_NORM;
                   continue;
               }
           }
           execptr+=z;
           continue;
       }
if(!grub_strcmp(scr->body+execptr,"global")||!grub_strcmp(scr->body+execptr,"superglobal")){
           scr->body[execptr+apptr]=c;
           execptr+=apptr;
           do{
               scr->body[execptr]=c;
while(script_isspace_wline(scr->body[execptr],scr))execptr++;
               if(scr->body[execptr]!='$'){
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: unexpected %c, expected '$' at line %d",scr->body[execptr],scr->curline);
                   scr->errno=SCRIPT_ERR_UNEXPECTED;
                   return NULL;
               }
               execptr++;
               execptr+=script_get_var_name(scr->body+execptr,tmp,env,scr);
               if(scr->errno)
                   return NULL;
vrptr=script_new_var(tmp,((scr->body[execptr]=='s')?&script_superglobenv:scr->globenv),scr); while(script_isspace_wline(scr->body[execptr],scr))execptr++; if(scr->body[execptr]!=';' && scr->body[execptr]!='=' && scr->body[execptr]!=','){
                   grub_error(GRUB_ERR_BAD_ARGUMENT,
"Error: unexpected %c, expected '=' or ';' or ',' at line %d",scr->body[execptr],scr->curline);
                   scr->errno=SCRIPT_ERR_UNEXPECTED;
                   return NULL;
               }
               if(scr->body[execptr]=='='){
                   execptr++;
                   char*expr=scr->body+execptr;int i,mustfreed,j;
                   i=script_get_argend(scr->body+execptr,scr);
                   c=(scr->body+execptr)[i];
                   (scr->body+execptr)[i]=0;
                   val=script_eval_expr(expr,env,&mustfreed,scr);
                   for(j=0;j<i;j++)
                       if((scr->body+execptr)[j]=='\n')
                           scr->curline++;
                   if(mustfreed){
                       grub_memcpy(vrptr,val,sizeof(struct script_var));
                       grub_free(val);
                   }else{
                       script_var_cpy(vrptr,val);
                   }
                   (scr->body+execptr)[i]=c;
                   execptr+=i;
               }
           }while(scr->body[execptr-1]==',');
           continue;
       }
       if(!grub_strcmp(scr->body+execptr,"echo") ){
           int i,mustfreed,j;
           scr->body[execptr+apptr]=c;
           execptr+=apptr;
           i=script_get_argend(scr->body+execptr,scr);
           c=(scr->body+execptr)[i];
           (scr->body+execptr)[i]=0;
           val=script_eval_expr(scr->body+execptr,env,&mustfreed,scr);
           (scr->body+execptr)[i]=c;
           for(j=execptr;j<=i;j++)
               if(scr->body[execptr+j]=='\n')
                   scr->curline++;
           val2=script_tostr(val,scr);
           execptr+=i+1;
           if(scr->errno)
               return NULL;
           grub_printf("%s",val2->strval);
           script_free_var(val2);
           if(mustfreed)
               script_free_var(val);
           continue;
       }
       if( !grub_strcmp(scr->body+execptr,"break")){
           *status=SCRIPT_BREAK;
           return NULL;
           continue;
       }
       if( !grub_strcmp(scr->body+execptr,"continue")){
           *status=SCRIPT_CONTINUE;
           return NULL;
           continue;
       }
       if( !grub_strcmp(scr->body+execptr,"return")){
           int i,mustfreed,j;
           scr->body[execptr+apptr]=c;
           execptr+=apptr;
           i=script_get_argend(scr->body+execptr,scr);
           c=(scr->body+execptr)[i];
           (scr->body+execptr)[i]=0;
           val=script_eval_expr(scr->body+execptr,env,&mustfreed,scr);
           (scr->body+execptr)[i]=c;
           for(j=execptr;j<=i;j++)
               if(scr->body[execptr+j]=='\n')
                   scr->curline++;
           struct script_var*rtval=grub_malloc(sizeof(struct script_var));
           script_init_var(rtval);
           script_var_cpy(rtval,val);
           if(mustfreed)
               script_free_var(val);
           execptr+=i+1;
           *status=SCRIPT_RET;
           return rtval;
           continue;
       }
       {
           int i,j,mustfreed;
           scr->body[execptr+apptr]=c;
           i=script_get_argend(scr->body+execptr,scr);
           c=(scr->body+execptr)[i];
           (scr->body+execptr)[i]=0;
           val=script_eval_expr(scr->body+execptr,env,&mustfreed,scr);
           (scr->body+execptr)[i]=c;
           for(j=execptr;j<=i;j++)
               if(scr->body[j]=='\n')
                   scr->curline++;
           execptr+=i+1;
           if(scr->errno)
               return NULL;
           if(mustfreed)
               script_free_var(val);
           continue;
       }
   }
   return NULL;
}

void script_free_env(struct script_env*env,int skip){
   int i;
   for(i=skip;i<env->num_vars;i++){
       script_free_var(env->vars[i]);
   }
   grub_free(env->names);
   grub_free(env);
}
void script_free_args(struct script_args*args){
   int i;
   for(i=0;i<args->number;i++)
       if(args->freeit[i]){
           script_free_var(args->passed[i]);
       }
   grub_free(args);
}

static struct script_var *script_exec_script_func(struct funclink*func,struct script_args*args,struct script *scr){
   int argcnt=0;enum script_retstatus status=SCRIPT_NORM;
struct script_env*lenv=script_new_env();struct script_var*rtval=script_create_var();
   struct script_function *fn=&func->insscr->funcs[func->num];
script_import_args(lenv,args,scr->body+fn->argsfrom,func->name,&argcnt,scr);
   if(scr->errno)
       return NULL;
   script_var_cpy(rtval,script_execute(scr,lenv,fn->beg,fn->end,&status));
   script_free_args(args);
   script_free_env(lenv,argcnt);
   return rtval;
}

struct script_var *script_exec_func(char*fname,struct script_args*args,struct script *scr, struct script_env*env ){
   unsigned i;
   if(scr->errno)
       return NULL;
   for(i=0;i<scr->numfuncs;i++)
       if(!grub_strcmp(scr->f_list[i].name,fname))
           break;
   if(i!=scr->numfuncs)
       return script_exec_script_func(&scr->f_list[i],args,scr);
   for(i=0;i<globfunccount;i++)
       if(!grub_strcmp(globfuncs[i].name,fname))
           break;
   if(i!=globfunccount)
       return script_exec_script_func(&globfuncs[i],args,scr);
   for(i=0;script_exts[i].script_fn;i++)
       if(!grub_strcmp(script_exts[i].name,fname))
           break;
   if(script_exts[i].script_fn)
       return script_exts[i].script_fn(args,scr,env);
   {
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: function %s called from line %d not found",fname,scr->curline);
       scr->errno=SCRIPT_ERR_FUNCUNFOUND;
       return NULL;
   }
}

struct script_var*script_get_singlestring(char*from,int*i,struct script*scr __attribute__ ((unused))){
   struct script_var*rtval=script_newstr();
   int j;
   for(j=0;from[*i]!='\'' && from[*i]!=0;(*i)++,j++){
   if((j+1)%SCRIPT_STR_SIZE==0)
       rtval->strval=grub_realloc(rtval->strval,j+1+SCRIPT_STR_SIZE);
   switch(from[*i]){
   case '\\':
       switch(from[(*i)+1]){
       case '\n':
           j--;
           break;
       case '\'':
       case '\\':
           rtval->strval[j]=from[(*i)+1];
           break;
       default:
           rtval->strval[j]='\\';
           (*i)--;
       }
       (*i)++;
       break;
   default:
       rtval->strval[j]=from[*i];
   }
   }
   rtval->strval[j]=0;
   (*i)++;
   return rtval;
}

struct script_var*script_get_doublestring(char*from,int*i,struct script_env*env,struct script*scr __attribute__ ((unused))){
   struct script_var*rtval=script_newstr();
   int j;char *end;
   for(j=0;from[*i]!='"' && from[*i]!=0;(*i)++,j++){
   if((j+1)%SCRIPT_STR_SIZE==0)
       rtval->strval=grub_realloc(rtval->strval,j+1+SCRIPT_STR_SIZE);
   switch(from[*i]){
case '\\':
       switch(from[(*i)+1]){
       case '\n':
           j--;
           break;
       case 'n':
           rtval->strval[j]='\n';
           break;
       case 'r':
           rtval->strval[j]='\r';
           break;
       case 'x':
           rtval->strval[j]=script_strtoul(from+*i+2,&end,16);
           *i=end-from-2;
           break;
       case 't':
           rtval->strval[j]='\t';
break; case '\'':
       case '\\':
       case '"':
       case '$':
           rtval->strval[j]=from[(*i)+1];
           break;
       default:
           if(from[(*i)+1]>='0' && from[(*i)+1]<='7'){
               rtval->strval[j]=script_strtoul(from+*i+1,&end,8);
               *i=end-from-2;
           }else{
               rtval->strval[j]='\\';
               (*i)--;
           }
       }
       (*i)++;
       break;
default:
       rtval->strval[j]=from[*i];
   }
   }
   rtval->strval[j]=0;
   (*i)++;
   return rtval;
}

struct script_var*script_get_var(char*exp,int*i,struct script_env*lenv,struct script*scr){
   (*i)++;
   int nbeg=(*i);char c;
   struct script_var *rtval;
   while(grub_isalpha(exp[*i])|| grub_isdigit(exp[*i]) || exp[*i] == '_')
       (*i)++;
   c=exp[*i];
   exp[*i]=0;
   if((rtval=script_find_var(exp+nbeg,lenv,scr))){
       exp[*i]=c;
       return rtval;
   }
   if((rtval=script_find_var(exp+nbeg,scr->globenv,scr))){
       exp[*i]=c;
       return rtval;
   }
   if((rtval=script_find_var(exp+nbeg,&script_superglobenv,scr))){
       exp[*i]=c;
       return rtval;
   }
   rtval=script_new_var(exp+nbeg,lenv,scr);
   exp[*i]=c;
   return rtval;
}

struct script_var *script_eval_expr(char*exp,struct script_env *lenv,int*mustfreed,struct script*scr){
   unsigned i,cptr;char c;
   struct script_var*cur=NULL;
   *mustfreed=0;
   for(i=0;exp[i];i++){
       if(grub_isspace(exp[i]))
           continue;
       int op=script_find_oper(exp+i,cur==NULL);
       if(op!=-1){
           int newop=0,expbeg,freeright=0,unary,tern1=0;
           struct script_var*right=NULL,*wcur;
           if((script_opers[op].type&SCRIPT_NEEDLVALUEA) && *mustfreed){
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: Lvalue needed at line %d for %s",scr->curline,script_opers[op].seq);
               scr->errno=SCRIPT_ERR_UNEXPECTED;
               return NULL;
           }
           i+=grub_strlen(script_opers[op].seq);
           expbeg=i;
           switch(script_opers[op].type&SCRIPT_ARGPART){
           case SCRIPT_BRACK:
i+=script_find_pas(script_opers[op].seq[0],(script_opers[op].seq[0]=='['?']':'}'),exp+i);
               break;
           case SCRIPT_RIGHT:
               break;
           case SCRIPT_TERN:
               for(;exp[i];i++){
                   if(exp[i]==':')
                       break;
if(grub_isalpha(exp[i])||grub_isdigit(exp[i])||exp[i]=='_')
                       unary=0;
                   if(exp[i]=='(')
                       i+=script_find_pas('(',')',exp+i),unary=0;
                   if(exp[i]=='{')
                       i+=script_find_pas('{','}',exp+i),unary=0;
                   if(exp[i]=='[')
                       i+=script_find_pas('[',']',exp+i),unary=0;
                   if(exp[i]=='"' || exp[i]=='\''){
                       i+=script_get_strend(exp+i),unary=0;
                       continue;
                   }
               }
               tern1=i;
               i++;
           case SCRIPT_LEFT:
           case SCRIPT_BIN:
           case SCRIPT_AND:
           case SCRIPT_OR:
               unary=1;
               for(;exp[i];i++){
                   newop=script_find_oper(exp+i,unary);
                   if(newop!=-1 &&!unary)
                       unary=1;
if(newop!=-1 && (script_opers[newop].priority<script_opers[op].priority || (script_opers[newop].priority==script_opers[op].priority && !(script_opers[op].type&SCRIPT_RASSOC)) ) )
                       break;
if(grub_isalpha(exp[i])||grub_isdigit(exp[i])||exp[i]=='_')
                       unary=0;
                   if(exp[i]=='(')
                       i+=script_find_pas('(',')',exp+i),unary=0;
                   if(exp[i]=='{')
                       i+=script_find_pas('{','}',exp+i),unary=0;
                   if(exp[i]=='[')
                       i+=script_find_pas('[',']',exp+i),unary=0;
                   if(exp[i]=='"' || exp[i]=='\''){
                       i+=script_get_strend(exp+i),unary=0;
                       continue;
                   }
               }
           }
           c=exp[i];
           exp[i]=0;
           switch(script_opers[op].type&SCRIPT_ARGPART){
           case SCRIPT_TERN:
               break;
           case SCRIPT_OR:
           case SCRIPT_AND:
               {
                   struct script_var*ncur=script_tobool(cur,scr);
                   if(*mustfreed)
                       script_free_var(cur);
if(ncur->intval==((script_opers[op].type&SCRIPT_ARGPART)==SCRIPT_AND)){ cur=script_eval_expr(exp+expbeg,lenv,&freeright,scr);
                       script_free_var(ncur);
                       ncur=script_tobool(cur,scr);
                       if(freeright)
                           script_free_var(cur);
                   }
                   cur=ncur;
                   *mustfreed=0;
                   freeright=0;
               }
               break;
           default:
               if((script_opers[op].type&SCRIPT_ARGPART)!=SCRIPT_RIGHT){
                   right=script_eval_expr(exp+expbeg,lenv,&freeright,scr);
                   if(!right){
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: unexpected end of expressin at line %d",exp[i],scr->curline);
                       scr->errno=SCRIPT_ERR_UNEXPECTED;
                       return NULL;
                   }
               }
               else
                   freeright=0;
           }
           wcur=cur;
           switch(script_opers[op].type&SCRIPT_ARGPART){
           case SCRIPT_BRACK:
           case SCRIPT_BIN:
               cur=script_opers[op].func_do(cur,right,op,scr);
               break;
           case SCRIPT_LEFT:
               cur=script_opers[op].func_do(right,NULL,op,scr);
               break;
           case SCRIPT_RIGHT:
               cur=script_opers[op].func_do(cur,NULL,op,scr);
               break;
           case SCRIPT_TERN:
               {
                   char c2;
                   struct script_var*ncur=script_tobool(cur,scr);
                   freeright=0;
                   if(ncur->intval){
                       c2=exp[tern1];
                       exp[tern1]=0;
                       script_free_var(ncur);
                       cur=script_eval_expr(exp+expbeg,lenv,mustfreed,scr);
                       exp[tern1]=c2;
                   }else{
                       script_free_var(ncur);
cur=script_eval_expr(exp+tern1+1,lenv,mustfreed,scr);
                   }
               }
               break;
           }
           exp[i]=c;
           if((script_opers[op].type&SCRIPT_ARGPART)!=SCRIPT_BRACK)
               i--;
           if(*mustfreed)
               script_free_var(wcur);
           if(freeright)
               script_free_var(right);
           *mustfreed=!(script_opers[op].type&SCRIPT_LVALUE);
           continue;
       }
       if(grub_isalpha(exp[i])||exp[i]=='_'){
           char*fname=exp+i;int fnameend;
           while(!script_islexend(exp[i]))i++;
           fnameend=i;
           while(grub_isspace(exp[i]))i++;
           cptr=fnameend;
           c=exp[cptr];
           exp[cptr]=0;
           if(!grub_strcmp(fname,"TRUE")){
               cur=script_create_var();
               cur->type=SCRIPT_VAR_TYPE_BOOL;
               cur->intval=1;
               exp[cptr]=c;
               *mustfreed=1;
               i--;
               continue;
           }
           if(!grub_strcmp(fname,"FALSE")){
               cur=script_create_var();
               cur->type=SCRIPT_VAR_TYPE_BOOL;
               cur->intval=0;
               exp[cptr]=c;
               *mustfreed=1;
               i--;
               continue;
           }
           if(!grub_strcmp(fname,"VOID") || !grub_strcmp(fname,"NULL")){
               cur=script_create_var();
               cur->type=SCRIPT_VAR_TYPE_VOID;
               cur->intval=0;
               exp[cptr]=c;
               *mustfreed=1;
               i--;
               continue;
           }
           if(((cptr==i)?c:exp[i])!='('){
grub_error(GRUB_ERR_BAD_ARGUMENT,"Error: unexpected '%c', expected '(' at line %d",(cptr==i)?c:exp[i],scr->curline);
               scr->errno=SCRIPT_ERR_UNEXPECTED;
               exp[cptr]=c;
               return NULL;
           }
cur=script_exec_func(fname,script_parse_args(exp,&i,lenv,scr),scr,lenv);
           exp[cptr]=c;
           if(scr->errno)
               return NULL;
           *mustfreed=1;
           continue;
       }
       if(grub_isdigit(exp[i])){
           cur=script_get_int(exp,&i);
           *mustfreed=1;
           i--;
           continue;
       }
       if(exp[i]=='"'){
           i++;
           cur=script_get_doublestring(exp,&i,lenv,scr);
           *mustfreed=1;
           i--;
           continue;
       }
       if(exp[i]=='\''){
           i++;
           cur=script_get_singlestring(exp,&i,scr);
           *mustfreed=1;
           i--;
           continue;
       }
       if(exp[i]=='$'){
           struct script_var*val;
           cur=script_get_var(exp,&i,lenv,scr);
           while(grub_isspace(exp[i]))
               i++;
           *mustfreed=0;
           if(exp[i]!='('){
               i--;
               continue;
           }
           val=script_tostr(cur,scr);
           if(scr->errno)
               return NULL;
cur=script_exec_func(val->strval,script_parse_args(exp,&i,lenv,scr),scr,lenv);
           if(scr->errno)
               return NULL;
           *mustfreed=1;
           continue;
       }
       if(exp[i]=='('){
           int exend;
           i++;
           exend=script_find_pas('(',')',exp+i)+i;
           c=exp[exend];
           exp[exend]=0;
           cur=script_eval_expr(exp+i,lenv,mustfreed,scr);
           if(scr->errno)
               return NULL;
           exp[exend]=c;
           i=exend;
           continue;
       }
   }
   return cur;
}

int script_register_ext_func(char*name,struct script_var* (*fn)(struct script_args*,struct script *,struct script_env*)){
   script_exts_count++;
script_exts=grub_realloc(script_exts,script_exts_count*sizeof(struct ext_func));
   grub_memcpy(script_exts[script_exts_count].name,name,MAXFUNCNAMELEN-1);
   script_exts[script_exts_count].name[MAXFUNCNAMELEN-1]=0;
   script_exts[script_exts_count].script_fn=fn;
   return 0;
}

int script_unregister_ext_func(char*name){
   int i;
for(i=0;script_exts[i].script_fn && grub_strcmp(script_exts[i].name,name);i++);
   for(;script_exts[i].script_fn;i++)
       script_exts[i]=script_exts[i+1];
   script_exts_count--;
script_exts=grub_realloc(script_exts,script_exts_count*sizeof(struct ext_func));
   return 0;
}

static int script_read_file(struct script *scr,char*fname){
#ifndef SCRIPT_EMU
 grub_file_t script_file;
 script_file=grub_file_open(fname);
 scr->bodylen=script_file->size;
 scr->body=grub_malloc(scr->bodylen+1);
 grub_file_read(script_file,scr->body,scr->bodylen);
 grub_file_close(script_file);
#else
 FILE*script_file;
 script_file=fopen(fname,"r");
 fseek(script_file,0,SEEK_END);
 scr->bodylen=ftell(script_file);
 fseek(script_file,0,SEEK_SET);
 scr->body=malloc(scr->bodylen+1);
 fread(scr->body,1,scr->bodylen,script_file);
 fclose(script_file);
#endif
return 0;
}

grub_err_t script_launch(char*file){
   struct script scr;
   struct script_args *argsload=grub_malloc(sizeof(struct script_args));
   argsload->number=0;
   script_read_file(&scr,file);
   scr.body[scr.bodylen]=0;
   script_remove_comments(&scr);
   scr.body[scr.bodylen]=0;
   script_parse_funcs(&scr);
   struct script_env curenv={.names="",.num_vars=0,.vars=NULL,.sumlen=0};
   script_exec_func("script_load",argsload,&scr,&curenv);
   return 0;
}

#ifndef SCRIPT_EMU
static grub_err_t
grub_cmd_script (struct grub_arg_list *state __attribute__ ((unused)),
       int argc ,
       char **args )
{
 if(argc==0){
     grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
   return GRUB_ERR_BAD_ARGUMENT;
 }
 script_launch(args[0]);
 return 0;
}
GRUB_MOD_NAME(script);

GRUB_MOD_INIT
{
 (void)mod;            /* To stop warning. */
 grub_register_command ("script", grub_cmd_script, GRUB_COMMAND_FLAG_BOTH,
            "script", "Run script", 0);
}

GRUB_MOD_FINI
{
 grub_unregister_command ("script");
}
#else
int main(int argc,char**args){
 if(argc==1){
     grub_error (GRUB_ERR_BAD_ARGUMENT, "no file specified");
   return GRUB_ERR_BAD_ARGUMENT;
 }
 script_launch(args[1]);
 return 0;
}
#endif

-----------------------------------------------------------------------------------------------------------------------------------------
Serbinenko Vladimir
address@hidden
vovas at irc.gnu.org#grub




reply via email to

[Prev in Thread] Current Thread [Next in Thread]