MMove the normalisation into a procedure.
[findutils.git] / lib / buildcmd.c
blobe9ca95e7c6d4f06d2ccbd584b0d5e724ee54e8c8
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 #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.
99 PFXLEN is the length of PREFIX. Substitution is not performed on
100 the prefix. The prefix is used if the argument contains replace_pat.
102 COMPAT: insertions on the SYSV version are limited to 255 chars per line,
103 and a max of 5 occurrences of replace_pat in the initial-arguments.
104 Those restrictions do not exist here. */
106 void
107 bc_do_insert (const struct buildcmd_control *ctl,
108 struct buildcmd_state *state,
109 char *arg, size_t arglen,
110 const char *prefix, size_t pfxlen,
111 const char *linebuf, size_t lblen,
112 int initial_args)
114 /* Temporary copy of each arg with the replace pattern replaced by the
115 real arg. */
116 static char *insertbuf;
117 char *p;
118 int bytes_left = ctl->arg_max - 1; /* Bytes left on the command line. */
119 int need_prefix;
121 if (!insertbuf)
122 insertbuf = (char *) xmalloc (ctl->arg_max + 1);
123 p = insertbuf;
125 need_prefix = 0;
128 size_t len; /* Length in ARG before `replace_pat'. */
129 char *s = mbstrstr (arg, ctl->replace_pat);
130 if (s)
132 need_prefix = 1;
133 len = s - arg;
135 else
137 len = arglen;
140 bytes_left -= len;
141 if (bytes_left <= 0)
142 break;
144 strncpy (p, arg, len);
145 p += len;
146 arg += len;
147 arglen -= len;
149 if (s)
151 bytes_left -= lblen;
152 if (bytes_left <= 0)
153 break;
154 strcpy (p, linebuf);
155 arg += ctl->rplen;
156 arglen -= ctl->rplen;
157 p += lblen;
160 while (*arg);
161 if (*arg)
162 error (1, 0, _("command too long"));
163 *p++ = '\0';
165 if (!need_prefix)
167 prefix = NULL;
168 pfxlen = 0;
171 bc_push_arg (ctl, state,
172 insertbuf, p - insertbuf,
173 prefix, pfxlen,
174 initial_args);
177 static
178 void do_exec(const struct buildcmd_control *ctl,
179 struct buildcmd_state *state)
181 (ctl->exec_callback)(ctl, state);
185 /* Add ARG to the end of the list of arguments `cmd_argv' to pass
186 to the command.
187 LEN is the length of ARG, including the terminating null.
188 If this brings the list up to its maximum size, execute the command. */
190 void
191 bc_push_arg (const struct buildcmd_control *ctl,
192 struct buildcmd_state *state,
193 const char *arg, size_t len,
194 const char *prefix, size_t pfxlen,
195 int initial_args)
197 if (!initial_args)
198 state->todo = 1;
200 if (arg)
202 if (state->cmd_argv_chars + len > ctl->arg_max)
204 if (initial_args || state->cmd_argc == ctl->initial_argc)
205 error (1, 0, _("can not fit single argument within argument list size limit"));
206 /* option -i (replace_pat) implies -x (exit_if_size_exceeded) */
207 if (ctl->replace_pat
208 || (ctl->exit_if_size_exceeded &&
209 (ctl->lines_per_exec || ctl->args_per_exec)))
210 error (1, 0, _("argument list too long"));
211 do_exec (ctl, state);
213 if (!initial_args && ctl->args_per_exec &&
214 state->cmd_argc - ctl->initial_argc == ctl->args_per_exec)
215 do_exec (ctl, state);
218 if (state->cmd_argc >= state->cmd_argv_alloc)
220 if (!state->cmd_argv)
222 state->cmd_argv_alloc = 64;
223 state->cmd_argv = (char **) xmalloc (sizeof (char *) * state->cmd_argv_alloc);
225 else
227 state->cmd_argv_alloc *= 2;
228 state->cmd_argv = (char **) xrealloc (state->cmd_argv,
229 sizeof (char *) * state->cmd_argv_alloc);
233 if (!arg)
234 state->cmd_argv[state->cmd_argc++] = NULL;
235 else
237 state->cmd_argv[state->cmd_argc++] = state->argbuf + state->cmd_argv_chars;
238 if (prefix)
240 strcpy (state->argbuf + state->cmd_argv_chars, prefix);
241 state->cmd_argv_chars += pfxlen;
244 strcpy (state->argbuf + state->cmd_argv_chars, arg);
245 state->cmd_argv_chars += len;
247 /* If we have now collected enough arguments,
248 * do the exec immediately. This must be
249 * conditional on arg!=NULL, since do_exec()
250 * actually calls bc_push_arg(ctl, state, NULL, 0, false).
252 if (!initial_args
253 && ctl->args_per_exec
254 && (state->cmd_argc - ctl->initial_argc) == ctl->args_per_exec)
255 do_exec (ctl, state);
258 /* If this is an initial argument, set the high-water mark. */
259 if (initial_args)
261 state->cmd_initial_argv_chars = state->cmd_argv_chars;
266 /* Finds the first occurrence of the substring NEEDLE in the string
267 HAYSTACK. Both strings can be multibyte strings. */
269 static char *
270 mbstrstr (const char *haystack, const char *needle)
272 #if DO_MULTIBYTE
273 if (MB_CUR_MAX > 1)
275 size_t hlen = strlen (haystack);
276 size_t nlen = strlen (needle);
277 mbstate_t mbstate;
278 size_t step;
280 memset (&mbstate, 0, sizeof (mbstate_t));
281 while (hlen >= nlen)
283 if (memcmp (haystack, needle, nlen) == 0)
284 return (char *) haystack;
285 step = mbrlen (haystack, hlen, &mbstate);
286 if (step <= 0)
287 break;
288 haystack += step;
289 hlen -= step;
291 return NULL;
293 #endif
294 return strstr (haystack, needle);
298 long
299 bc_get_arg_max(void)
301 long val;
302 #ifdef _SC_ARG_MAX
303 val = sysconf(_SC_ARG_MAX);
304 #else
305 val = -1;
306 #endif
308 if (val > 0)
309 return val;
311 /* either _SC_ARG_MAX was not available or
312 * there is no particular limit.
314 #ifdef ARG_MAX
315 val = ARG_MAX;
316 #endif
318 if (val > 0)
319 return val;
321 /* The value returned by this function bounds the
322 * value applied as the ceiling for the -s option.
323 * Hence it the system won't tell us what its limit
324 * is, we allow the user to specify more or less
325 * whatever value they like.
327 return LONG_MAX;
331 static int cb_exec_noop(const struct buildcmd_control *ctl,
332 struct buildcmd_state *state)
334 /* does nothing. */
335 (void) ctl;
336 (void) state;
338 return 0;
341 void
342 bc_init_controlinfo(struct buildcmd_control *ctl)
344 ctl->exit_if_size_exceeded = 0;
345 ctl->arg_max = bc_get_arg_max() - 2048; /* a la xargs */
346 ctl->rplen = 0u;
347 ctl->replace_pat = NULL;
348 ctl->initial_argc = 0;
349 ctl->exec_callback = cb_exec_noop;
350 ctl->lines_per_exec = 0;
351 ctl->args_per_exec = 0;
354 void
355 bc_init_state(const struct buildcmd_control *ctl,
356 struct buildcmd_state *state,
357 void *context)
359 state->cmd_argc = 0;
360 state->cmd_argv_chars = 0;
361 state->cmd_argv = NULL;
362 state->cmd_argv_alloc = 0;
363 state->argbuf = (char *) xmalloc (ctl->arg_max + 1);
364 state->cmd_argv_chars = state->cmd_initial_argv_chars = 0;
365 state->todo = 0;
366 state->usercontext = context;
369 void
370 bc_clear_args(const struct buildcmd_control *ctl,
371 struct buildcmd_state *state)
373 state->cmd_argc = ctl->initial_argc;
374 state->cmd_argv_chars = state->cmd_initial_argv_chars;
375 state->todo = 0;