First working version of -exec ...+
[findutils.git] / lib / buildcmd.c
blobc71bcb089a240e919729adc3238532a36c13e60a
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
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 #ifdef HAVE_UNISTD_H
72 /* for sysconf() */
73 #include <unistd.h>
74 #endif
76 /* COMPAT: SYSV version defaults size (and has a max value of) to 470.
77 We try to make it as large as possible. */
78 #if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
79 #define ARG_MAX sysconf (_SC_ARG_MAX)
80 #endif
81 #ifndef ARG_MAX
82 #define ARG_MAX NCARGS
83 #endif
87 #include <xalloc.h>
88 #include <error.h>
90 #include "buildcmd.h"
92 static char *mbstrstr PARAMS ((const char *haystack, const char *needle));
94 /* Replace all instances of `replace_pat' in ARG with `linebuf',
95 and add the resulting string to the list of arguments for the command
96 to execute.
97 ARGLEN is the length of ARG, not including the null.
98 LBLEN is the length of LINEBUF, not including the null.
100 COMPAT: insertions on the SYSV version are limited to 255 chars per line,
101 and a max of 5 occurrences of replace_pat in the initial-arguments.
102 Those restrictions do not exist here. */
104 void
105 bc_do_insert (const struct buildcmd_control *ctl,
106 struct buildcmd_state *state,
107 char *arg,
108 size_t arglen,
109 const char *linebuf,
110 size_t lblen,
111 int initial_args)
113 /* Temporary copy of each arg with the replace pattern replaced by the
114 real arg. */
115 static char *insertbuf;
116 char *p;
117 int bytes_left = ctl->arg_max - 1; /* Bytes left on the command line. */
119 if (!insertbuf)
120 insertbuf = (char *) xmalloc (ctl->arg_max + 1);
121 p = insertbuf;
125 size_t len; /* Length in ARG before `replace_pat'. */
126 char *s = mbstrstr (arg, ctl->replace_pat);
127 if (s)
128 len = s - arg;
129 else
130 len = arglen;
131 bytes_left -= len;
132 if (bytes_left <= 0)
133 break;
135 strncpy (p, arg, len);
136 p += len;
137 arg += len;
138 arglen -= len;
140 if (s)
142 bytes_left -= lblen;
143 if (bytes_left <= 0)
144 break;
145 strcpy (p, linebuf);
146 arg += ctl->rplen;
147 arglen -= ctl->rplen;
148 p += lblen;
151 while (*arg);
152 if (*arg)
153 error (1, 0, _("command too long"));
154 *p++ = '\0';
155 bc_push_arg (ctl, state, insertbuf, p - insertbuf, initial_args);
158 static
159 void do_exec(const struct buildcmd_control *ctl,
160 struct buildcmd_state *state)
162 (ctl->exec_callback)(ctl, state);
166 /* Add ARG to the end of the list of arguments `cmd_argv' to pass
167 to the command.
168 LEN is the length of ARG, including the terminating null.
169 If this brings the list up to its maximum size, execute the command. */
171 void
172 bc_push_arg (const struct buildcmd_control *ctl,
173 struct buildcmd_state *state,
174 char *arg,
175 size_t len,
176 int initial_args)
178 state->todo = 1;
179 if (arg)
181 if (state->cmd_argv_chars + len > ctl->arg_max)
183 if (initial_args || state->cmd_argc == ctl->initial_argc)
184 error (1, 0, _("can not fit single argument within argument list size limit"));
185 /* option -i (replace_pat) implies -x (exit_if_size_exceeded) */
186 if (ctl->replace_pat
187 || (ctl->exit_if_size_exceeded &&
188 (ctl->lines_per_exec || ctl->args_per_exec)))
189 error (1, 0, _("argument list too long"));
190 do_exec (ctl, state);
192 if (!initial_args && ctl->args_per_exec &&
193 state->cmd_argc - ctl->initial_argc == ctl->args_per_exec)
194 do_exec (ctl, state);
197 if (state->cmd_argc >= state->cmd_argv_alloc)
199 if (!state->cmd_argv)
201 state->cmd_argv_alloc = 64;
202 state->cmd_argv = (char **) xmalloc (sizeof (char *) * state->cmd_argv_alloc);
204 else
206 state->cmd_argv_alloc *= 2;
207 state->cmd_argv = (char **) xrealloc (state->cmd_argv,
208 sizeof (char *) * state->cmd_argv_alloc);
212 if (!arg)
213 state->cmd_argv[state->cmd_argc++] = NULL;
214 else
216 state->cmd_argv[state->cmd_argc++] = state->argbuf + state->cmd_argv_chars;
217 strcpy (state->argbuf + state->cmd_argv_chars, arg);
218 state->cmd_argv_chars += len;
220 /* If we have now collected enough arguments,
221 * do the exec immediately. This must be
222 * conditional on arg!=NULL, since do_exec()
223 * actually calls bc_push_arg(ctl, state, NULL, 0, false).
225 if (!initial_args
226 && ctl->args_per_exec
227 && (state->cmd_argc - ctl->initial_argc) == ctl->args_per_exec)
228 do_exec (ctl, state);
231 /* If this is an initial argument, set the high-water mark. */
232 if (initial_args)
234 state->cmd_initial_argv_chars = state->cmd_argv_chars;
239 /* Finds the first occurrence of the substring NEEDLE in the string
240 HAYSTACK. Both strings can be multibyte strings. */
242 static char *
243 mbstrstr (const char *haystack, const char *needle)
245 #if DO_MULTIBYTE
246 if (MB_CUR_MAX > 1)
248 size_t hlen = strlen (haystack);
249 size_t nlen = strlen (needle);
250 mbstate_t mbstate;
251 size_t step;
253 memset (&mbstate, 0, sizeof (mbstate_t));
254 while (hlen >= nlen)
256 if (memcmp (haystack, needle, nlen) == 0)
257 return (char *) haystack;
258 step = mbrlen (haystack, hlen, &mbstate);
259 if (step <= 0)
260 break;
261 haystack += step;
262 hlen -= step;
264 return NULL;
266 #endif
267 return strstr (haystack, needle);
271 long
272 bc_get_arg_max(void)
274 long val;
275 #ifdef _SC_ARG_MAX
276 val = sysconf(_SC_ARG_MAX);
277 #else
278 val = -1;
279 #endif
281 if (val > 0)
282 return val;
284 /* either _SC_ARG_MAX was not available or
285 * there is no particular limit.
287 #ifdef ARG_MAX
288 val = ARG_MAX;
289 #endif
291 if (val > 0)
292 return val;
294 /* The value returned by this function bounds the
295 * value applied as the ceiling for the -s option.
296 * Hence it the system won't tell us what its limit
297 * is, we allow the user to specify more or less
298 * whatever value they like.
300 return LONG_MAX;
304 static int cb_exec_noop(const struct buildcmd_control *ctl,
305 struct buildcmd_state *state)
307 /* does nothing. */
308 (void) ctl;
309 (void) state;
311 return 0;
314 void
315 bc_init_controlinfo(struct buildcmd_control *ctl)
317 ctl->exit_if_size_exceeded = 0;
318 ctl->arg_max = bc_get_arg_max() - 2048; /* a la xargs */
319 ctl->rplen = 0u;
320 ctl->replace_pat = NULL;
321 ctl->initial_argc = 0;
322 ctl->exec_callback = cb_exec_noop;
323 ctl->lines_per_exec = 0;
324 ctl->args_per_exec = 0;
327 void
328 bc_init_state(const struct buildcmd_control *ctl,
329 struct buildcmd_state *state)
331 state->cmd_argc = 0;
332 state->cmd_argv_chars = 0;
333 state->cmd_argv = NULL;
334 state->cmd_argv_alloc = 0;
335 state->argbuf = (char *) xmalloc (ctl->arg_max + 1);
336 state->cmd_argv_chars = 0;
337 state->todo = 0;
338 state->usercontext = NULL;
341 void
342 bc_clear_args(const struct buildcmd_control *ctl,
343 struct buildcmd_state *state)
345 state->cmd_argc = ctl->initial_argc;
346 state->cmd_argv_chars = state->cmd_initial_argv_chars;
347 state->todo = 0;