console: Format tabs semi-intelligently
[attac-man.git] / console_args.c
blobbc6b146301af186d307a765c979b7cc19659d3b9
1 /**
2 * License - GPL
4 * Command-line splitter function.
5 * Lon Hohberger <lon@metamorphism.com>
6 */
7 #include <stdio.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <malloc.h>
12 typedef enum _command_state {
13 STATE_QUOTE = 0x1,
14 STATE_LITERAL = 0x2,
15 STATE_COPY = 0x4
16 } command_state_t;
19 /**
20 * Break up a command string into argv values. Rudimentary.
21 * Destroys the value of cmdline (inserts 0s in order to keep argv
22 * pointers 0-terminated in typical C-style)
24 int
25 command_split(char *cmdline, int *argc, char **argv, int max)
27 char *cmd_copy = NULL;
28 command_state_t state = 0;
29 int offset = 0, copy_offset = 0, ret = 1;
31 if (max <= 0 || argv == NULL || argc == NULL) {
32 errno = EINVAL;
33 return -1;
36 cmd_copy = strdup(cmdline);
37 if (!cmd_copy)
38 return -1;
40 memset(cmdline, 0, strlen(cmdline)+1);
41 *argc = 0;
43 while (cmd_copy[copy_offset]) {
44 switch(cmd_copy[copy_offset]) {
45 case ' ':
46 case '\t':
47 case '\r':
48 case '\n':
49 if (state & (STATE_LITERAL | STATE_QUOTE))
50 break;
51 if (state & STATE_COPY) {
52 state &= ~STATE_COPY;
53 cmdline[offset++] = 0;
54 continue;
56 if (!state) {
57 copy_offset++;
58 continue;
60 break;
61 case '\\':
62 if (state & STATE_LITERAL)
63 break;
64 state |= STATE_LITERAL;
65 ++copy_offset;
66 continue;
68 case '\"':
69 if (state & STATE_LITERAL)
70 break;
71 if (state & STATE_QUOTE) {
72 state &= ~STATE_QUOTE;
73 } else {
74 state |= STATE_QUOTE;
76 ++copy_offset;
77 continue;
80 if (!(state & STATE_COPY)) {
81 if (*argc >= max)
82 goto out;
83 state |= STATE_COPY;
84 argv[(*argc)++] = &cmdline[offset];
87 state &= ~STATE_LITERAL;
89 cmdline[offset] = cmd_copy[copy_offset];
90 ++offset;
91 ++copy_offset;
93 ret = 0;
95 out:
96 if (cmd_copy)
97 free(cmd_copy);
98 return ret;