Applied all the trunk changes (up to this point) to the 4.3.x sources
[findutils.git] / lib / buildcmd.c
blobe0919f19d33d3841bc2db203e9808c0bb1eacb7e
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 /* COMPAT: SYSV version defaults size (and has a max value of) to 470.
78 We try to make it as large as possible. */
79 #if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
80 #define ARG_MAX sysconf (_SC_ARG_MAX)
81 #endif
82 #ifndef ARG_MAX
83 #define ARG_MAX NCARGS
84 #endif
88 #include <xalloc.h>
89 #include <error.h>
91 #include "buildcmd.h"
93 static char *mbstrstr PARAMS ((const char *haystack, const char *needle));
95 /* Replace all instances of `replace_pat' in ARG with `linebuf',
96 and add the resulting string to the list of arguments for the command
97 to execute.
98 ARGLEN is the length of ARG, not including the null.
99 LBLEN is the length of LINEBUF, not including the null.
100 PFXLEN is the length of PREFIX. Substitution is not performed on
101 the prefix. The prefix is used if the argument contains replace_pat.
103 COMPAT: insertions on the SYSV version are limited to 255 chars per line,
104 and a max of 5 occurrences of replace_pat in the initial-arguments.
105 Those restrictions do not exist here. */
107 void
108 bc_do_insert (const struct buildcmd_control *ctl,
109 struct buildcmd_state *state,
110 char *arg, size_t arglen,
111 const char *prefix, size_t pfxlen,
112 const char *linebuf, size_t lblen,
113 int initial_args)
115 /* Temporary copy of each arg with the replace pattern replaced by the
116 real arg. */
117 static char *insertbuf;
118 char *p;
119 int bytes_left = ctl->arg_max - 1; /* Bytes left on the command line. */
120 int need_prefix;
122 if (!insertbuf)
123 insertbuf = (char *) xmalloc (ctl->arg_max + 1);
124 p = insertbuf;
126 need_prefix = 0;
129 size_t len; /* Length in ARG before `replace_pat'. */
130 char *s = mbstrstr (arg, ctl->replace_pat);
131 if (s)
133 need_prefix = 1;
134 len = s - arg;
136 else
138 len = arglen;
141 bytes_left -= len;
142 if (bytes_left <= 0)
143 break;
145 strncpy (p, arg, len);
146 p += len;
147 arg += len;
148 arglen -= len;
150 if (s)
152 bytes_left -= lblen;
153 if (bytes_left <= 0)
154 break;
155 strcpy (p, linebuf);
156 arg += ctl->rplen;
157 arglen -= ctl->rplen;
158 p += lblen;
161 while (*arg);
162 if (*arg)
163 error (1, 0, _("command too long"));
164 *p++ = '\0';
166 if (!need_prefix)
168 prefix = NULL;
169 pfxlen = 0;
172 bc_push_arg (ctl, state,
173 insertbuf, p - insertbuf,
174 prefix, pfxlen,
175 initial_args);
178 static
179 void do_exec(const struct buildcmd_control *ctl,
180 struct buildcmd_state *state)
182 (ctl->exec_callback)(ctl, state);
186 /* Add ARG to the end of the list of arguments `cmd_argv' to pass
187 to the command.
188 LEN is the length of ARG, including the terminating null.
189 If this brings the list up to its maximum size, execute the command. */
191 void
192 bc_push_arg (const struct buildcmd_control *ctl,
193 struct buildcmd_state *state,
194 const char *arg, size_t len,
195 const char *prefix, size_t pfxlen,
196 int initial_args)
198 if (!initial_args)
199 state->todo = 1;
201 if (arg)
203 if (state->cmd_argv_chars + len > ctl->arg_max)
205 if (initial_args || state->cmd_argc == ctl->initial_argc)
206 error (1, 0, _("can not fit single argument within argument list size limit"));
207 /* option -i (replace_pat) implies -x (exit_if_size_exceeded) */
208 if (ctl->replace_pat
209 || (ctl->exit_if_size_exceeded &&
210 (ctl->lines_per_exec || ctl->args_per_exec)))
211 error (1, 0, _("argument list too long"));
212 do_exec (ctl, state);
214 if (!initial_args && ctl->args_per_exec &&
215 state->cmd_argc - ctl->initial_argc == ctl->args_per_exec)
216 do_exec (ctl, state);
219 if (state->cmd_argc >= state->cmd_argv_alloc)
221 if (!state->cmd_argv)
223 state->cmd_argv_alloc = 64;
224 state->cmd_argv = (char **) xmalloc (sizeof (char *) * state->cmd_argv_alloc);
226 else
228 state->cmd_argv_alloc *= 2;
229 state->cmd_argv = (char **) xrealloc (state->cmd_argv,
230 sizeof (char *) * state->cmd_argv_alloc);
234 if (!arg)
235 state->cmd_argv[state->cmd_argc++] = NULL;
236 else
238 state->cmd_argv[state->cmd_argc++] = state->argbuf + state->cmd_argv_chars;
239 if (prefix)
241 strcpy (state->argbuf + state->cmd_argv_chars, prefix);
242 state->cmd_argv_chars += pfxlen;
245 strcpy (state->argbuf + state->cmd_argv_chars, arg);
246 state->cmd_argv_chars += len;
248 /* If we have now collected enough arguments,
249 * do the exec immediately. This must be
250 * conditional on arg!=NULL, since do_exec()
251 * actually calls bc_push_arg(ctl, state, NULL, 0, false).
253 if ((!initial_args
254 && ctl->args_per_exec
255 && (state->cmd_argc - ctl->initial_argc) == ctl->args_per_exec)
256 || state->cmd_argc == ARG_MAX / sizeof (void *) - 1)
257 do_exec (ctl, state);
260 /* If this is an initial argument, set the high-water mark. */
261 if (initial_args)
263 state->cmd_initial_argv_chars = state->cmd_argv_chars;
268 /* Finds the first occurrence of the substring NEEDLE in the string
269 HAYSTACK. Both strings can be multibyte strings. */
271 static char *
272 mbstrstr (const char *haystack, const char *needle)
274 #if DO_MULTIBYTE
275 if (MB_CUR_MAX > 1)
277 size_t hlen = strlen (haystack);
278 size_t nlen = strlen (needle);
279 mbstate_t mbstate;
280 size_t step;
282 memset (&mbstate, 0, sizeof (mbstate_t));
283 while (hlen >= nlen)
285 if (memcmp (haystack, needle, nlen) == 0)
286 return (char *) haystack;
287 step = mbrlen (haystack, hlen, &mbstate);
288 if (step <= 0)
289 break;
290 haystack += step;
291 hlen -= step;
293 return NULL;
295 #endif
296 return strstr (haystack, needle);
300 long
301 bc_get_arg_max(void)
303 long val;
304 #ifdef _SC_ARG_MAX
305 val = sysconf(_SC_ARG_MAX);
306 #else
307 val = -1;
308 #endif
310 if (val > 0)
311 return val;
313 /* either _SC_ARG_MAX was not available or
314 * there is no particular limit.
316 #ifdef ARG_MAX
317 val = ARG_MAX;
318 #endif
320 if (val > 0)
321 return val;
323 /* The value returned by this function bounds the
324 * value applied as the ceiling for the -s option.
325 * Hence it the system won't tell us what its limit
326 * is, we allow the user to specify more or less
327 * whatever value they like.
329 return LONG_MAX;
333 static int cb_exec_noop(const struct buildcmd_control *ctl,
334 struct buildcmd_state *state)
336 /* does nothing. */
337 (void) ctl;
338 (void) state;
340 return 0;
343 void
344 bc_init_controlinfo(struct buildcmd_control *ctl)
346 ctl->exit_if_size_exceeded = 0;
347 ctl->arg_max = bc_get_arg_max() - 2048; /* a la xargs */
348 ctl->rplen = 0u;
349 ctl->replace_pat = NULL;
350 ctl->initial_argc = 0;
351 ctl->exec_callback = cb_exec_noop;
352 ctl->lines_per_exec = 0;
353 ctl->args_per_exec = 0;
356 void
357 bc_init_state(const struct buildcmd_control *ctl,
358 struct buildcmd_state *state,
359 void *context)
361 state->cmd_argc = 0;
362 state->cmd_argv_chars = 0;
363 state->cmd_argv = NULL;
364 state->cmd_argv_alloc = 0;
365 state->argbuf = (char *) xmalloc (ctl->arg_max + 1);
366 state->cmd_argv_chars = state->cmd_initial_argv_chars = 0;
367 state->todo = 0;
368 state->usercontext = context;
371 void
372 bc_clear_args(const struct buildcmd_control *ctl,
373 struct buildcmd_state *state)
375 state->cmd_argc = ctl->initial_argc;
376 state->cmd_argv_chars = state->cmd_initial_argv_chars;
377 state->todo = 0;