]>
diplodocus.org Git - nmh/blob - sbr/arglist.c
0dde2c86d06d52edf067499b60be5ff8e087c9ab
1 /* arglist.c -- Routines for handling argument lists for execvp() and friends
3 * This code is Copyright (c) 2013, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
14 * Split up a command into an appropriate array to pass to execvp()
15 * or similar function. Returns an allocated argv[] array.
19 * command - String to split up
20 * file - the first argument to "command", suitable for the first argument
21 * to execvp(). Returns allocated memory that must be free()d.
22 * argp - Index to last element (NULL) of returned argv[] array.
24 * Our basic algorithm is this:
26 * - If there are no spaces or shell metacharacters in "command", then
28 * - If there are spaces in command, space-split command string.
29 * - If we have shell metacharacters, run the command using
30 * /bin/sh -c 'command "$@"'. In this case, any additional arguments
31 * appended to the arglist will be expanded by "$@".
33 * In all cases additional arguments can be added to the argv[] array.
36 /* Shell metacharacters we use to trigger a call to the shell */
38 #define METACHARS "$&*(){}[]'\";\\|?<>~`\n"
41 argsplit(char *command
, char **file
, int *argp
)
47 bool metachar
= false;
48 for (p
= command
; *p
; p
++) {
49 if (*p
== ' ' || *p
== '\t') {
51 } else if (strchr(METACHARS
, *p
)) {
57 argvarray
= mh_xmalloc(sizeof *argvarray
* (MAXARGS
+ 5));
60 * The simple case - no spaces or shell metacharacters
63 if (!space
&& !metachar
) {
64 argvarray
[0] = mh_xstrdup(r1bindex(command
, '/'));
66 *file
= mh_xstrdup(command
);
73 * Spaces, but no shell metacharacters; space-split into separate
77 if (space
&& !metachar
) {
79 p
= mh_xstrdup(command
);
80 split
= brkstring(p
, " \t", NULL
);
81 if (split
[0] == NULL
) {
82 die("Invalid blank command found");
84 argvarray
[0] = mh_xstrdup(r1bindex(split
[0], '/'));
85 for (i
= 1; split
[i
] != NULL
; i
++) {
87 die("Command exceeded argument limit");
89 argvarray
[i
] = mh_xstrdup(split
[i
]);
92 *file
= mh_xstrdup(split
[0]);
100 * Remaining option - pass to the shell.
104 * - The command passed to "sh -c" is actually:
107 * If there are additional arguments they will be expanded by the
108 * shell, otherwise "$@" expands to nothing.
110 * - Every argument after the -c string gets put into positional
111 * parameters starting at $0, but $@ starts expanding with $1.
112 * So we put in a dummy argument (we just use /bin/sh)
115 *file
= mh_xstrdup("/bin/sh");
116 argvarray
[0] = mh_xstrdup("sh");
117 argvarray
[1] = mh_xstrdup("-c");
118 argvarray
[2] = mh_xstrdup(command
);
119 argvarray
[2] = add(" \"$@\"", argvarray
[2]);
120 argvarray
[3] = mh_xstrdup("/bin/sh");
130 * Free our argument array
134 arglist_free(char *command
, char **argvarray
)
140 if (argvarray
!= NULL
) {
141 for (i
= 0; argvarray
[i
] != NULL
; i
++)
148 * Similar in functionality to argsplit, but is designed to deal with
153 argsplit_msgarg(struct msgs_array
*msgs
, char *command
, char **program
)
158 vec
= argsplit(command
, program
, &argp
);
161 * As usual, there is lousy memory management in nmh. Nothing ever
162 * free's the msgs_array, and a lot of the arguments are allocated
163 * from static memory. I could have app_msgarg() allocate new
164 * memory for each pointer, but for now I decided to stick with
165 * the existing interface; maybe that will be revisited later.
166 * So we'll just copy over our pointers and free the pointer list
167 * (not the actual pointers themselves). Note that we don't
168 * include a trailing NULL, since we are expecting the application
169 * to take care of that.
172 for (i
= 0; i
< argp
; i
++) {
173 app_msgarg(msgs
, vec
[i
]);
180 * Insert a arglist vector into the beginning of an struct msgs array
182 * Uses by some programs (e.g., show) who want to decide which proc
183 * to use after the argument vector has been constructed
191 argsplit_insert(struct msgs_array
*msgs
, char *command
, char **program
)
196 vec
= argsplit(command
, program
, &argp
);
199 * Okay, we want to shuffle all of our arguments down so we have room
200 * for argp number of arguments. This means we need to know about
201 * msgs_array internals. If that changes, we need to change this
205 if (msgs
->size
+ argp
>= msgs
->max
) {
206 msgs
->max
+= max(MAXMSGS
, argp
);
207 msgs
->msgs
= mh_xrealloc(msgs
->msgs
, msgs
->max
* sizeof(*msgs
->msgs
));
210 for (i
= msgs
->size
- 1; i
>= 0; i
--)
211 msgs
->msgs
[i
+ argp
] = msgs
->msgs
[i
];
216 * Now fill in the arguments at the beginning of the vector.
219 for (i
= 0; i
< argp
; i
++)
220 msgs
->msgs
[i
] = vec
[i
];