Eliminated a few compiler warnings
[findutils.git] / lib / buildcmd.c
blob05f54e1f8ce98da2ca16237171f88ba627243034
1 /* buildcmd.c -- build command lines from a list of arguments.
2 Copyright (C) 1990, 91, 92, 93, 94, 2000, 2003, 2005 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
17 USA.
20 #include <config.h>
22 # ifndef PARAMS
23 # if defined PROTOTYPES || (defined __STDC__ && __STDC__)
24 # define PARAMS(Args) Args
25 # else
26 # define PARAMS(Args) ()
27 # endif
28 # endif
30 #if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
31 #include <string.h>
32 #endif
35 #if DO_MULTIBYTE
36 # if HAVE_MBRLEN
37 # include <wchar.h>
38 # else
39 /* Simulate mbrlen with mblen as best we can. */
40 # define mbstate_t int
41 # define mbrlen(s, n, ps) mblen (s, n)
42 # endif
43 #endif
45 #ifdef HAVE_LOCALE_H
46 #include <locale.h>
47 #endif
48 #if ENABLE_NLS
49 # include <libintl.h>
50 # define _(Text) gettext (Text)
51 #else
52 # define _(Text) Text
53 #define textdomain(Domain)
54 #define bindtextdomain(Package, Directory)
55 #endif
56 #ifdef gettext_noop
57 # define N_(String) gettext_noop (String)
58 #else
59 /* See locate.c for explanation as to why not use (String) */
60 # define N_(String) String
61 #endif
63 #ifndef _POSIX_SOURCE
64 #include <sys/param.h>
65 #endif
67 #ifdef HAVE_LIMITS_H
68 #include <limits.h>
69 #endif
71 /* The presence of unistd.h is assumed by gnulib these days, so we
72 * might as well assume it too.
74 /* for sysconf() */
75 #include <unistd.h>
77 #include <assert.h>
79 /* COMPAT: SYSV version defaults size (and has a max value of) to 470.
80 We try to make it as large as possible. */
81 #if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
82 #define ARG_MAX sysconf (_SC_ARG_MAX)
83 #endif
84 #ifndef ARG_MAX
85 #define ARG_MAX NCARGS
86 #endif
90 #include <xalloc.h>
91 #include <error.h>
93 #include "buildcmd.h"
96 extern char **environ;
99 static char *mbstrstr PARAMS ((const char *haystack, const char *needle));
101 /* Replace all instances of `replace_pat' in ARG with `linebuf',
102 and add the resulting string to the list of arguments for the command
103 to execute.
104 ARGLEN is the length of ARG, not including the null.
105 LBLEN is the length of LINEBUF, not including the null.
106 PFXLEN is the length of PREFIX. Substitution is not performed on
107 the prefix. The prefix is used if the argument contains replace_pat.
109 COMPAT: insertions on the SYSV version are limited to 255 chars per line,
110 and a max of 5 occurrences of replace_pat in the initial-arguments.
111 Those restrictions do not exist here. */
113 void
114 bc_do_insert (const struct buildcmd_control *ctl,
115 struct buildcmd_state *state,
116 char *arg, size_t arglen,
117 const char *prefix, size_t pfxlen,
118 const char *linebuf, size_t lblen,
119 int initial_args)
121 /* Temporary copy of each arg with the replace pattern replaced by the
122 real arg. */
123 static char *insertbuf;
124 char *p;
125 size_t bytes_left = ctl->arg_max - 1; /* Bytes left on the command line. */
127 /* XXX: on systems lacking an upper limit for exec args, ctl->arg_max
128 * may have been set to LONG_MAX (see bc_get_arg_max()). Hence
129 * this xmalloc call may be a bad idea, especially since we are
130 * adding 1 to it...
132 if (!insertbuf)
133 insertbuf = (char *) xmalloc (ctl->arg_max + 1);
134 p = insertbuf;
138 size_t len; /* Length in ARG before `replace_pat'. */
139 char *s = mbstrstr (arg, ctl->replace_pat);
140 if (s)
142 len = s - arg;
144 else
146 len = arglen;
149 if (bytes_left <= len)
150 break;
151 else
152 bytes_left -= len;
154 strncpy (p, arg, len);
155 p += len;
156 arg += len;
157 arglen -= len;
159 if (s)
161 if (bytes_left <= (lblen + pfxlen))
162 break;
163 else
164 bytes_left -= (lblen + pfxlen);
166 if (prefix)
168 strcpy (p, prefix);
169 p += pfxlen;
171 strcpy (p, linebuf);
172 p += lblen;
174 arg += ctl->rplen;
175 arglen -= ctl->rplen;
178 while (*arg);
179 if (*arg)
180 error (1, 0, _("command too long"));
181 *p++ = '\0';
183 bc_push_arg (ctl, state,
184 insertbuf, p - insertbuf,
185 NULL, 0,
186 initial_args);
189 static
190 void do_exec(const struct buildcmd_control *ctl,
191 struct buildcmd_state *state)
193 (ctl->exec_callback)(ctl, state);
197 /* Return nonzero if there would not be enough room for an additional
198 * argument. We check the total number of arguments only, not the space
199 * occupied by those arguments.
201 * If we return zero, there still may not be enough room for the next
202 * argument, depending on its length.
204 static int
205 bc_argc_limit_reached(int initial_args,
206 const struct buildcmd_control *ctl,
207 struct buildcmd_state *state)
209 /* Check to see if we about to exceed a limit set by xargs' -n option */
210 if (!initial_args && ctl->args_per_exec &&
211 ( (state->cmd_argc - ctl->initial_argc) == ctl->args_per_exec))
212 return 1;
214 /* We deliberately use an equality test here rather than >= in order
215 * to force a software failure if the code is modified in such a way
216 * that it fails to call this function for every new argument.
218 return state->cmd_argc == ctl->max_arg_count;
222 /* Add ARG to the end of the list of arguments `cmd_argv' to pass
223 to the command.
224 LEN is the length of ARG, including the terminating null.
225 If this brings the list up to its maximum size, execute the command.
228 void
229 bc_push_arg (const struct buildcmd_control *ctl,
230 struct buildcmd_state *state,
231 const char *arg, size_t len,
232 const char *prefix, size_t pfxlen,
233 int initial_args)
235 if (!initial_args)
236 state->todo = 1;
238 if (arg)
240 if (state->cmd_argv_chars + len > ctl->arg_max)
242 if (initial_args || state->cmd_argc == ctl->initial_argc)
243 error (1, 0, _("can not fit single argument within argument list size limit"));
244 /* xargs option -i (replace_pat) implies -x (exit_if_size_exceeded) */
245 if (ctl->replace_pat
246 || (ctl->exit_if_size_exceeded &&
247 (ctl->lines_per_exec || ctl->args_per_exec)))
248 error (1, 0, _("argument list too long"));
249 do_exec (ctl, state);
252 if (bc_argc_limit_reached(initial_args, ctl, state))
253 do_exec (ctl, state);
256 if (state->cmd_argc >= state->cmd_argv_alloc)
258 if (!state->cmd_argv)
260 state->cmd_argv_alloc = 64;
261 state->cmd_argv = (char **) xmalloc (sizeof (char *) * state->cmd_argv_alloc);
263 else
265 state->cmd_argv_alloc *= 2;
266 state->cmd_argv = (char **) xrealloc (state->cmd_argv,
267 sizeof (char *) * state->cmd_argv_alloc);
271 if (!arg)
272 state->cmd_argv[state->cmd_argc++] = NULL;
273 else
275 state->cmd_argv[state->cmd_argc++] = state->argbuf + state->cmd_argv_chars;
276 if (prefix)
278 strcpy (state->argbuf + state->cmd_argv_chars, prefix);
279 state->cmd_argv_chars += pfxlen;
282 strcpy (state->argbuf + state->cmd_argv_chars, arg);
283 state->cmd_argv_chars += len;
285 /* If we have now collected enough arguments,
286 * do the exec immediately. This must be
287 * conditional on arg!=NULL, since do_exec()
288 * actually calls bc_push_arg(ctl, state, NULL, 0, false).
290 if (bc_argc_limit_reached(initial_args, ctl, state))
291 do_exec (ctl, state);
294 /* If this is an initial argument, set the high-water mark. */
295 if (initial_args)
297 state->cmd_initial_argv_chars = state->cmd_argv_chars;
302 /* Finds the first occurrence of the substring NEEDLE in the string
303 HAYSTACK. Both strings can be multibyte strings. */
305 static char *
306 mbstrstr (const char *haystack, const char *needle)
308 #if DO_MULTIBYTE
309 if (MB_CUR_MAX > 1)
311 size_t hlen = strlen (haystack);
312 size_t nlen = strlen (needle);
313 mbstate_t mbstate;
314 size_t step;
316 memset (&mbstate, 0, sizeof (mbstate_t));
317 while (hlen >= nlen)
319 if (memcmp (haystack, needle, nlen) == 0)
320 return (char *) haystack;
321 step = mbrlen (haystack, hlen, &mbstate);
322 if (step <= 0)
323 break;
324 haystack += step;
325 hlen -= step;
327 return NULL;
329 #endif
330 return strstr (haystack, needle);
333 static size_t
334 get_line_max(void)
336 long val;
337 #ifdef _SC_LINE_MAX
338 val = sysconf(_SC_LINE_MAX);
339 #else
340 val = -1;
341 #endif
343 if (val > 0)
344 return val;
346 /* either _SC_LINE_MAX was not available or
347 * there is no particular limit.
349 #ifdef LINE_MAX
350 val = LINE_MAX;
351 #endif
353 if (val > 0)
354 return val;
356 return 2048L; /* a reasonable guess. */
360 size_t
361 bc_get_arg_max(void)
363 long val;
365 /* We may resort to using LONG_MAX, so check it fits. */
366 /* XXX: better to do a compile-time check */
367 assert( (~(size_t)0) >= LONG_MAX);
369 #ifdef _SC_ARG_MAX
370 val = sysconf(_SC_ARG_MAX);
371 #else
372 val = -1;
373 #endif
375 if (val > 0)
376 return val;
378 /* either _SC_ARG_MAX was not available or
379 * there is no particular limit.
381 #ifdef ARG_MAX
382 val = ARG_MAX;
383 #endif
385 if (val > 0)
386 return val;
388 /* The value returned by this function bounds the
389 * value applied as the ceiling for the -s option.
390 * Hence it the system won't tell us what its limit
391 * is, we allow the user to specify more or less
392 * whatever value they like.
394 return LONG_MAX;
398 static int cb_exec_noop(const struct buildcmd_control *ctl,
399 struct buildcmd_state *state)
401 /* does nothing. */
402 (void) ctl;
403 (void) state;
405 return 0;
409 /* Return how much of ARG_MAX is used by the environment. */
410 size_t
411 bc_size_of_environment (void)
413 size_t len = 0u;
414 char **envp = environ;
416 while (*envp)
417 len += strlen (*envp++) + 1;
419 return len;
423 enum BC_INIT_STATUS
424 bc_init_controlinfo(struct buildcmd_control *ctl)
426 size_t size_of_environment = bc_size_of_environment();
427 size_t arg_max;
429 ctl->posix_arg_size_min = get_line_max();
430 arg_max = bc_get_arg_max();
432 /* POSIX.2 requires subtracting 2048. */
433 assert(arg_max > 2048u); /* XXX: this is an external condition, should not check it with assert. */
434 ctl->posix_arg_size_max = (arg_max - 2048);
436 ctl->exit_if_size_exceeded = 0;
438 /* Take the size of the environment into account. */
439 if (size_of_environment > ctl->posix_arg_size_max)
441 return BC_INIT_ENV_TOO_BIG;
443 else
445 #warning the next line is probably a bug.
446 ctl->posix_arg_size_max - size_of_environment;
449 /* need to subtract 2 on the following line - for Linux/PPC */
450 ctl->max_arg_count = (ctl->posix_arg_size_max / sizeof(char*)) - 2u;
451 assert(ctl->max_arg_count > 0);
452 ctl->rplen = 0u;
453 ctl->replace_pat = NULL;
454 ctl->initial_argc = 0;
455 ctl->exec_callback = cb_exec_noop;
456 ctl->lines_per_exec = 0;
457 ctl->args_per_exec = 0;
459 /* Set the initial value of arg_max to the largest value we can
460 * tolerate.
462 ctl->arg_max = ctl->posix_arg_size_max;
464 return BC_INIT_OK;
467 void
468 bc_use_sensible_arg_max(struct buildcmd_control *ctl)
470 size_t env_size = bc_size_of_environment();
471 const size_t arg_size = (128u * 1024u) + env_size;
473 /* Check against the upper and lower limits. */
474 if (arg_size > ctl->posix_arg_size_max)
475 ctl->arg_max = ctl->posix_arg_size_max - env_size;
476 else if (arg_size < ctl->posix_arg_size_min)
477 ctl->arg_max = ctl->posix_arg_size_min;
478 else
479 ctl->arg_max = arg_size;
485 void
486 bc_init_state(const struct buildcmd_control *ctl,
487 struct buildcmd_state *state,
488 void *context)
490 state->cmd_argc = 0;
491 state->cmd_argv_chars = 0;
492 state->cmd_argv = NULL;
493 state->cmd_argv_alloc = 0;
495 /* XXX: the following memory allocation is inadvisable on systems
496 * with no ARG_MAX, because ctl->arg_max may actually be close to
497 * LONG_MAX. Adding one to it is safe though because earlier we
498 * subtracted 2048.
500 assert(ctl->arg_max <= (LONG_MAX - 2048L));
501 state->argbuf = (char *) xmalloc (ctl->arg_max + 1u);
503 state->cmd_argv_chars = state->cmd_initial_argv_chars = 0;
504 state->todo = 0;
505 state->usercontext = context;
508 void
509 bc_clear_args(const struct buildcmd_control *ctl,
510 struct buildcmd_state *state)
512 state->cmd_argc = ctl->initial_argc;
513 state->cmd_argv_chars = state->cmd_initial_argv_chars;
514 state->todo = 0;