1 |
/* misc.c - definitions of misc functions */ |
/* misc.c - definitions of misc functions */ |
2 |
/* |
/* |
3 |
* GRUB -- GRand Unified Bootloader |
* GRUB -- GRand Unified Bootloader |
4 |
* Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc. |
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005 Free Software Foundation, Inc. |
5 |
* |
* |
6 |
* GRUB is free software; you can redistribute it and/or modify |
* GRUB is free software; you can redistribute it and/or modify |
7 |
* it under the terms of the GNU General Public License as published by |
* it under the terms of the GNU General Public License as published by |
874 |
|
|
875 |
return p - dest; |
return p - dest; |
876 |
} |
} |
|
|
|
|
grub_err_t |
|
|
grub_split_cmdline (const char *cmdline, grub_err_t (*getline) (char **), |
|
|
int *argc, char ***argv) |
|
|
{ |
|
|
/* XXX: Fixed size buffer, perhaps this buffer should be dynamically |
|
|
allocated. */ |
|
|
char buffer[1024]; |
|
|
char *bp = buffer; |
|
|
char *rd = (char *) cmdline; |
|
|
char unputbuf; |
|
|
int unput = 0; |
|
|
char *args; |
|
|
int i; |
|
|
|
|
|
auto char getchar (void); |
|
|
auto void unputc (char c); |
|
|
auto void getenvvar (void); |
|
|
auto int getarg (void); |
|
|
|
|
|
/* Get one character from the commandline. If the caller reads |
|
|
beyond the end of the string a new line will be read. This |
|
|
function will not chech for errors, the caller has to check for |
|
|
grub_errno. */ |
|
|
char getchar (void) |
|
|
{ |
|
|
int c; |
|
|
if (unput) |
|
|
{ |
|
|
unput = 0; |
|
|
return unputbuf; |
|
|
} |
|
|
|
|
|
if (! rd) |
|
|
{ |
|
|
getline (&rd); |
|
|
/* Error is ignored here, the caller will check for this |
|
|
when it reads beyond the EOL. */ |
|
|
c = *(rd)++; |
|
|
return c; |
|
|
} |
|
|
|
|
|
c = *(rd)++; |
|
|
if (! c) |
|
|
{ |
|
|
rd = 0; |
|
|
return '\n'; |
|
|
} |
|
|
|
|
|
return c; |
|
|
} |
|
|
|
|
|
void unputc (char c) |
|
|
{ |
|
|
unputbuf = c; |
|
|
unput = 1; |
|
|
} |
|
|
|
|
|
/* Read a variable name from the commandline and insert its content |
|
|
into the buffer. */ |
|
|
void getenvvar (void) |
|
|
{ |
|
|
char varname[100]; |
|
|
char *p = varname; |
|
|
char *val; |
|
|
char c; |
|
|
|
|
|
c = getchar (); |
|
|
if (c == '{') |
|
|
while ((c = getchar ()) != '}') |
|
|
*(p++) = c; |
|
|
else |
|
|
{ |
|
|
/* XXX: An env. variable can have characters and digits in |
|
|
its name, are more characters allowed here? */ |
|
|
while (c && (grub_isalpha (c) || grub_isdigit (c))) |
|
|
{ |
|
|
*(p++) = c; |
|
|
c = getchar (); |
|
|
} |
|
|
unputc (c); |
|
|
} |
|
|
*p = '\0'; |
|
|
|
|
|
/* The variable does not exist. */ |
|
|
val = grub_env_get (varname); |
|
|
if (! val) |
|
|
return; |
|
|
|
|
|
/* Copy the contents of the variable into the buffer. */ |
|
|
for (p = val; *p; p++) |
|
|
*(bp++) = *p; |
|
|
} |
|
|
|
|
|
/* Read one argument. Return 1 if no variables can be read anymore, |
|
|
otherwise return 0. If there is an error, return 1, the caller |
|
|
has to check grub_errno. */ |
|
|
int getarg (void) |
|
|
{ |
|
|
char c; |
|
|
|
|
|
/* Skip all whitespaces before an argument. */ |
|
|
do { |
|
|
c = getchar (); |
|
|
} while (c == ' ' || c == '\t'); |
|
|
|
|
|
do { |
|
|
switch (c) |
|
|
{ |
|
|
case '"': |
|
|
/* Double quote. */ |
|
|
while ((c = getchar ())) |
|
|
{ |
|
|
if (grub_errno) |
|
|
return 1; |
|
|
/* Read in an escaped character. */ |
|
|
if (c == '\\') |
|
|
{ |
|
|
c = getchar (); |
|
|
*(bp++) = c; |
|
|
continue; |
|
|
} |
|
|
else if (c == '"') |
|
|
break; |
|
|
/* Read a variable. */ |
|
|
if (c == '$') |
|
|
{ |
|
|
getenvvar (); |
|
|
continue; |
|
|
} |
|
|
*(bp++) = c; |
|
|
} |
|
|
break; |
|
|
|
|
|
case '\'': |
|
|
/* Single quote. */ |
|
|
while ((c = getchar ()) != '\'') |
|
|
{ |
|
|
if (grub_errno) |
|
|
return 1; |
|
|
|
|
|
*(bp++) = c; |
|
|
} |
|
|
break; |
|
|
|
|
|
case '\n': |
|
|
/* This was not a argument afterall. */ |
|
|
return 1; |
|
|
|
|
|
default: |
|
|
/* A normal option. */ |
|
|
while (c && (grub_isalpha (c) |
|
|
|| grub_isdigit (c) || grub_isgraph (c))) |
|
|
{ |
|
|
/* Read in an escaped character. */ |
|
|
if (c == '\\') |
|
|
{ |
|
|
c = getchar (); |
|
|
*(bp++) = c; |
|
|
c = getchar (); |
|
|
continue; |
|
|
} |
|
|
/* Read a variable. */ |
|
|
if (c == '$') |
|
|
{ |
|
|
getenvvar (); |
|
|
c = getchar (); |
|
|
continue; |
|
|
} |
|
|
*(bp++) = c; |
|
|
c = getchar (); |
|
|
} |
|
|
unputc (c); |
|
|
|
|
|
break; |
|
|
} |
|
|
} while (! grub_isspace (c) && c != '\'' && c != '"'); |
|
|
|
|
|
return 0; |
|
|
} |
|
|
|
|
|
/* Read in all arguments and count them. */ |
|
|
*argc = 0; |
|
|
while (1) |
|
|
{ |
|
|
if (getarg ()) |
|
|
break; |
|
|
*(bp++) = '\0'; |
|
|
(*argc)++; |
|
|
} |
|
|
|
|
|
/* Check if there were no errors. */ |
|
|
if (grub_errno) |
|
|
return grub_errno; |
|
|
|
|
|
/* Reserve memory for the return values. */ |
|
|
args = grub_malloc (bp - buffer); |
|
|
if (! args) |
|
|
return grub_errno; |
|
|
grub_memcpy (args, buffer, bp - buffer); |
|
|
|
|
|
*argv = grub_malloc (sizeof (char *) * (*argc + 1)); |
|
|
if (! *argv) |
|
|
{ |
|
|
grub_free (args); |
|
|
return grub_errno; |
|
|
} |
|
|
|
|
|
/* The arguments are separated with 0's, setup argv so it points to |
|
|
the right values. */ |
|
|
bp = args; |
|
|
for (i = 0; i < *argc; i++) |
|
|
{ |
|
|
(*argv)[i] = bp; |
|
|
while (*bp) |
|
|
bp++; |
|
|
bp++; |
|
|
} |
|
|
|
|
|
(*argc)--; |
|
|
return 0; |
|
|
} |
|