[acripting] Use a generic stack for argv. Also fix memory leaks
authorLynus Vaz <lynus@Arch.localdomain>
Wed, 24 Jun 2009 14:16:47 +0000 (19:46 +0530)
committerLynus Vaz <lynus@Arch.localdomain>
Wed, 24 Jun 2009 14:16:47 +0000 (19:46 +0530)
src/core/exec.c
src/hci/gen_stack.c [new file with mode: 0644]
src/include/gpxe/errfile.h
src/include/gpxe/gen_stack.h [new file with mode: 0644]
src/include/gpxe/parse.h
src/tests/quotes.gpxe

index 1402ae5..44fdeb3 100644 (file)
@@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #include <gpxe/command.h>
 #include <gpxe/settings.h>
 #include <gpxe/parse.h>
+#include <gpxe/gen_stack.h>
 
 #include <lib.h>
 
@@ -94,10 +95,7 @@ int execv ( const char *command, char * const argv[] ) {
        return -ENOEXEC;
 }
 
-struct argument {
-       char *word;
-       struct argument *next;
-};
+
 
 char * dollar_expand ( char *inp, char **end ) {
        char *expdollar;
@@ -124,25 +122,24 @@ char * dollar_expand ( char *inp, char **end ) {
 
                /* Read setting into temporary buffer */
                {
-                       char *setting_buf = malloc ( setting_len + 1 );
+                       expdollar = malloc ( setting_len + 1 );
 
-                       setting_buf[0] = '\0';
-                       fetchf_named_setting ( name, setting_buf,
+                       expdollar[0] = '\0';
+                       fetchf_named_setting ( name, expdollar,
                                               setting_len + 1 );
-                       return setting_buf;
+                       return expdollar;
                }
        } else if ( inp[1] == '(' ) {
                name = ( inp + 1 );
                {
                        int ret;
-                       char *arith_res;
-                       ret = parse_arith ( name, end, &arith_res );
+                       ret = parse_arith ( name, end, &expdollar );
                        
                        if( ret < 0 ) {
                                return NULL;
                        }
                        
-                       return arith_res;
+                       return expdollar;
                }
        }
        /* Can't find { or (, so preserve the $ (current behaviour) */
@@ -157,7 +154,8 @@ char * parse_escape ( char *input, char **end ) {
        if ( input[1] == '\n' ) {
                *end = input + 2;
                exp = malloc ( 1 );
-               *exp = 0;
+               if ( exp )
+                       *exp = 0;
        } else {
                *end = input + 2;
                asprintf ( &exp, "%c", input[1] );
@@ -183,10 +181,10 @@ static struct char_table table[6] = {
        { .token = '\t', .type = ENDTOK }
 };
 
-char * expand_string ( char * input, char **end, const struct char_table *table, int tlen, int in_quotes, int *success ) {
+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 *nstr, *tmp;
+       char *tmp;
        int i;
        int new_len;
        
@@ -213,15 +211,17 @@ char * expand_string ( char * input, char **end, const struct char_table *table,
                                        *success = 1;
                                        *head = 0;
                                        *end = head + 1;
-                                       //printf ( "return value: [%s]\n", expstr );
                                        return expstr;
                                        break;
                                case TABLE: /* 1 for recursive call. Probably found quotes */
                                case FUNC: /* Call another function */
                                        {
+                                               char *nstr;
+                                               int s2;
+                                               
                                                *success = 1;
                                                *head = 0;
-                                               nstr = ( tline->type == TABLE ) ? ( expand_string ( head + 1, &head, tline->next.next_table.ntable, tline->next.next_table.len, 1, success ) ) 
+                                               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;
                                                
@@ -262,66 +262,57 @@ char * expand_string ( char * input, char **end, const struct char_table *table,
  * The expanded command line is allocated with malloc() and the caller
  * must eventually free() it.
  */
-int expand_command ( const char *command, struct argument **argv_start ) {
-
+int expand_command ( const char *command, struct generic_stack *argv_stack ) {
        char *expcmd;
        char *head, *end;
        char *nstring;
-       struct argument *cur_arg = NULL;
        int argc = 0;
        int success;
        
+       init_generic_stack ( argv_stack, sizeof ( char * ) );
+       
        /* Obtain temporary modifiable copy of command line */
        expcmd = strdup ( command );    
        if ( ! expcmd )
                return -ENOMEM;
-       *argv_start = NULL;
        head = expcmd;
+       
        /* Expand while expansions remain */
        while ( *head ) {
                while ( isspace ( *head ) )
                        head++;
-               if ( *head == '#' && !*argv_start ) { /* Comment starts with # */
-                       return 0;
+               if ( *head == '#' ) { /* Comment is a new word that starts with # */
+                       break;
                }
                nstring = expand_string ( head, &end, table, 6, 0, &success );
-               if ( !nstring ) {
-                       while ( *argv_start ) {
-                               cur_arg = *argv_start;
-                               *argv_start = ( *argv_start )->next;
-                               free ( cur_arg );
-                       }
-                       free ( expcmd );
-                       return -ENOMEM;
-               }
-               if ( success ) {
-                       argc++;
-                       if ( !*argv_start ) {
-                               *argv_start = calloc ( sizeof ( struct argument ), 1 );
-                               cur_arg = *argv_start;
-                       } else {
-                               cur_arg->next = calloc ( sizeof ( struct argument ), 1 );
-                               cur_arg = cur_arg->next;
-                       }
-               
-                       if ( !cur_arg ) {
-                               while ( *argv_start ) {
-                                       cur_arg = *argv_start;
-                                       *argv_start = ( *argv_start )->next;
-                                       free ( cur_arg );
+               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;
                                }
-                               free ( expcmd );
-                               free ( nstring );
-                               return -ENOMEM;
                        }
-               
-                       cur_arg->word = calloc ( end - nstring + 1, 1);
-                       strncpy ( cur_arg->word, nstring, end - nstring );
                }
                free ( expcmd );
+
+               if ( !nstring ) {
+                       return -ENOMEM;
+               }
                expcmd = nstring;
                head = end;
        }
+       free ( expcmd );
        return argc;
 }
 
@@ -336,35 +327,25 @@ int expand_command ( const char *command, struct argument **argv_start ) {
 int system ( const char *command ) {
        int argc;
        int rc = 0;
-       int i;
-       struct argument *argv_start;
-       struct argument *arg;
+       struct generic_stack argv_stack;
 
-       argc = expand_command ( command, &argv_start );
+       argc = expand_command ( command, &argv_stack );
        
-       if ( argc < 0 )
-               return -ENOMEM;
-
-       arg = argv_start;
-       {
-               char *argv[argc + 1];
-               for ( i = 0; i < argc; i++ ) {
-                       struct argument *tmp;
-                       tmp = arg;
-                       argv[i] = arg->word;
-                       arg = arg->next;
-                       free ( tmp );
-                       
-                       //printf ( "[%s] ", argv[i] );
-               }
-               argv[i] = NULL;
-               //printf ( "\n" );
+       if ( argc < 0 ) {
+               rc = argc;
+       } else {
+               char **argv = realloc ( argv_stack.ptr, ( argc + 1 ) * sizeof ( char * ) );
                
-               if ( argc > 0 )
-                       rc = execv ( argv[0], argv );
-               for ( i = 0; i < argc; i++)
-                       free ( argv[i] );
+               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 );
        return rc;
 }
 
diff --git a/src/hci/gen_stack.c b/src/hci/gen_stack.c
new file mode 100644 (file)
index 0000000..f1f59f5
--- /dev/null
@@ -0,0 +1,52 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <gpxe/gen_stack.h>
+
+
+
+void init_generic_stack ( struct generic_stack *stack, size_t size ) {
+       stack->ptr = NULL;
+       stack->tos = -1;
+       stack->size = size;
+}
+
+
+int pop_generic_stack ( struct generic_stack *stack, void *ptr ) {
+       if ( stack->tos >= 0 ) {
+               memcpy ( ptr, ( void * ) ( ( (int)stack->ptr ) + stack->size * stack->tos-- ), stack->size );
+               return 0;
+       } else
+               return -ENOMEM;
+}
+
+void free_generic_stack ( struct generic_stack *stack, int on_stack ) {
+       void *ptr = NULL;
+       if ( on_stack ) {
+               while ( !pop_generic_stack ( stack, ptr ) ) {
+                       free ( ptr );
+               }
+       }
+       free ( stack->ptr );
+}
+
+int push_generic_stack ( struct generic_stack *stack, void *str, int is_string ) {
+       char **nptr;
+       nptr = realloc ( stack->ptr, stack->size * ( stack->tos + 2 ) );
+       if ( !nptr ) {
+               printf ( "error in resizing stack\n" );
+               return -ENOMEM;
+       }
+       stack->ptr = nptr;
+       stack->tos++;
+       if ( !is_string ) 
+               memcpy ( ( void * ) ( ( ( int ) stack->ptr ) + stack->size * stack->tos ), str, stack->size );
+       else {
+               if ( asprintf ( ( char ** ) ( ( ( int ) stack->ptr ) + stack->size * stack->tos ), "%s", *( char ** ) str ) < 0 ) {
+                       return -ENOMEM;
+               }
+       }
+       return 0;
+}
index 5b80439..7253ef5 100644 (file)
@@ -175,6 +175,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define ERRFILE_x509                 ( ERRFILE_OTHER | 0x00160000 )
 #define ERRFILE_login_ui             ( ERRFILE_OTHER | 0x00170000 )
 #define ERRFILE_arith                  ( ERRFILE_OTHER | 0x00180000 )
+#define ERRFILE_gen_stack              ( ERRFILE_OTHER | 0x00190000 )
 
 /** @} */
 
diff --git a/src/include/gpxe/gen_stack.h b/src/include/gpxe/gen_stack.h
new file mode 100644 (file)
index 0000000..210767c
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _GPXE_GEN_STACK_H
+#define _GPXE_GEN_STACK_H
+
+
+#include <ctype.h>
+#include <errno.h>
+
+#include <lib.h>
+
+struct generic_stack {
+       void *ptr;
+       int tos;
+       size_t size;
+};
+
+void init_generic_stack ( struct generic_stack *stack, size_t size );
+int push_generic_stack ( struct generic_stack *stack, void *str, int is_string );
+int pop_generic_stack ( struct generic_stack *stack, void *ptr );
+void free_generic_stack ( struct generic_stack *stack, int on_stack );
+
+#endif
\ No newline at end of file
index 5af2106..8e8ae51 100644 (file)
@@ -20,7 +20,7 @@ struct char_table {
 
 int parse_arith ( char *inp_string, char **end, char **buffer );
 
-char * expand_string ( char * input, char **end, const struct char_table *table, int tlen, int in_quotes, int *success );
+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 );
 int isnum ( char *string, long *num );
index fde111d..bf8ce34 100644 (file)
@@ -11,4 +11,5 @@ set b 'world"'
 echo $("${a} ${b}" == "\"hello world\"")
 echo "$("${a} ${b}" == \"hello\ world\")"
 echo '${a} = '${a} '${b}'" = ${b}"
-echo $((1+2*3)<<2)
\ No newline at end of file
+echo $((1+2*3)<<2)
+echo $('' == "" )