#include <getopt.h>
#include <errno.h>
#include <assert.h>
-#include <gpxe/tables.h>
#include <gpxe/command.h>
-#include <gpxe/settings.h>
#include <gpxe/parse.h>
#include <gpxe/gen_stack.h>
{ .token = '\t', .type = ENDTOK }
};
-/**
- * Expand variables within command line
- *
- * @v command Command line
- * @ret expcmd Expanded command line
- *
- * The expanded command line is allocated with malloc() and the caller
- * must eventually free() it.
- */
-int expand_command ( const char *command, struct generic_stack *argv_stack ) {
- char *expcmd;
+static int expand_command ( const char *command, struct generic_stack *argv_stack ) {
char *head, *end;
char *nstring;
- int argc = 0;
int success;
+ int argc;
- init_generic_stack ( argv_stack, sizeof ( char * ) );
+ struct string expcmd = { .value = NULL };
- /* Obtain temporary modifiable copy of command line */
- expcmd = strdup ( command );
- if ( ! expcmd )
- return -ENOMEM;
- head = expcmd;
+ argc = 0;
+ init_generic_stack ( argv_stack, sizeof ( int ) );
+
+ stringcpy ( &expcmd, command );
+ if ( ! expcmd.value ) {
+ argc = -ENOMEM;
+ return argc;
+ }
+ head = expcmd.value;
/* Expand while expansions remain */
while ( *head ) {
- while ( isspace ( *head ) )
+ while ( isspace ( *head ) ) {
+ *head = 0;
head++;
+ }
if ( *head == '#' ) { /* Comment is a new word that starts with # */
break;
}
- nstring = expand_string ( head, &end, table, 6, 0, &success );
+ stringcpy ( &expcmd, head );
+ head = expcmd.value;
+ nstring = expand_string ( &expcmd, &head, &end, table, 6, 0, &success );
if ( nstring ) {
if ( success ) {
- char *cur_argv;
argc++;
- cur_argv = calloc ( end - nstring + 1, 1);
-
- if ( cur_argv ) {
- strncpy ( cur_argv, nstring, end - nstring );
- if ( push_generic_stack ( argv_stack, &cur_argv, 0 ) < 0 ) {
- free ( cur_argv );
- free ( nstring );
- nstring = NULL;
- }
- } else {
- free ( nstring );
- nstring = NULL;
- }
+ push_generic_stack ( argv_stack, &expcmd.value, 0 );
+ expcmd.value = NULL;
+ stringcpy ( &expcmd, end );
+ *end = 0;
}
+ } else {
+ argc = -ENOMEM;
+ break;
}
- free ( expcmd );
-
- if ( !nstring ) {
- return -ENOMEM;
- }
- expcmd = nstring;
- head = end;
+ head = expcmd.value;
}
- free ( expcmd );
+ free_string ( &expcmd );
return argc;
}
struct generic_stack argv_stack;
argc = expand_command ( command, &argv_stack );
-
if ( argc < 0 ) {
rc = argc;
} else {
- char **argv = realloc ( argv_stack.ptr, ( argc + 1 ) * sizeof ( char * ) );
-
+ char **argv;
+
+ argv = realloc ( argv_stack.ptr, sizeof ( char * ) * ( argc + 1 ) );
if ( argv ) {
argv_stack.ptr = argv;
argv[argc] = NULL;
+
if ( argc > 0 )
rc = execv ( argv[0], argv );
- } else
- rc = -ENOMEM;
+ }
}
- free_generic_stack ( &argv_stack, 1 );
+ free_generic_stack ( &argv_stack, 0 );
return rc;
}
#define SEP1 -1
#define SEP2 -1, -1
-#ifndef __ARITH_TEST__
#define EPARSE (EINVAL | EUNIQ_01)
#define EDIV0 (EINVAL | EUNIQ_02)
#define ENOOP (EINVAL | EUNIQ_03)
#define EWRONGOP (EINVAL | EUNIQ_04)
-#else
-#define EPARSE 1
-#define EDIV0 2
-#define ENOOP 3
-#define EWRONGOP 4
-#endif
-static char *inp, *prev, *orig;
+static struct string *input_str;
+static char *inp_ptr = NULL;
static int tok;
static int err_val;
static union {
static void input ( void ) {
char t_op[3] = { '\0', '\0', '\0'};
char *p1, *p2;
- char *strtmp = NULL, *tmp;
+ char *tmp, *strtmp = NULL;
char *end;
int success;
if ( tok == -1 )
return;
- prev = inp;
ignore_whitespace();
- if ( *inp == '\0' ) {
+ if ( *inp_ptr == '\0' ) {
tok = -1;
return;
}
tok = 0;
- tmp = expand_string ( inp, &end, table, 21, 1, &success );
- inp = end;
- free ( orig );
-
+ tmp = expand_string ( input_str, &inp_ptr, &end, table, 21, 0, &success );
if ( !tmp ) {
tok = -1;
err_val = -ENOMEM;
return;
}
- orig = tmp;
if ( success ) {
- strtmp = calloc ( end - tmp + 1, 1 );
- strncpy ( strtmp, tmp, end - tmp );
+ strtmp = strndup ( inp_ptr, end - inp_ptr );
if ( isnum ( strtmp, &tok_value.num_value ) ) {
free ( strtmp );
tok = TOK_NUMBER;
tok_value.str_value = strtmp;
tok = TOK_STRING;
}
+ inp_ptr = end;
return;
}
/* Check for an operator */
- t_op[0] = *inp++;
+ t_op[0] = *inp_ptr++;
p1 = strstr ( op_table, t_op );
if ( !p1 ) { /* The character is not present in the list of operators */
tok = *t_op;
return;
}
- t_op[1] = *inp;
+ t_op[1] = *inp_ptr;
p2 = strstr ( op_table, t_op );
if ( !p2 || p1 == p2 ) {
if ( ( p1 - op_table ) % 3 ) { /* Without this, it would take '=' as '<=' */
tok = MIN_TOK + ( p1 - op_table ) / 3;
return;
}
- inp++;
+ inp_ptr++;
tok = MIN_TOK + ( p2 - op_table ) / 3;
}
}
static void ignore_whitespace ( void ) {
- while ( isspace ( *inp ) ) {
- inp++;
+ while ( isspace ( *inp_ptr ) ) {
+ inp_ptr++;
}
}
return parse_prio ( -1, buffer );
}
-int parse_arith ( const char *inp_string, char **end, char **buffer ) {
+int parse_arith ( struct string *inp, char *orig, char **end ) {
+ char *buffer = NULL;
+ int start;
+
+ start = orig - inp->value;
+
+ input_str = inp;
err_val = tok = 0;
- orig = strdup ( inp_string );
- inp = orig;
+ inp_ptr = orig + 1;
+
input();
- *buffer = NULL;
skip ( '(' );
- parse_expr ( buffer );
-
+ parse_expr ( &buffer );
if ( !err_val ) {
if ( tok != ')' ) {
- free ( *buffer );
+ free ( buffer );
err_val = -EPARSE;
+ } else {
+ orig = inp->value + start;
+ *orig = 0;
+ *end = inp_ptr;
+ orig = string3cat ( inp, buffer, *end );
+ *end = orig + start + strlen ( buffer );
}
}
- *end = inp;
- if ( err_val ) { //Read till we get a ')'
+ if ( err_val ) {
if ( tok == TOK_STRING )
free ( tok_value.str_value );
switch ( err_val ) {
printf("out of memory\n");
break;
}
+ free_string ( inp );
return err_val;
}
#include <stdlib.h>
#include <gpxe/settings.h>
-/* The returned string is allocated on the heap and the calling function must free it */
-char * dollar_expand ( char *inp, char ** end ) {
- char *expdollar;
- const char *name;
+char * string3cat ( struct string *s1, const char *s2, const char *s3 ) { /* The len is the size of s1 */
+ char *tmp = s1->value;
+ asprintf ( &s1->value, "%s%s%s", s1->value, s2, s3 );
+ free ( tmp );
+ return s1->value;
+}
+
+char * stringcpy ( struct string *s1, const char *s2 ) {
+ char *tmp = s1->value;
+ s1->value = strdup ( s2 );
+ free ( tmp );
+ return s1->value;
+}
+
+char * stringcat ( struct string *s1, const char *s2 ) {
+ char *tmp;
+ if ( !s1->value )
+ return stringcpy ( s1, s2 );
+ if ( !s2 )
+ return s1->value;
+ tmp = s1->value;
+ asprintf ( &s1->value, "%s%s", s1->value, s2 );
+ free ( tmp );
+ return s1->value;
+}
+
+void free_string ( struct string *s ) {
+ free ( s->value );
+ s->value = NULL;
+}
+
+/* struct string *s:
+Before: [start]$<exp>[end]
+End: [start]<expanded>[end]
+and *end points to [end]
+*/
+char * dollar_expand ( struct string *s, char *inp, char ** end ) {
+ char *name;
int setting_len;
+ int len;
+
+ len = inp - s->value;
if ( inp[1] == '{' ) {
+ *inp = 0;
name = ( inp + 2 );
/* Locate closer */
*end = strstr ( name, "}" );
if ( ! *end ) {
printf ( "can't find ending }\n" );
+ free_string ( s );
return NULL;
}
**end = 0;
setting_len = 0; /* Treat error as empty setting */
/* Read setting into buffer */
- expdollar = malloc ( setting_len + 1 );
- if ( expdollar ) {
+ {
+ char expdollar[setting_len + 1];
expdollar[0] = '\0';
fetchf_named_setting ( name, expdollar,
setting_len + 1 );
+ if ( string3cat ( s, expdollar, *end ) )
+ *end = s->value + len + strlen ( expdollar );
}
- return expdollar;
-
+ return s->value;
} else if ( inp[1] == '(' ) {
- name = ( inp + 1 );
+ name = inp;
{
int ret;
- ret = parse_arith ( name, end, &expdollar );
-
- if( ret < 0 ) {
- return NULL;
- }
-
- return expdollar;
+ ret = parse_arith ( s, name, end );
+ return s->value; /* if ret < 0, s->value = NULL */
}
}
/* Can't find { or (, so preserve the $ */
*end = inp + 1;
- asprintf ( &expdollar, "%c", '$' );
- return expdollar;
+ return s->value;
}
-/* The returned string is allocated on the heap and the calling function must free it */
-char * parse_escape ( char *input, char **end ) {
+char * parse_escape ( struct string *s, char *input, char **end ) {
char *exp;
+ *input = 0;
*end = input + 2;
if ( input[1] == '\n' ) {
- exp = malloc ( 1 );
- if ( exp )
- *exp = 0;
+ int len = input - s->value;
+ exp = stringcat ( s, *end );
+ *end = exp + len;
} else {
- asprintf ( &exp, "%c", input[1] );
+ int len = input - s->value;
+ *end = input + 1;
+ exp = stringcat ( s, *end );
+ *end = exp + len + 1;
}
return exp;
}
-/* The returned string is allocated on the heap and the calling function must free it */
-char * expand_string ( const char * input, char **end, const struct char_table *table, int tlen, int in_quotes, int *success ) {
- char *expstr;
- char *head;
- char *tmp;
+/* Both *head and *end point somewhere within s */
+char * expand_string ( struct string *s, char **head, char **end, const struct char_table *table, int tlen, int in_quotes, int *success ) {
int i;
- int new_len;
+ char *cur_pos;
+ int start;
*success = 0;
- expstr = strdup ( input );
-
- head = expstr;
+ start = *head - s->value;
+ cur_pos = *head;
- while ( *head ) {
+ while ( *cur_pos ) {
const struct char_table * tline = NULL;
for ( i = 0; i < tlen; i++ ) {
- if ( table[i].token == *head ) {
+ if ( table[i].token == *cur_pos ) {
tline = table + i;
break;
}
if ( ! tline ) {
*success = 1;
- head++;
+ cur_pos++;
} else {
switch ( tline->type ) {
case ENDQUOTES: /* 0 for end of input, where next char is to be discarded. Used for ending ' or " */
+ {
+ int pos = cur_pos - s->value;
+ char *t;
*success = 1;
- *head = 0;
- *end = head + 1;
- return expstr;
+ *cur_pos = 0;
+ if ( ( t = stringcat ( s, cur_pos + 1 ) ) ) {
+ *end = t + pos;
+ *head = s->value + start;
+ }
+ return s->value;
+ }
break;
case TABLE: /* 1 for recursive call. Probably found quotes */
- case FUNC: /* Call another function */
{
- char *nstr;
int s2;
+ char *end;
+ char *tmp;
*success = 1;
- *head = 0;
- nstr = ( tline->type == TABLE ) ? ( expand_string ( head + 1, &head, tline->next.next_table.ntable, tline->next.next_table.len, 1, &s2 ) )
- : ( tline->next.parse_func ( head, &head ) );
- tmp = expstr;
- new_len = asprintf ( &expstr, "%s%s%s", expstr, nstr, head );
- head = expstr + strlen ( tmp ) + strlen ( nstr );
+ *cur_pos = 0;
+ tmp = s->value;
+ stringcat ( s, cur_pos + 1 );
+ cur_pos = s->value + ( cur_pos - tmp );
+ if ( !expand_string ( s, &cur_pos, &end, tline->next.next_table.ntable, tline->next.next_table.len, 1, &s2 ) ) {
+ return NULL;
+ }
+ cur_pos = end;
+ }
+ break;
+ case FUNC: /* Call another function */
+ {
+ char *nstr;
- free ( tmp );
- free ( nstr );
- if ( !nstr || new_len < 0 ) { /* if new_len < 0, expstr = NULL */
- free ( expstr );
+ *success = 1;
+ nstr = tline->next.parse_func ( s, cur_pos, &cur_pos );
+ if ( !nstr ) {
return NULL;
}
}
break;
+
case ENDTOK: /* End of input, and we also want next character */
- *end = head;
- return expstr;
+ *end = cur_pos;
+ *head = s->value + start;
+ return s->value;
break;
}
}
}
if ( in_quotes ) {
printf ( "can't find closing '%c'\n", table[0].token );
- free ( expstr );
+ free_string ( s );
return NULL;
}
- *end = head;
- return expstr;
+ *end = cur_pos;
+ *head = s->value + start;
+ return s->value;
}
#ifndef _GPXE_PARSE_H_
#define _GPXE_PARSE_H_
+#include <stdint.h>
+
#define ENDQUOTES 0
#define TABLE 1
#define FUNC 2
#define ENDTOK 3
+struct string {
+ char *value;
+};
+
struct char_table {
char token;
int type;
struct char_table *ntable;
int len;
} next_table;
- char * ( *parse_func ) ( char *, char ** );
+ char * ( *parse_func ) ( struct string *, char *, char ** );
}next;
};
-int parse_arith ( const char *inp_string, char **end, char **buffer );
+int parse_arith ( struct string *inp, char *inp_str, char **end );
-char * expand_string ( const char * input, char **end, const struct char_table *table, int tlen, int in_quotes, int *success );
-char * dollar_expand ( char *inp, char **end );
-char * parse_escape ( char *input, char **end );
+char * expand_string ( struct string *s, char **head, char **end, const struct char_table *table, int tlen, int in_quotes, int *success );
+char * dollar_expand ( struct string *s, char *inp, char ** end );
+char * parse_escape ( struct string *s, char *input, char **end );
int isnum ( char *string, long *num );
+void free_string ( struct string *s );
+char * string3cat ( struct string *s1, const char *s2, const char *s3 );
+char * stringcpy ( struct string *s1, const char *s2 );
+char * stringcat ( struct string *s1, const char *s2 );
+
extern struct char_table dquote_table[3];
extern struct char_table squote_table[1];