BRL-CAD
argv.c
Go to the documentation of this file.
1 /* A R G V . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2008-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 
21 #include "common.h"
22 
23 #include <string.h>
24 #include <ctype.h>
25 
26 #include "bu/log.h"
27 #include "bu/malloc.h"
28 #include "bu/str.h"
29 #include "bu/file.h"
30 
31 size_t
32 bu_argv_from_string(char *argv[], size_t lim, char *lp)
33 {
34  size_t argc = 0; /* number of words seen */
35  size_t skip = 0;
36  int quoted = 0;
37  int escaped = 0;
38 
39  if (UNLIKELY(!argv)) {
40  /* do this instead of crashing */
41  bu_bomb("bu_argv_from_string received a null argv\n");
42  }
43 
44  /* argv is expected to be at least lim+1 */
45  argv[0] = (char *)NULL;
46 
47  if (UNLIKELY(lim == 0 || !lp)) {
48  /* nothing to do, only return NULL in argv[0] */
49  return 0;
50  }
51 
52  /* skip leading whitespace */
53  while (*lp != '\0' && isspace((int)(*lp)))
54  lp++;
55 
56  if (*lp == '\0') {
57  /* no words, only return NULL in argv[0] */
58  return 0;
59  }
60 
61  /* some non-space string has been seen, set argv[0] */
62  argc = 0;
63  argv[argc] = lp;
64 
65  for (; *lp != '\0'; lp++) {
66 
67  if (*lp == '\\') {
68  char *cp = lp;
69 
70  /* Shift everything to the left (i.e. stomp on the escape character) */
71  while (*cp != '\0') {
72  *cp = *(cp+1);
73  cp++;
74  }
75 
76  /* mark the next character as escaped */
77  escaped = 1;
78 
79  /* remember the loops lp++ */
80  lp--;
81 
82  continue;
83  }
84 
85  if (*lp == '"') {
86  if (!quoted) {
87  char *cp = lp;
88 
89  /* start collecting quoted string */
90  quoted = 1;
91 
92  if (!escaped) {
93  /* Shift everything to the left (i.e. stomp on the quote character) */
94  while (*cp != '\0') {
95  *cp = *(cp+1);
96  cp++;
97  }
98 
99  /* remember the loops lp++ */
100  lp--;
101  }
102 
103  continue;
104  }
105 
106  /* end qoute */
107  quoted = 0;
108  if (escaped)
109  lp++;
110  else
111  *lp++ = '\0';
112 
113  /* skip leading whitespace */
114  while (*lp != '\0' && isspace((int)(*lp))) {
115  /* null out spaces */
116  *lp = '\0';
117  lp++;
118  }
119 
120  skip = 0;
121  goto nextword;
122  }
123 
124  escaped = 0;
125 
126  /* skip over current word */
127  if (quoted || !isspace((int)(*lp)))
128  continue;
129 
130  skip = 0;
131 
132  /* terminate current word, skip space until we find the start
133  * of the next word nulling out the spaces as we go along.
134  */
135  while (*(lp+skip) != '\0' && isspace((int)(*(lp+skip)))) {
136  lp[skip] = '\0';
137  skip++;
138  }
139 
140  if (*(lp + skip) == '\0')
141  break;
142 
143  nextword:
144  /* make sure argv[] isn't full, need room for NULL */
145  if (argc >= lim-1)
146  break;
147 
148  /* start of next word */
149  argc++;
150  argv[argc] = lp + skip;
151 
152  /* jump over the spaces, remember the loop's lp++ */
153  lp += skip - 1;
154  }
155 
156  /* always NULL-terminate the array */
157  argc++;
158  argv[argc] = (char *)NULL;
159 
160  return argc;
161 }
162 
163 
164 void
165 bu_free_argv(int argc, char *argv[])
166 {
167  register int i;
168 
169  if (UNLIKELY(!argv || argc <= 0)) {
170  return;
171  }
172 
173  for (i = 0; i < argc; ++i) {
174  if (argv[i]) {
175  bu_free((void *)argv[i], "bu_free_argv");
176  argv[i] = NULL; /* sanity */
177  }
178  }
179 
180  bu_free((void *)argv, "bu_free_argv");
181  argv = NULL;
182 }
183 
184 
185 void
186 bu_free_array(int argc, char *argv[], const char *str)
187 {
188  int count = 0;
189 
190  if (UNLIKELY(!argv || argc <= 0)) {
191  return;
192  }
193 
194  while (count < argc) {
195  if (argv[count]) {
196  bu_free(argv[count], str);
197  argv[count] = NULL;
198  }
199  count++;
200  }
201 
202  return;
203 }
204 
205 
206 char **
207 bu_dup_argv(int argc, const char *argv[])
208 {
209  register int i;
210  char **av;
211 
212  if (UNLIKELY(argc < 1))
213  return (char **)0;
214 
215  av = (char **)bu_calloc((unsigned int)argc+1, sizeof(char *), "bu_copy_argv");
216  for (i = 0; i < argc; ++i)
217  av[i] = bu_strdup(argv[i]);
218  av[i] = (char *)0;
219 
220  return av;
221 }
222 
223 
224 char **
225 bu_dupinsert_argv(int insert, int insertArgc, const char *insertArgv[], int argc, const char *argv[])
226 {
227  register int i, j;
228  int ac = argc + insertArgc + 1;
229  char **av;
230 
231  /* Nothing to insert */
232  if (insertArgc < 1)
233  return bu_dup_argv(argc, argv);
234 
235  av = (char **)bu_calloc((unsigned int)ac, sizeof(char *), "bu_insert_argv");
236 
237  if (insert <= 0) { /* prepend */
238  for (i = 0; i < insertArgc; ++i)
239  av[i] = bu_strdup(insertArgv[i]);
240 
241  for (j = 0; j < argc; ++i, ++j)
242  av[i] = bu_strdup(argv[j]);
243  } else if (argc <= insert) { /* append */
244  for (i = 0; i < argc; ++i)
245  av[i] = bu_strdup(argv[i]);
246 
247  for (j = 0; j < insertArgc; ++i, ++j)
248  av[i] = bu_strdup(insertArgv[j]);
249  } else { /* insert */
250  for (i = 0; i < insert; ++i)
251  av[i] = bu_strdup(argv[i]);
252 
253  for (j = 0; j < insertArgc; ++i, ++j)
254  av[i] = bu_strdup(insertArgv[j]);
255 
256  for (j = insert; j < argc; ++i, ++j)
257  av[i] = bu_strdup(argv[j]);
258  }
259 
260  av[i] = (char *)0;
261 
262  return av;
263 }
264 
265 
266 char **
267 bu_argv_from_path(const char *path, int *ac)
268 {
269  char **av;
270  char *begin;
271  char *end;
272  char *newstr;
273  char *headpath;
274  register int i;
275 
276  if (UNLIKELY(path == (char *)0 || path[0] == '\0'))
277  return (char **)0;
278 
279  newstr = bu_strdup(path);
280 
281  /* skip leading /'s */
282  i = 0;
283  while (newstr[i] == '/')
284  ++i;
285 
286  if (UNLIKELY(newstr[i] == '\0')) {
287  bu_free((void *)newstr, "bu_argv_from_path");
288  return (char **)0;
289  }
290 
291  /* If we get here, there is at least one path element */
292  *ac = 1;
293  headpath = &newstr[i];
294 
295  /* First count the number of '/' */
296  begin = headpath;
297  while ((end = strchr(begin, '/')) != (char *)0) {
298  if (begin != end)
299  ++*ac;
300 
301  begin = end + 1;
302  }
303  av = (char **)bu_calloc((unsigned int)(*ac)+1, sizeof(char *), "bu_argv_from_path");
304 
305  begin = headpath;
306  i = 0;
307  while ((end = strchr(begin, '/')) != (char *)0) {
308  if (begin != end) {
309  *end = '\0';
310  av[i++] = bu_strdup(begin);
311  }
312 
313  begin = end + 1;
314  }
315 
316  if (begin[0] != '\0') {
317  av[i++] = bu_strdup(begin);
318  av[i] = (char *)0;
319  } else {
320  av[i] = (char *)0;
321  --*ac;
322  }
323  bu_free((void *)newstr, "bu_argv_from_path");
324 
325  return av;
326 }
327 
328 
329 /*
330  * Local Variables:
331  * mode: C
332  * tab-width: 8
333  * indent-tabs-mode: t
334  * c-file-style: "stroustrup"
335  * End:
336  * ex: shiftwidth=4 tabstop=8
337  */
void bu_free_argv(int argc, char *argv[])
Definition: argv.c:165
char ** bu_argv_from_path(const char *path, int *ac)
Definition: argv.c:267
Header file for the BRL-CAD common definitions.
void bu_free_array(int argc, char *argv[], const char *str)
Definition: argv.c:186
char * strchr(const char *sp, int c)
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
char ** bu_dup_argv(int argc, const char *argv[])
Definition: argv.c:207
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
off_t end
Definition: ptbl.h:64
size_t bu_argv_from_string(char *argv[], size_t lim, char *lp)
Definition: argv.c:32
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
char ** bu_dupinsert_argv(int insert, int insertArgc, const char *insertArgv[], int argc, const char *argv[])
Definition: argv.c:225
#define bu_strdup(s)
Definition: str.h:71
#define UNLIKELY(expression)
Definition: common.h:282