[scripting] Using a string struct to help with memory issues
authorLynus Vaz <lynus@Arch.localdomain>
Thu, 25 Jun 2009 18:56:39 +0000 (00:26 +0530)
committerLynus Vaz <lynus@Arch.localdomain>
Thu, 25 Jun 2009 18:56:39 +0000 (00:26 +0530)
src/core/exec.c
src/hci/arith.c
src/hci/parse.c
src/include/gpxe/parse.h

index 0b109ff..ed85b30 100644 (file)
@@ -27,9 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #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>
 
@@ -112,66 +110,51 @@ static struct char_table table[6] = {
        { .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;
 }
 
@@ -189,22 +172,22 @@ int system ( const char *command ) {
        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;
 }
 
index cc4d17b..7187483 100644 (file)
 #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 {
@@ -91,36 +85,30 @@ struct char_table table[21] = {
 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;
@@ -128,18 +116,19 @@ static void input ( void ) {
                        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 '<=' */
@@ -150,7 +139,7 @@ static void input ( void ) {
                tok = MIN_TOK + ( p1 - op_table ) / 3;
                return;
        }
-       inp++;
+       inp_ptr++;
        tok = MIN_TOK + ( p2 - op_table ) / 3;
 
 }
@@ -177,8 +166,8 @@ int isnum ( char *string, long *num ) {
 }
 
 static void ignore_whitespace ( void ) {
-       while ( isspace ( *inp ) ) {
-               inp++;
+       while ( isspace ( *inp_ptr ) ) {
+               inp_ptr++;
        }
 }
 
@@ -391,26 +380,35 @@ static int parse_expr ( char **buffer ) {
        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 ) {
@@ -430,6 +428,7 @@ int parse_arith ( const char *inp_string, char **end, char **buffer ) {
                                printf("out of memory\n");
                                break;
                }
+               free_string ( inp );
                return err_val;
        }
        
index ad10d1f..e6ead10 100644 (file)
@@ -5,19 +5,58 @@
 #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;
@@ -29,65 +68,60 @@ char * dollar_expand ( char *inp, char ** end ) {
                        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;
                        }
@@ -95,40 +129,55 @@ char * expand_string ( const char * input, char **end, const struct char_table *
                
                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;
                        }
                }
@@ -136,9 +185,10 @@ char * expand_string ( const char * input, char **end, const struct char_table *
        }
        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;
 }
index 2d6a99a..388294d 100644 (file)
@@ -1,11 +1,17 @@
 #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;
@@ -14,17 +20,22 @@ struct char_table {
                        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];