All of lore.kernel.org
 help / color / mirror / Atom feed
* Pre-alpha scripting engine
       [not found] <E1CpUhp-000IYX-00.grub-devel-bounces+serbinenko-vova=list-ru-gnu-org@mx11.mail.ru>
@ 2005-01-14 18:48 ` Serbinenko Vladimir
  2005-01-18 18:55   ` Marco Gerards
  0 siblings, 1 reply; 15+ messages in thread
From: Serbinenko Vladimir @ 2005-01-14 18:48 UTC (permalink / raw)
  To: grub-devel

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 <gniibe@m17n.org>
 *
 *  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
serbinenko.vova@list.ru
vovas at irc.gnu.org#grub



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Pre-alpha scripting engine
  2005-01-14 18:48 ` Pre-alpha scripting engine Serbinenko Vladimir
@ 2005-01-18 18:55   ` Marco Gerards
  2005-01-18 19:54     ` Serbinenko Vladimir
  0 siblings, 1 reply; 15+ messages in thread
From: Marco Gerards @ 2005-01-18 18:55 UTC (permalink / raw)
  To: The development of GRUB 2

Serbinenko Vladimir <serbinenko.vova@list.ru> writes:

> Script syntax description:
> I took PHP-syntax as a base

Personally I would prefer something like a bash like syntax, but ok...

Assuming you want this to applied to CVS, Okuji has to agree with this
first.  Okuji, what is your opinion on this?

Can you please explain how the parser itself works?  What kind of
parser is it, something about the scanner perhaps, etc?

> 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>
> }

How about grub.cfg?  It would be nice if it would be possible to embed
code there.

> Notes:
[...]
> Spaces in (type) are not supported,

Sorry, I don't understand this one.

Thanks,
Marco




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Pre-alpha scripting engine
  2005-01-18 18:55   ` Marco Gerards
@ 2005-01-18 19:54     ` Serbinenko Vladimir
  2005-01-19 13:01       ` Marco Gerards
  0 siblings, 1 reply; 15+ messages in thread
From: Serbinenko Vladimir @ 2005-01-18 19:54 UTC (permalink / raw)
  To: The development of GRUB 2

Marco Gerards wrote:

>Can you please explain how the parser itself works?  What kind of
>parser is it, something about the scanner perhaps, etc?
>
>  
>
It's two times parser. First time it removes comments and creates 
function list.Then it launches "script_load" function. Real script 
execution is in script_execute. This function detects what structure is 
used. IF it's a loop it makes a recursive call. If it's  return, 
brake,... if return value and status(why exited?) for expressions it 
uses recursive function script_eval_expr. It checks the type of first 
token(string,function, variable,...) ,calculates it and stores to cur, 
then it repeats until end of expression. If it's an operator it can be 
unary operator only if cur==NULL. Then it determines the part of 
expression that must be passed as right argument
Ex: $a+$b*$c When it finds+ cur contains $a so it's binary+ right part 
is $b*$c as priority of * is bigger than binary+.
Then it invokes corresponding function(in that case script_arith). There 
are some special operators like ?:, ||, &&,... that control execution so 
they must be calculated directly in script_eval_expr and so .func_do=NULL
Function script_parse_args converts script-like argument to internal 
format. Function import_args imports arguments to local environment. 
script_exec_* are made to call different functions. For information 
about other functions just mail me or wait alpha-beta version where I'll 
add some comments

>>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>
>>}
>>    
>>
>
>How about grub.cfg?  It would be nice if it would be possible to embed
>code there.
>
>  
>
You can just write in grub.cfg
insmod script
script <file>
And there is no mess between  scripts and shell(however shell functions 
can be used by scripts...will in alpha)

>>Notes:
>>    
>>
>[...]
>  
>
>>Spaces in (type) are not supported,
>>    
>>
>
>Sorry, I don't understand this one.
>
>  
>
in PHP you can write (   int   ), (   int),  (int   ),  (int
),... and so on but  current version supports only (int), (bool) and (str)

>Thanks,
>Marco
>
>
>
>_______________________________________________
>Grub-devel mailing list
>Grub-devel@gnu.org
>http://lists.gnu.org/mailman/listinfo/grub-devel
>
>
>  
>




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Pre-alpha scripting engine
  2005-01-18 19:54     ` Serbinenko Vladimir
@ 2005-01-19 13:01       ` Marco Gerards
  2005-01-19 20:04         ` Yoshinori K. Okuji
  0 siblings, 1 reply; 15+ messages in thread
From: Marco Gerards @ 2005-01-19 13:01 UTC (permalink / raw)
  To: The development of GRUB 2

Serbinenko Vladimir <serbinenko.vova@list.ru> writes:

> Marco Gerards wrote:
>
>>Can you please explain how the parser itself works?  What kind of
>>parser is it, something about the scanner perhaps, etc?
> It's two times parser. First time it removes comments and creates
> function list.Then it launches "script_load" function. Real script
> execution is in script_execute.

[...]

Ok.  What I would like to see in GRUB is a simple top-down parser.
That makes it really easy for us to maintain it.  Here is some more
information about top-down parsers:

http://en.wikipedia.org/wiki/Top-down_parsing

This wikipedia entry is a bit short, but there is a lot of information
you can find about this subject on google.

One other thing I noticed is that is is not GCS conforming.  GRUB is
GCS conforming and we want to keep it that way.  The GCS the document
that describes our coding style, the way we document changes, etc:

http://www.gnu.org/prep/standards/

But as I said before, the most important thing that needs to be done
is that Okuji agrees with the syntax.  

>>How about grub.cfg?  It would be nice if it would be possible to embed
>>code there.
> You can just write in grub.cfg
> insmod script
> script <file>
> And there is no mess between  scripts and shell(however shell
> functions can be used by scripts...will in alpha)

Ok...

What I would like to see is that scripting would be possible in the
configuration file and that it easily integrates.

Thanks,
Marco




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Pre-alpha scripting engine
  2005-01-19 13:01       ` Marco Gerards
@ 2005-01-19 20:04         ` Yoshinori K. Okuji
  2005-01-19 20:48           ` Marco Gerards
  2005-01-19 20:59           ` Tomas Ebenlendr
  0 siblings, 2 replies; 15+ messages in thread
From: Yoshinori K. Okuji @ 2005-01-19 20:04 UTC (permalink / raw)
  To: The development of GRUB 2

On Wednesday 19 January 2005 14:01, Marco Gerards wrote:
> But as I said before, the most important thing that needs to be done
> is that Okuji agrees with the syntax.

Honestly speaking, I don't know.

I also prefer that it looks more like BASH, but shell scripting is 
sometimes very ugly (e.g. "i = `expr $i + 1`"). So I don't know what 
the best is.

But I bet that these should be right:

- GRUB should not distinguish command execution from scripting.

- The language must not enforce users to learn really new things.

- The language should be flexible enough to do many things without 
writing modules in C.

The first item is a must for GRUB, because the strongest advantage in 
GRUB is that you can do whatever at run time. Once we accept that 
scripting can do more than from the command line, we would lose 
complete control of booting process.

I think the first one suggests that we should not have multiple 
languages. There is a way to have multiple ones without breaking that 
policy (i.e. embedding a language in another language), but this sounds 
overkill to me.

So a scripting language should fit into the semantics of the 
command-line interface. For example, Lisp is not acceptable, because it 
is too difficult to use as a shell. I don't know if PHP-like syntax 
fulfills this requirement, but I don't like it very much, because PHP 
is really similar to Perl (which is known as a maker of write-only 
code).

I'd like to hear others' opinions. I have been thinking this issue for 
some years, but I still don't know a good answer.

Okuji



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Pre-alpha scripting engine
  2005-01-19 20:04         ` Yoshinori K. Okuji
@ 2005-01-19 20:48           ` Marco Gerards
  2005-01-19 21:48             ` Maurizio Boriani
  2005-01-19 20:59           ` Tomas Ebenlendr
  1 sibling, 1 reply; 15+ messages in thread
From: Marco Gerards @ 2005-01-19 20:48 UTC (permalink / raw)
  To: The development of GRUB 2

"Yoshinori K. Okuji" <okuji@enbug.org> writes:

> On Wednesday 19 January 2005 14:01, Marco Gerards wrote:
>> But as I said before, the most important thing that needs to be done
>> is that Okuji agrees with the syntax.
>
> Honestly speaking, I don't know.
>
> I also prefer that it looks more like BASH, but shell scripting is 
> sometimes very ugly (e.g. "i = `expr $i + 1`"). So I don't know what 
> the best is.

[...]

> I'd like to hear others' opinions. I have been thinking this issue for 
> some years, but I still don't know a good answer.

A sane bash look alike would seem the best to me.  I don't have
problems with PHP-like syntax either.  As long as it is sane, looks
like other languages and is easy to learn.

Thanks,
Marco




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Pre-alpha scripting engine
  2005-01-19 20:04         ` Yoshinori K. Okuji
  2005-01-19 20:48           ` Marco Gerards
@ 2005-01-19 20:59           ` Tomas Ebenlendr
  1 sibling, 0 replies; 15+ messages in thread
From: Tomas Ebenlendr @ 2005-01-19 20:59 UTC (permalink / raw)
  To: The development of GRUB 2

> So a scripting language should fit into the semantics of the 
> command-line interface. For example, Lisp is not acceptable, because it 
> is too difficult to use as a shell. I don't know if PHP-like syntax 
> fulfills this requirement, but I don't like it very much, because PHP 
> is really similar to Perl (which is known as a maker of write-only 
> code).
> 
> I'd like to hear others' opinions. I have been thinking this issue for 
> some years, but I still don't know a good answer.
> 
> Okuji

PHP-like thing (or embedding LUA language) seems good to me because it
can be very small (#lines, #bytes - binary). On the other hand
shell-like thing will know many people (but it will not be regular bash,
with command `[', sed, and arrays and many other things that are need, when
you want to write a complex script), so I don't know if the shell-like
language will not be confusing because of not exactly same as sh. I'm
woting for simple shell-like language as primal language, and for
modules with extended languages, that can `compute' more complicated
things. I.e. grub-commands are same for both, but in the extended
language you can simply use asociative arrays and other advanced tools,
that are not needed in standard (=simple) scenario.
-- 
                                 Tomas 'ebi' Ebenlendr
                                 http://get.to/ebik
                                 PF 2005.05180384323




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Pre-alpha scripting engine
  2005-01-19 20:48           ` Marco Gerards
@ 2005-01-19 21:48             ` Maurizio Boriani
  2005-01-20 17:10               ` Serbinenko Vladimir
  0 siblings, 1 reply; 15+ messages in thread
From: Maurizio Boriani @ 2005-01-19 21:48 UTC (permalink / raw)
  To: The development of GRUB 2

>>>>> "Marco" == Marco Gerards <metgerards@student.han.nl> writes:

    >> I'd like to hear others' opinions. I have been thinking this
    >> issue for some years, but I still don't know a good answer.

    Marco> A sane bash look alike would seem the best to me.  I don't
    Marco> have problems with PHP-like syntax either.  As long as it
    Marco> is sane, looks like other languages and is easy to learn.

The use of guile (as specified in gnu standards) as embedded language 
should be a good choice :) but this is only an idea

bye

-- 
Maurizio Boriani 
GPG key: 0xCC0FBF8F
fingerprint => E429 A37C 5259 763C 9DEE  FC8B 5D61 C796 CC0F BF8F <= fingerprint




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Pre-alpha scripting engine
  2005-01-19 21:48             ` Maurizio Boriani
@ 2005-01-20 17:10               ` Serbinenko Vladimir
  2005-01-20 17:56                 ` Yoshinori K. Okuji
  0 siblings, 1 reply; 15+ messages in thread
From: Serbinenko Vladimir @ 2005-01-20 17:10 UTC (permalink / raw)
  To: The development of GRUB 2

Maurizio Boriani wrote:

>The use of guile (as specified in gnu standards) as embedded language 
>should be a good choice :) but this is only an idea
>
>bye
>
>  
>
The problem with guile is that it has no $ before variable which makes 
it difficult to integrate with shell. I discovered that bash and PHP can 
even coexist!!
But I don't know bash very well so if I'm wrong please e-mail it. Now 
I'm rewriting the parser for easier integrating(thanks Marco). At the 
same time it'll be combined PHP/bash blocks detector
Ambiguos operator I found is do in constuction like
for (...) do
    ..;
    while(...);
Can wcript end here? Is do ...; while (...); PHP or bash I propose 
folowing checking: if after ambiguos do there is operator and then while 
with ; it's PHP because in bash you have to write
while (...)
    do ...
If you really want that while is PHP but do is bash you can write
for (...) do
    ..;;
    while(...);
done;
Other my idea is to introduce #!bash and #!php commands to switch 
languages ex:
#!bash
for (...) do
    ..;
#!php
    while(...);
#!bash
done;
Perhaps also #!auto. But in my realisation they won't restrict using of 
other language but simply set that ambiguos constructions are php or bash.
What do you think about it all?
Please mail any your idea.




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Pre-alpha scripting engine
  2005-01-20 17:10               ` Serbinenko Vladimir
@ 2005-01-20 17:56                 ` Yoshinori K. Okuji
  2005-01-20 18:34                   ` Serbinenko Vladimir
  0 siblings, 1 reply; 15+ messages in thread
From: Yoshinori K. Okuji @ 2005-01-20 17:56 UTC (permalink / raw)
  To: The development of GRUB 2

On Thursday 20 January 2005 18:10, Serbinenko Vladimir wrote:
> The problem with guile is that it has no $ before variable which
> makes it difficult to integrate with shell. I discovered that bash
> and PHP can even coexist!!

As I said, Lisp is not good, because it is too difficult to use on the 
command-line interface. But I don't know if PHP is easy to use on it. I 
used PHP many years ago, but I forget it.

> But I don't know bash very well so if I'm wrong please e-mail it. Now
> I'm rewriting the parser for easier integrating(thanks Marco).

There are many differences. The critical point is that you cannot write 
this in PHP:

kernel /boot/vmlinuz root=/dev/hda1

This is not a valid expression in PHP. If you want to do the same in 
PHP, it could look like this:

kernel("/boot/vmlinuz", "root=/dev/hda1")

As I mentioned in the previous mail, I don't think it is a good idea to 
have multiple languages. So the important question here is if you want 
to use PHP on the command-line interface or not. I suspect that this is 
not feasible.

If your intention is to make your scripting engine standard in GRUB, I'd 
recommend considering what you really want to do with a scripting 
language under GRUB. IIRC, you haven't described what your motivation 
is.

I think the choice of a scripting language depends on what we really 
want to address. In other words, what do we want to define as the scope 
of a scripting language? Do we want to remove C code as much as 
possible, or, do we want to have a merely preprocessor? It is not a new 
idea to have a scripting language to make low-level functions (suppose 
Forth on Open Firmware), but I doubt if this is worth doing, because 
writing an interpreter can be more complex than writing device drivers.

Okuji



^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Pre-alpha scripting engine
  2005-01-20 17:56                 ` Yoshinori K. Okuji
@ 2005-01-20 18:34                   ` Serbinenko Vladimir
  2005-01-21  2:26                     ` Hollis Blanchard
  2005-01-23 14:22                     ` Pre-alpha scripting engine Yoshinori K. Okuji
  0 siblings, 2 replies; 15+ messages in thread
From: Serbinenko Vladimir @ 2005-01-20 18:34 UTC (permalink / raw)
  To: The development of GRUB 2

Yoshinori K. Okuji wrote:

>On Thursday 20 January 2005 18:10, Serbinenko Vladimir wrote:
>  
>
>>The problem with guile is that it has no $ before variable which
>>makes it difficult to integrate with shell. I discovered that bash
>>and PHP can even coexist!!
>>    
>>
>
>As I said, Lisp is not good, because it is too difficult to use on the 
>command-line interface. But I don't know if PHP is easy to use on it. I 
>used PHP many years ago, but I forget it.
>
>  
>
>>But I don't know bash very well so if I'm wrong please e-mail it. Now
>>I'm rewriting the parser for easier integrating(thanks Marco).
>>    
>>
>
>There are many differences. The critical point is that you cannot write 
>this in PHP:
>
>kernel /boot/vmlinuz root=/dev/hda1
>  
>
Normally not but it's easy to extend it

>This is not a valid expression in PHP. If you want to do the same in 
>PHP, it could look like this:
>
>kernel("/boot/vmlinuz", "root=/dev/hda1")
>
>As I mentioned in the previous mail, I don't think it is a good idea to 
>have multiple languages. So the important question here is if you want 
>to use PHP on the command-line interface or not. I suspect that this is 
>not feasible.
>
>  
>
Imho multiple languages will just wasting of time. As a matter of fact 
my prevous letter was just some thoughts

>If your intention is to make your scripting engine standard in GRUB, I'd 
>recommend considering what you really want to do with a scripting 
>language under GRUB. IIRC, you haven't described what your motivation 
>is.
>
>  
>
My motivation is an automatisation of booting e.g. run different 
commands depending on circumstances (time, system crash, wake-on-..., 
undoing booting preparation(hide,unhide,...))

>I think the choice of a scripting language depends on what we really 
>want to address. In other words, what do we want to define as the scope 
>of a scripting language? Do we want to remove C code as much as 
>possible, or, do we want to have a merely preprocessor? It is not a new 
>idea to have a scripting language to make low-level functions (suppose 
>Forth on Open Firmware), but I doubt if this is worth doing, because 
>writing an interpreter can be more complex than writing device drivers.
>
>  
>
I think that low-level scripting language will be an error but perhaps 
some easy scripts like running cmp with MBR and file parsing its output 
and pausing booting if difference detected

>Okuji
>
>  
>
So I'm waiting for your decision about language. But after all now I 
think that bash will be good idea

>_______________________________________________
>Grub-devel mailing list
>Grub-devel@gnu.org
>http://lists.gnu.org/mailman/listinfo/grub-devel
>
>
>  
>




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Pre-alpha scripting engine
  2005-01-20 18:34                   ` Serbinenko Vladimir
@ 2005-01-21  2:26                     ` Hollis Blanchard
  2005-01-21 17:23                       ` Scripting, partitions and filesystems Serbinenko Vladimir
  2005-01-21 17:52                       ` Device syntax, scripting, " Serbinenko Vladimir
  2005-01-23 14:22                     ` Pre-alpha scripting engine Yoshinori K. Okuji
  1 sibling, 2 replies; 15+ messages in thread
From: Hollis Blanchard @ 2005-01-21  2:26 UTC (permalink / raw)
  To: The development of GRUB 2

On Jan 20, 2005, at 12:34 PM, Serbinenko Vladimir wrote:

> Yoshinori K. Okuji wrote:
>
>> If your intention is to make your scripting engine standard in GRUB, 
>> I'd recommend considering what you really want to do with a scripting 
>> language under GRUB. IIRC, you haven't described what your motivation 
>> is.
>>
> My motivation is an automatisation of booting e.g. run different 
> commands depending on circumstances (time, system crash, wake-on-..., 
> undoing booting preparation(hide,unhide,...))

I'm also curious about this. Could you provide some easily understood 
examples (in the syntax of your choosing)? What I mean is: if your 
ideal script engine were already part of GRUB, what scripts would you 
use with it? Don't just describe them; instead put them into an email.

-Hollis




^ permalink raw reply	[flat|nested] 15+ messages in thread

* Scripting, partitions and filesystems
  2005-01-21  2:26                     ` Hollis Blanchard
@ 2005-01-21 17:23                       ` Serbinenko Vladimir
  2005-01-21 17:52                       ` Device syntax, scripting, " Serbinenko Vladimir
  1 sibling, 0 replies; 15+ messages in thread
From: Serbinenko Vladimir @ 2005-01-21 17:23 UTC (permalink / raw)
  To: The development of GRUB 2

Hollis Blanchard wrote:

> On Jan 20, 2005, at 12:34 PM, Serbinenko Vladimir wrote:
>
> I'm also curious about this. Could you provide some easily understood 
> examples (in the syntax of your choosing)? What I mean is: if your 
> ideal script engine were already part of GRUB, what scripts would you 
> use with it? Don't just describe them; instead put them into an email.
>
> -Hollis
>
>
For me scripting is necessary thing to write some features.
So examples
if bash:
#Wake-on-time at 17:02
if (((s=`time +"%H:%M"`)>="17:00" && s<="17:05")) then
    default=4;
    timeout=10;
else
    default=0;
    timeout=-1;
fi
if PHP
//Wake-on-time at 17:02
if((s=`time +"%H:%M"`)>="17:00" && s<="17:05")
{
    $_ENV["default"]=4;
    $_ENV["timeout"]=10;
}
else
{
    $_ENV["default"]=0;
    $_ENV["timeout"]=-1;
}
Bad OSes(just like windows)
togpt <device>
is a command that moves partition to GRUB Partion table invisible for 
OSes. In some bootloaders it's called something like many primary 
partiotions or EMBR
toprim <number> <device>
is the inverse <number> is an indication what slot in MBR to use.
For this feature some modifications are necessary to partition names as 
it must be independent if part is MBR/GPT/logic. I think that we can 
have two modules: gpt and pc
pc- standart pc parts
gpt- with gpt support and partition names by physical position
SAVEDBOOLS is array of bools stored in a file
#bash version
if((SAVEDBOOLS[0])); then
    togpt (hd0,4);
    SAVEDBOOLS[0]=0;
fi
...
title windows
toprim 0 (hd0,4);
SAVEDBOOLS[0]=1;
...
//PHP version script file
if($_SAVEDBOOLS[0])
{
    `togpt (hd0,4)`;
    $_SAVEDBOOLS[0]=0;
}
function win1boot(){
    $_SAVEDBOOLS[0]=1;
    `toprim 0 (hd0,4)`;
...
}

menu file:
....
script $prefix/scr.grb
...
title windows
eval win1boot()

Third example:fso
exchangefso is a command to exchange FileSystem Objects like
exchangefso /grubhid/win1/windows /windows
and /grubhid/win1/windows and /windows will be exchanged just by 
exchanging directory entries
#bash example
#run: win_undo <number> <dir>
function win_undo()
{
    if((SAVEDBOOLS[$0])); then
       for u in $1/*; do
           if ((u!="$1\/bsect.bin"))
           exchangefso $u ${u:$(strlen $1)};
       done;
       SAVEDBOOLS[$0]=0;
    fi
}
function winboot()
{
       for u in $1/*; do
           if ((u!="$1\/bsect.bin"))
           exchangefso $u ${u:$(strlen $1)};
       done;
       SAVEDBOOLS[$0]=1;
       chainloader $1/bsect.bin;
}
...
root <device>
win_undo 1 /grubhid/win1
...
title windows
root <device>
winboot 1 /grubhid/win1
...
//PHP example
function win_undo($num,$dir)
{
    if($_SAVEDBOOLS[$num])
    {
       foreach(glob("$dir/*") as $u)
           if ($u!="$dir/bsect.bin")
               shell_execute("exchangefso $u ".substr($u,strlen($dir)));
       $_SAVEDBOOLS[$num]=0;
    }
}
function winboot()
{
       foreach(glob("$dir/*") as $u)
           if ($u!="$dir/bsect.bin")
               shell_execute("exchangefso $u ".substr($u,strlen($dir)));
       $_SAVEDBOOLS[$num]=1;
       `chainloader $dir/bsect.bin`;
}

menu file:
..
script $prefix/w32s.grb
..
root <device>
eval win_undo(1,"/grubhid/win1");

...
title windows
root <device>
eval winboot(1,"/grubhid/win1");

Some questions about future gpt:
do you think that format of gpt like
GPT2<4 bytes reserved><records>
And every record is
<4 bytes part begin><4 bytes part end><1 byte type>
And it takes 1 sector. So you can have 56 gpt partitions
And parts numbers will be in order of physical position.
About fso exchange I think that exchanging must be without name as in 
many filesystems name has dynamic sizeor for FAT we will have no 
problems with long names. OK?

P.S. I haven't had a lot of time to write this letter. Rorry for 
possible erorrs








^ permalink raw reply	[flat|nested] 15+ messages in thread

* Device syntax, scripting, partitions and filesystems
  2005-01-21  2:26                     ` Hollis Blanchard
  2005-01-21 17:23                       ` Scripting, partitions and filesystems Serbinenko Vladimir
@ 2005-01-21 17:52                       ` Serbinenko Vladimir
  1 sibling, 0 replies; 15+ messages in thread
From: Serbinenko Vladimir @ 2005-01-21 17:52 UTC (permalink / raw)
  To: The development of GRUB 2

About device syntax. What realising quotting or escaping support like:

(/pci@1f\,0/pci@1\,1/ide@3/disk@0\,0)/path/file
Or
("/pci@1f,0/pci@1,1/ide@3/disk@0,0")/path/file

I haven't recieved my copy of this letter. I suppose some e-mail 
problems. So I resend it. Sorry if recieved twice
Hollis Blanchard wrote:

> On Jan 20, 2005, at 12:34 PM, Serbinenko Vladimir wrote:
>
> I'm also curious about this. Could you provide some easily understood 
> examples (in the syntax of your choosing)? What I mean is: if your 
> ideal script engine were already part of GRUB, what scripts would you 
> use with it? Don't just describe them; instead put them into an email.
>
> -Hollis
>
>
For me scripting is necessary thing to write some features.
So examples
if bash:
#Wake-on-time at 17:02
if (((s=`time +"%H:%M"`)>="17:00" && s<="17:05")) then
    default=4;
    timeout=10;
else
    default=0;
    timeout=-1;
fi
if PHP
//Wake-on-time at 17:02
if((s=`time +"%H:%M"`)>="17:00" && s<="17:05")
{
    $_ENV["default"]=4;
    $_ENV["timeout"]=10;
}
else
{
    $_ENV["default"]=0;
    $_ENV["timeout"]=-1;
}
Bad OSes(just like windows)
togpt <device>
is a command that moves partition to GRUB Partion table invisible for
OSes. In some bootloaders it's called something like many primary
partiotions or EMBR
toprim <number> <device>
is the inverse <number> is an indication what slot in MBR to use.
For this feature some modifications are necessary to partition names as
it must be independent if part is MBR/GPT/logic. I think that we can
have two modules: gpt and pc
pc- standart pc parts
gpt- with gpt support and partition names by physical position
SAVEDBOOLS is array of bools stored in a file
#bash version
if((SAVEDBOOLS[0])); then
    togpt (hd0,4);
    SAVEDBOOLS[0]=0;
fi
...
title windows
toprim 0 (hd0,4);
SAVEDBOOLS[0]=1;
...
//PHP version script file
if($_SAVEDBOOLS[0])
{
    `togpt (hd0,4)`;
    $_SAVEDBOOLS[0]=0;
}
function win1boot(){
    $_SAVEDBOOLS[0]=1;
    `toprim 0 (hd0,4)`;
...
}

menu file:
....
script $prefix/scr.grb
...
title windows
eval win1boot()

Third example:fso
exchangefso is a command to exchange FileSystem Objects like
exchangefso /grubhid/win1/windows /windows
and /grubhid/win1/windows and /windows will be exchanged just by
exchanging directory entries
#bash example
#run: win_undo <number> <dir>
function win_undo()
{
    if((SAVEDBOOLS[$0])); then
       for u in $1/*; do
           if ((u!="$1\/bsect.bin"))
           exchangefso $u ${u:$(strlen $1)};
       done;
       SAVEDBOOLS[$0]=0;
    fi
}
function winboot()
{
       for u in $1/*; do
           if ((u!="$1\/bsect.bin"))
           exchangefso $u ${u:$(strlen $1)};
       done;
       SAVEDBOOLS[$0]=1;
       chainloader $1/bsect.bin;
}
...
root <device>
win_undo 1 /grubhid/win1
...
title windows
root <device>
winboot 1 /grubhid/win1
...
//PHP example
function win_undo($num,$dir)
{
    if($_SAVEDBOOLS[$num])
    {
       foreach(glob("$dir/*") as $u)
           if ($u!="$dir/bsect.bin")
               shell_execute("exchangefso $u ".substr($u,strlen($dir)));
       $_SAVEDBOOLS[$num]=0;
    }
}
function winboot()
{
       foreach(glob("$dir/*") as $u)
           if ($u!="$dir/bsect.bin")
               shell_execute("exchangefso $u ".substr($u,strlen($dir)));
       $_SAVEDBOOLS[$num]=1;
       `chainloader $dir/bsect.bin`;
}

menu file:
..
script $prefix/w32s.grb
..
root <device>
eval win_undo(1,"/grubhid/win1");

...
title windows
root <device>
eval winboot(1,"/grubhid/win1");

Some questions about future gpt:
do you think that format of gpt like
GPT2<4 bytes reserved><records>
And every record is
<4 bytes part begin><4 bytes part end><1 byte type>
And it takes 1 sector. So you can have 56 gpt partitions
And parts numbers will be in order of physical position.
About fso exchange I think that exchanging must be without name as in
many filesystems name has dynamic sizeor for FAT we will have no
problems with long names. OK?

P.S. I haven't had a lot of time to write this letter. Rorry for
possible erorrs









^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: Pre-alpha scripting engine
  2005-01-20 18:34                   ` Serbinenko Vladimir
  2005-01-21  2:26                     ` Hollis Blanchard
@ 2005-01-23 14:22                     ` Yoshinori K. Okuji
  1 sibling, 0 replies; 15+ messages in thread
From: Yoshinori K. Okuji @ 2005-01-23 14:22 UTC (permalink / raw)
  To: The development of GRUB 2

On Thursday 20 January 2005 19:34, Serbinenko Vladimir wrote:
> So I'm waiting for your decision about language. But after all now I
> think that bash will be good idea

For now, I conclude that BASH is the best. If you get another idea, let 
me know.

Okuji



^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2005-01-23 15:02 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <E1CpUhp-000IYX-00.grub-devel-bounces+serbinenko-vova=list-ru-gnu-org@mx11.mail.ru>
2005-01-14 18:48 ` Pre-alpha scripting engine Serbinenko Vladimir
2005-01-18 18:55   ` Marco Gerards
2005-01-18 19:54     ` Serbinenko Vladimir
2005-01-19 13:01       ` Marco Gerards
2005-01-19 20:04         ` Yoshinori K. Okuji
2005-01-19 20:48           ` Marco Gerards
2005-01-19 21:48             ` Maurizio Boriani
2005-01-20 17:10               ` Serbinenko Vladimir
2005-01-20 17:56                 ` Yoshinori K. Okuji
2005-01-20 18:34                   ` Serbinenko Vladimir
2005-01-21  2:26                     ` Hollis Blanchard
2005-01-21 17:23                       ` Scripting, partitions and filesystems Serbinenko Vladimir
2005-01-21 17:52                       ` Device syntax, scripting, " Serbinenko Vladimir
2005-01-23 14:22                     ` Pre-alpha scripting engine Yoshinori K. Okuji
2005-01-19 20:59           ` Tomas Ebenlendr

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.