1/*
2   This file contains a function, build_argv(), which will take an input
3   string and chop it into individual words.  The return value is an
4   argv style array (i.e. like what main() receives).
5
6  THIS CODE COPYRIGHT DOMINIC GIAMPAOLO.  NO WARRANTY IS EXPRESSED
7  OR IMPLIED.  YOU MAY USE THIS CODE AND FREELY DISTRIBUTE IT FOR
8  NON-COMMERCIAL USE AS LONG AS THIS NOTICE REMAINS ATTACHED.
9
10  FOR COMMERCIAL USE, CONTACT DOMINIC GIAMPAOLO (dbg@be.com).
11
12  Dominic Giampaolo
13  dbg@be.com
14*/
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <ctype.h>
19#include <string.h>
20
21#include "argv.h"
22
23#define DOUBLE_QUOTE  '"'
24#define SINGLE_QUOTE  '\''
25#define BACK_SLASH    '\\'
26
27char **
28build_argv(char *str, int *argc)
29{
30    int table_size = 16, _argc;
31    char **argv;
32
33    if (argc == NULL)
34        argc = &_argc;
35
36    *argc = 0;
37    argv  = (char **)calloc(table_size, sizeof(char *));
38
39    if (argv == NULL)
40        return NULL;
41
42    while(*str) {
43        /* skip intervening white space */
44        while(*str != '\0' && (*str == ' ' || *str == '\t' || *str == '\n'))
45            str++;
46
47        if (*str == '\0')
48            break;
49
50        if (*str == DOUBLE_QUOTE) {
51            argv[*argc] = ++str;
52            while(*str && *str != DOUBLE_QUOTE) {
53                if (*str == BACK_SLASH)
54                    strcpy(str, str+1);  /* copy everything down */
55                str++;
56            }
57        } else if (*str == SINGLE_QUOTE) {
58            argv[*argc] = ++str;
59            while(*str && *str != SINGLE_QUOTE) {
60                if (*str == BACK_SLASH)
61                    strcpy(str, str+1);  /* copy everything down */
62                str++;
63            }
64        } else {
65            argv[*argc] = str;
66            while(*str && *str != ' ' && *str != '\t' && *str != '\n') {
67                if (*str == BACK_SLASH)
68                    strcpy(str, str+1);  /* copy everything down */
69                str++;
70            }
71        }
72
73        if (*str != '\0')
74            *str++ = '\0';   /* chop the string */
75
76        *argc = *argc + 1;
77        if (*argc >= table_size-1) {
78            char **nargv;
79
80            table_size = table_size * 2;
81            nargv = (char **)calloc(table_size, sizeof(char *));
82
83            if (nargv == NULL) {   /* drats! failure. */
84                free(argv);
85                return NULL;
86            }
87
88            memcpy(nargv, argv, (*argc) * sizeof(char *));
89            free(argv);
90            argv = nargv;
91        }
92    }
93
94    return argv;
95}
96