grub-devel
[Top][All Lists]
Advanced

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

Scripting framework


From: Marco Gerards
Subject: Scripting framework
Date: Sun, 23 Oct 2005 16:05:46 +0200
User-agent: Gnus/5.1007 (Gnus v5.10.7) Emacs/21.4 (gnu/linux)

Hi,

In the last emails we discussed scripting support.  Because it was
quite hard to explain everything and it was quite easy to implement
the basic framework we can use to implement scripting I just did some
hacking.

It is not complete scripting support.  All it is is just a structure
to work from.  It also shows how we can implement menu entries and
functions (I have written function support, which is just a conceptual
one liner now :-)).

Now I have to learn for some exams (like I had to do this afternoon
when I was working on this code :-/).  I will clean all this up next
week and make sure it can be used by GRUB, instead of just a few
separate files.

Vladimir, there is still enough to do, don't be worried.  I will stop
right after the basics work (just see how little amount of code it is
so far).  I am not interested in writing complete scripting support
now.

To parse a script in `char *cmdline' you can use the following
commands using this code:

  set_lex (cmdline);
  yyparse ();
  grub_execute_cmd (grub_script_parsed);

grub_script_parsed is a global at the moment, but I will make that
cleaner.  It contains the complete parsed scripted after running
yyparse.  grub_execute_cmd executes the script.  Have a look at that
function, it is easy to understand how it works and how to extend it.
The same thing can be used for menu entries and functions, just use
`struct grub_script_cmd *' to store a function.  And the function can
be executed by grub_execute_cmd.

If you have any questions or comments please tell me.  You just have
to know that the code is not yet finished, so no need to proof read
it; it is full of bugs and ugliness.

Thanks,
Marco



/* scripting.h  */
/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2005  Free Software Foundation, Inc.
 *
 *  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.
 */

struct grub_script_arglist
{
  struct grub_script_arglist *next;
  char *arg;
};

typedef enum
{
  GRUB_CMDTYPE_CMDLINE,
  GRUB_CMDTYPE_BLOCK,
  GRUB_CMDTYPE_IF
} grub_script_command_type_t;

struct grub_script_cmd
{
  grub_script_command_type_t cmdtype;
  struct grub_script_cmd *next;
};

struct grub_script_cmdline
{
  struct grub_script_cmd cmd;
  struct grub_script_arglist *arglist;
  char *cmdname;
};

struct grub_script_cmdblock
{
  struct grub_script_cmd cmd;
  struct grub_script_cmd *cmdlist;
};

struct grub_script_arglist *grub_script_create_arglist (void);
struct grub_script_arglist *grub_script_add_arglist (struct grub_script_arglist 
*list, char *arg);
struct grub_script_cmd *grub_script_create_cmdline (char *cmdname, struct 
grub_script_arglist *arglist);
struct grub_script_cmd *grub_script_create_cmdblock (void);
struct grub_script_cmd *grub_script_add_cmd (struct grub_script_cmdblock 
*cmdblock, struct grub_script_cmd *cmd);

extern struct grub_script_cmd *grub_script_parsed;

void grub_execute_cmd (struct grub_script_cmd *cmd);


--------------------------------------------------------------------------------

/* lexer.c - The scripting lexer.  */
/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2005  Free Software Foundation, Inc.
 *
 *  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.
 */

#include <grub/parser.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include "parser.tab.h"

static grub_parser_state_t state;
static char *script;

static int
check_varstate (grub_parser_state_t state)
{
  return (state == GRUB_PARSER_STATE_VARNAME
          || state == GRUB_PARSER_STATE_VARNAME2
          || state == GRUB_PARSER_STATE_QVARNAME
          || state == GRUB_PARSER_STATE_QVARNAME2);
}


void
set_lex (char *s)
{
  state = GRUB_PARSER_STATE_TEXT;
  script = s;
}

int
yylex (void)
{
  char *buffer;
  char *bp;
  char use;
  grub_parser_state_t newstate;

  buffer = (char *) grub_malloc (4096);
  bp = buffer;

  if (!*script)
    return 0;

  while (*script)
    {
      newstate = grub_parser_cmdline_state (state, *script, &use);

      if (check_varstate (state) && ! check_varstate (newstate))
        break;

      if (newstate == GRUB_PARSER_STATE_TEXT
          && state != GRUB_PARSER_STATE_ESC && use == ' ')
        {
          /* Don't add more than one space if multiple spaces are
             used.  */
          if (bp != buffer && *(bp - 1))
            {
              script++;
              break;
            }
        }
      else if (use)
        *(bp++) = use;

      script++;
      state = newstate;
    }
  *bp = '\0';

  yylval.string = buffer;

  if (check_varstate (state))
    return GRUB_PARSER_TOKEN_VAR;
  else if (! grub_strcmp (buffer, "while"))
    return GRUB_PARSER_TOKEN_WHILE;
  else if (! grub_strcmp (buffer, "if"))
    return GRUB_PARSER_TOKEN_IF;
  else if (! grub_strcmp (buffer, "function"))
    return GRUB_PARSER_TOKEN_FUNCTION;
  else if (! grub_strcmp (buffer, "{"))
    return GRUB_PARSER_TOKEN_OBRACE;
  else if (! grub_strcmp (buffer, "}"))
    return GRUB_PARSER_TOKEN_CBRACE;
  else
    return GRUB_PARSER_TOKEN_NAME;
}


void
yyerror (char const *err)
{
  grub_printf (err);
}

--------------------------------------------------------------------------------

/* parser.y - The scripting parser.  */
/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2005  Free Software Foundation, Inc.
 *
 *  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.
 */

%{
#include <grub/scripting.h>


%}

%union {
  struct grub_script_cmd *cmd;
  struct grub_script_arglist *arglist;
  char *string;
}

%token GRUB_PARSER_TOKEN_IF             "if"
%token GRUB_PARSER_TOKEN_WHILE          "while"
%token GRUB_PARSER_TOKEN_FUNCTION       "function"
%token GRUB_PARSER_TOKEN_OBRACE         "{"
%token GRUB_PARSER_TOKEN_CBRACE         "}"
%token GRUB_PARSER_TOKEN_NAME
%token GRUB_PARSER_TOKEN_VAR
%type <cmd> script grubcmd commands
%type <arglist> arguments;
%type <string> text "if" "while" GRUB_PARSER_TOKEN_NAME
%%
/* It should be possible to do this in a clean way...  */
script:         commands        { grub_script_parsed = $1; }
                | function

text:           GRUB_PARSER_TOKEN_NAME                  { $$ = $1;              
        }
                | "if"                                  { $$ = $1;              
        }
                | "while"                               { $$ = $1;              
        }
;


arguments:      /* Empty */                             { $$ = 
grub_script_create_arglist ();           }
                | arguments text                        { $$ = 
grub_script_add_arglist ($1, $2);                }
;

grubcmd:        GRUB_PARSER_TOKEN_NAME arguments        { $$ = 
grub_script_create_cmdline ($1, $2);             }
;

commands:       /* Empty */                             { $$ = 
grub_script_create_cmdblock ();          }
                | commands grubcmd                      { $$ = 
grub_script_add_cmd ((struct grub_script_cmdblock *) $1, $2);            }
;

function:       "function" GRUB_PARSER_TOKEN_NAME "{" commands "}" { 
grub_script_create_function ($2, $4); }

/*              | commands "if"         { $$ = grub_script_add_cmd ((struct 
cmd_cmdblock *) $1, $2);            }*/

%%


--------------------------------------------------------------------------------

/* script.c */
/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2005  Free Software Foundation, Inc.
 *
 *  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.
 */

#include <grub/misc.h>
#include <grub/scripting.h>
#include <grub/parser.h>
#include <grub/mm.h>


struct grub_script_arglist *
grub_script_create_arglist (void)
{
  struct grub_script_arglist *link;

  link = (struct grub_script_arglist *) grub_malloc (sizeof (*link));
  link->next = 0;
  link->arg = 0;
  return link;
}

struct grub_script_arglist *
grub_script_add_arglist (struct grub_script_arglist *list, char *arg)
{
  struct grub_script_arglist *link;
  struct grub_script_arglist *ll;

  /* XXX: Perhaps we can just create a character array with '\0'
     separators right away.  */
  
  link = (struct grub_script_arglist *) grub_malloc (sizeof (*link));
  link->next = 0;
  link->arg = arg;

  /* Look up the last link in the chain.  */
  for (ll = list; list->next; list = list->next);

  ll->next = link;
  return list;
}

struct grub_script_cmd *
grub_script_create_cmdline (char *cmdname, struct grub_script_arglist *arglist)
{
  struct grub_script_cmdline *cmd;
  
  cmd = grub_malloc (sizeof (*cmd));
  cmd->cmd.cmdtype = GRUB_CMDTYPE_CMDLINE;
  cmd->cmd.next = 0;
  cmd->arglist = arglist;
  cmd->cmdname = cmdname;

  return (struct grub_script_cmd *) cmd;
}

struct grub_script_cmd *
grub_script_create_cmdblock (void)
{
  struct grub_script_cmdblock *cmdblock;

  cmdblock = (struct grub_script_cmdblock *) grub_malloc (sizeof (*cmdblock));
  cmdblock->cmd.cmdtype = GRUB_CMDTYPE_BLOCK;
  cmdblock->cmd.next = 0;
  cmdblock->cmdlist = 0;

  return (struct grub_script_cmd *) cmdblock;
}

struct grub_script_cmd *
grub_script_add_cmd (struct grub_script_cmdblock *cmdblock, struct 
grub_script_cmd *cmd)
{
  struct grub_script_cmd **last;

  for (last = &cmdblock->cmdlist; *last; last = &(*last)->next);

  *last = cmd;
  cmd->next = 0;

  return (struct grub_script_cmd *) cmdblock;
}

void
grub_script_create_function (char *functionname, struct grub_script_cmd *cmd)
{
  /* Register the function FUNCTIONNAME.  After that it can be called
     using a standard GRUB command.  */

  grub_printf ("Register function `%s'\n", functionname);
}

--------------------------------------------------------------------------------

/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2005  Free Software Foundation, Inc.
 *
 *  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.
 */

#include <grub/misc.h>
#include <grub/scripting.h>

/* Execute GRUB scripts.  */

struct grub_script_cmd *grub_script_parsed = 0;

static void
grub_execute_cmdline (struct grub_script_cmdline *cmdline)
{
  struct grub_script_arglist *arglist;
  int i = 1;
  
  grub_printf ("Command name: `%s'\n", cmdline->cmdname);
  for (arglist = cmdline->arglist->next; arglist; arglist = arglist->next)
    grub_printf ("Argument %d) %s\n", i++, arglist->arg);
}
  
static void
grub_execute_cmdblock (struct grub_script_cmdblock *cmdblock)
{
  struct grub_script_cmd *cmd;

  grub_printf ("Executing block of commands\n");
  /* Loop over every command and execute it.  */
  for (cmd = cmdblock->cmdlist; cmd; cmd = cmd->next)
    grub_execute_cmd (cmd);
}

/* static grub_execute_cmdif (struct grub_script_cmdline *cmd) */
/* { */

/* } */

void
grub_execute_cmd (struct grub_script_cmd *cmd)
{
  if (cmd == 0)
    {
      /* XXX */
      grub_printf ("No script!\n");
      return;
    }

  grub_printf ("Execute: %d\n", cmd->cmdtype);  
  switch (cmd->cmdtype)
    {
    case GRUB_CMDTYPE_CMDLINE:
      grub_execute_cmdline ((struct grub_script_cmdline *) cmd);
      break;

    case GRUB_CMDTYPE_BLOCK:
      grub_execute_cmdblock ((struct grub_script_cmdblock *) cmd);
      break;

    case GRUB_CMDTYPE_IF:
      /*       grub_execute_cmdif ((struct grub_script_cmdif *) cmd); */
      break;
    }
}





reply via email to

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