xref: /illumos-gate/usr/src/cmd/xargs/xargs.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <stdio.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
36*7c478bd9Sstevel@tonic-gate #include <unistd.h>
37*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
38*7c478bd9Sstevel@tonic-gate #include <string.h>
39*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
40*7c478bd9Sstevel@tonic-gate #include <libgen.h>
41*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
42*7c478bd9Sstevel@tonic-gate #include <limits.h>
43*7c478bd9Sstevel@tonic-gate #include <wchar.h>
44*7c478bd9Sstevel@tonic-gate #include <locale.h>
45*7c478bd9Sstevel@tonic-gate #include <langinfo.h>
46*7c478bd9Sstevel@tonic-gate #include <stropts.h>
47*7c478bd9Sstevel@tonic-gate #include <poll.h>
48*7c478bd9Sstevel@tonic-gate #include <errno.h>
49*7c478bd9Sstevel@tonic-gate #include <stdarg.h>
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #define	HEAD	0
52*7c478bd9Sstevel@tonic-gate #define	TAIL	1
53*7c478bd9Sstevel@tonic-gate #define	FALSE 0
54*7c478bd9Sstevel@tonic-gate #define	TRUE 1
55*7c478bd9Sstevel@tonic-gate #define	MAXSBUF 255
56*7c478bd9Sstevel@tonic-gate #define	MAXIBUF 512
57*7c478bd9Sstevel@tonic-gate #define	MAXINSERTS 5
58*7c478bd9Sstevel@tonic-gate #define	BUFSIZE LINE_MAX
59*7c478bd9Sstevel@tonic-gate #define	MAXARGS 255
60*7c478bd9Sstevel@tonic-gate #define	INSPAT_STR	"{}"	/* default replstr string for -[Ii]	*/
61*7c478bd9Sstevel@tonic-gate #define	FORK_RETRY	5
62*7c478bd9Sstevel@tonic-gate 
63*7c478bd9Sstevel@tonic-gate #define	QBUF_STARTLEN 255  /* start size of growable string buffer */
64*7c478bd9Sstevel@tonic-gate #define	QBUF_INC 100	   /* how much to grow a growable string by */
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate static wctype_t	blank;
67*7c478bd9Sstevel@tonic-gate static char	*arglist[MAXARGS+1];
68*7c478bd9Sstevel@tonic-gate static char	argbuf[BUFSIZE+1];
69*7c478bd9Sstevel@tonic-gate static char	*next = argbuf;
70*7c478bd9Sstevel@tonic-gate static char	*lastarg = "";
71*7c478bd9Sstevel@tonic-gate static char	**ARGV = arglist;
72*7c478bd9Sstevel@tonic-gate static char	*LEOF = "_";
73*7c478bd9Sstevel@tonic-gate static char	*INSPAT = INSPAT_STR;
74*7c478bd9Sstevel@tonic-gate static char	ins_buf[MAXIBUF];
75*7c478bd9Sstevel@tonic-gate static char	*p_ibuf;
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate static struct inserts {
78*7c478bd9Sstevel@tonic-gate 	char	**p_ARGV;	/* where to put newarg ptr in arg list */
79*7c478bd9Sstevel@tonic-gate 	char	*p_skel;	/* ptr to arg template */
80*7c478bd9Sstevel@tonic-gate } saveargv[MAXINSERTS];
81*7c478bd9Sstevel@tonic-gate 
82*7c478bd9Sstevel@tonic-gate static off_t	file_offset = 0;
83*7c478bd9Sstevel@tonic-gate static int	PROMPT = -1;
84*7c478bd9Sstevel@tonic-gate static int	BUFLIM = BUFSIZE;
85*7c478bd9Sstevel@tonic-gate static int	N_ARGS = 0;
86*7c478bd9Sstevel@tonic-gate static int	N_args = 0;
87*7c478bd9Sstevel@tonic-gate static int	N_lines = 0;
88*7c478bd9Sstevel@tonic-gate static int	DASHX = FALSE;
89*7c478bd9Sstevel@tonic-gate static int	MORE = TRUE;
90*7c478bd9Sstevel@tonic-gate static int	PER_LINE = FALSE;
91*7c478bd9Sstevel@tonic-gate static int	ERR = FALSE;
92*7c478bd9Sstevel@tonic-gate static int	OK = TRUE;
93*7c478bd9Sstevel@tonic-gate static int	LEGAL = FALSE;
94*7c478bd9Sstevel@tonic-gate static int	TRACE = FALSE;
95*7c478bd9Sstevel@tonic-gate static int	INSERT = FALSE;
96*7c478bd9Sstevel@tonic-gate static int	linesize = 0;
97*7c478bd9Sstevel@tonic-gate static int	ibufsize = 0;
98*7c478bd9Sstevel@tonic-gate static char	*yesstr;	/* the string contains int'l for "yes"	*/
99*7c478bd9Sstevel@tonic-gate static int	exitstat = 0;	/* our exit status			*/
100*7c478bd9Sstevel@tonic-gate static int	mac;		/* modified argc, after parsing		*/
101*7c478bd9Sstevel@tonic-gate static char	**mav;		/* modified argv, after parsing		*/
102*7c478bd9Sstevel@tonic-gate static int	n_inserts;	/* # of insertions.			*/
103*7c478bd9Sstevel@tonic-gate static int	inquote = 0;	/* processing a quoted string		*/
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate /*
106*7c478bd9Sstevel@tonic-gate  * the pio structure is used to save any pending input before the
107*7c478bd9Sstevel@tonic-gate  * user replies to a prompt. the pending input is saved here,
108*7c478bd9Sstevel@tonic-gate  * for the appropriate processing later.
109*7c478bd9Sstevel@tonic-gate  */
110*7c478bd9Sstevel@tonic-gate typedef struct pio {
111*7c478bd9Sstevel@tonic-gate 	struct pio *next;	/* next in stack			*/
112*7c478bd9Sstevel@tonic-gate 	char *start;		/* starting addr of the buffer		*/
113*7c478bd9Sstevel@tonic-gate 	char *cur;		/* ptr to current char in buf		*/
114*7c478bd9Sstevel@tonic-gate 	size_t length;		/* number of bytes remaining		*/
115*7c478bd9Sstevel@tonic-gate } pio;
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate static pio *queued_data = NULL;
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate /* our usage message:							*/
120*7c478bd9Sstevel@tonic-gate #define	USAGEMSG "Usage: xargs: [-t] [-p] [-e[eofstr]] [-E eofstr] "\
121*7c478bd9Sstevel@tonic-gate 	"[-I replstr] [-i[replstr]] [-L #] [-l[#]] [-n # [-x]] [-s size] "\
122*7c478bd9Sstevel@tonic-gate 	"[cmd [args ...]]\n"
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate static int	echoargs();
125*7c478bd9Sstevel@tonic-gate static int	getchr(void);
126*7c478bd9Sstevel@tonic-gate static wchar_t	getwchr(void);
127*7c478bd9Sstevel@tonic-gate static void	ungetwchr(wchar_t);
128*7c478bd9Sstevel@tonic-gate static int	lcall(char *sub, char **subargs);
129*7c478bd9Sstevel@tonic-gate static int	xindex(char *as1, char *as2);
130*7c478bd9Sstevel@tonic-gate static void	addibuf(struct inserts *p);
131*7c478bd9Sstevel@tonic-gate static void	ermsg(char *messages, ...);
132*7c478bd9Sstevel@tonic-gate static char	*addarg(char *arg);
133*7c478bd9Sstevel@tonic-gate static char	*checklen(char *arg);
134*7c478bd9Sstevel@tonic-gate static size_t   store_wchr(char **, size_t *, size_t, wchar_t);
135*7c478bd9Sstevel@tonic-gate static char	*getarg();
136*7c478bd9Sstevel@tonic-gate static char	*insert(char *pattern, char *subst);
137*7c478bd9Sstevel@tonic-gate static void	usage();
138*7c478bd9Sstevel@tonic-gate static void	parseargs();
139*7c478bd9Sstevel@tonic-gate static void	saveinput();
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate void
143*7c478bd9Sstevel@tonic-gate main(int argc, char **argv)
144*7c478bd9Sstevel@tonic-gate {
145*7c478bd9Sstevel@tonic-gate 	int	j;
146*7c478bd9Sstevel@tonic-gate 	struct inserts *psave;
147*7c478bd9Sstevel@tonic-gate 	int c;
148*7c478bd9Sstevel@tonic-gate 	int	initsize;
149*7c478bd9Sstevel@tonic-gate 	char	*cmdname, *initbuf, **initlist;
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate 	/* initialization */
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 	blank = wctype("blank");
155*7c478bd9Sstevel@tonic-gate 	n_inserts = 0;
156*7c478bd9Sstevel@tonic-gate 	psave = saveargv;
157*7c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
158*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D 		*/
159*7c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't 		*/
160*7c478bd9Sstevel@tonic-gate #endif
161*7c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 	/*
164*7c478bd9Sstevel@tonic-gate 	 * now we get the appropriate "yes" string for our locale.
165*7c478bd9Sstevel@tonic-gate 	 * since this may be a multibyte character, we store the
166*7c478bd9Sstevel@tonic-gate 	 * string which is returned. later on, when we're looking for
167*7c478bd9Sstevel@tonic-gate 	 * a "y" in response to our prompt, we'll use the first
168*7c478bd9Sstevel@tonic-gate 	 * multibyte character of yesstr as a comparision.
169*7c478bd9Sstevel@tonic-gate 	 */
170*7c478bd9Sstevel@tonic-gate 	initbuf = nl_langinfo(YESSTR);	/* initbuf is a tmp placeholder here */
171*7c478bd9Sstevel@tonic-gate 	if ((yesstr = malloc(strlen(initbuf) + 1)) == NULL) {
172*7c478bd9Sstevel@tonic-gate 		perror(gettext("xargs: Memory allocation failure"));
173*7c478bd9Sstevel@tonic-gate 		exit(1);
174*7c478bd9Sstevel@tonic-gate 	}
175*7c478bd9Sstevel@tonic-gate 	(void) strcpy(yesstr, initbuf);
176*7c478bd9Sstevel@tonic-gate 
177*7c478bd9Sstevel@tonic-gate 	parseargs(argc, argv);
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 	/* handling all of xargs arguments:				*/
180*7c478bd9Sstevel@tonic-gate 	while ((c = getopt(mac, mav, "tpe:E:I:i:L:l:n:s:x")) != EOF) {
181*7c478bd9Sstevel@tonic-gate 		switch (c) {
182*7c478bd9Sstevel@tonic-gate 		case 't':	/* -t: turn trace mode on		*/
183*7c478bd9Sstevel@tonic-gate 			TRACE = TRUE;
184*7c478bd9Sstevel@tonic-gate 			break;
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 		case 'p':	/* -p: turn on prompt mode.		*/
187*7c478bd9Sstevel@tonic-gate 			if ((PROMPT = open("/dev/tty", O_RDONLY)) == -1) {
188*7c478bd9Sstevel@tonic-gate 				perror(gettext("can't read from tty for -p"));
189*7c478bd9Sstevel@tonic-gate 			} else {
190*7c478bd9Sstevel@tonic-gate 				TRACE = TRUE;
191*7c478bd9Sstevel@tonic-gate 			}
192*7c478bd9Sstevel@tonic-gate 			break;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 		case 'e':
195*7c478bd9Sstevel@tonic-gate 			/*
196*7c478bd9Sstevel@tonic-gate 			 * -e[eofstr]: set/disable end-of-file.
197*7c478bd9Sstevel@tonic-gate 			 * N.B. that an argument *isn't* required here; but
198*7c478bd9Sstevel@tonic-gate 			 * parseargs forced an argument if not was given.  The
199*7c478bd9Sstevel@tonic-gate 			 * forced argument is the default...
200*7c478bd9Sstevel@tonic-gate 			 */
201*7c478bd9Sstevel@tonic-gate 			LEOF = optarg; /* can be empty */
202*7c478bd9Sstevel@tonic-gate 			break;
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 		case 'E':
205*7c478bd9Sstevel@tonic-gate 			/*
206*7c478bd9Sstevel@tonic-gate 			 * -E eofstr: change end-of-file string.
207*7c478bd9Sstevel@tonic-gate 			 * eofstr *is* required here:
208*7c478bd9Sstevel@tonic-gate 			 */
209*7c478bd9Sstevel@tonic-gate 			LEOF = optarg;
210*7c478bd9Sstevel@tonic-gate #ifdef XPG6
211*7c478bd9Sstevel@tonic-gate 			if (LEOF == NULL) {
212*7c478bd9Sstevel@tonic-gate #else
213*7c478bd9Sstevel@tonic-gate 			if ((LEOF == NULL) || (*LEOF == NULL)) {
214*7c478bd9Sstevel@tonic-gate #endif
215*7c478bd9Sstevel@tonic-gate 				ermsg(gettext("Must specify subargment to -E "
216*7c478bd9Sstevel@tonic-gate 					" flag\n"));
217*7c478bd9Sstevel@tonic-gate 			}
218*7c478bd9Sstevel@tonic-gate 			break;
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 		case 'I':
221*7c478bd9Sstevel@tonic-gate 			/* -I replstr: Insert mode. replstr *is* required. */
222*7c478bd9Sstevel@tonic-gate 			INSERT = PER_LINE = LEGAL = TRUE;
223*7c478bd9Sstevel@tonic-gate 			N_ARGS = 0;
224*7c478bd9Sstevel@tonic-gate 			if (*optarg) {
225*7c478bd9Sstevel@tonic-gate 				INSPAT = optarg;
226*7c478bd9Sstevel@tonic-gate 			} else {
227*7c478bd9Sstevel@tonic-gate 				ermsg(gettext("Must specify subargment "
228*7c478bd9Sstevel@tonic-gate 				    "for -I\n"));
229*7c478bd9Sstevel@tonic-gate 			}
230*7c478bd9Sstevel@tonic-gate 			break;
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 		case 'i':
233*7c478bd9Sstevel@tonic-gate 			/*
234*7c478bd9Sstevel@tonic-gate 			 * -i [replstr]: insert mode, with *optional* replstr.
235*7c478bd9Sstevel@tonic-gate 			 * N.B. that an argument *isn't* required here; if
236*7c478bd9Sstevel@tonic-gate 			 * it's not given, then the string INSPAT_STR will
237*7c478bd9Sstevel@tonic-gate 			 * be assumed.
238*7c478bd9Sstevel@tonic-gate 			 *
239*7c478bd9Sstevel@tonic-gate 			 * Since getopts(3C) doesn't handle the case of an
240*7c478bd9Sstevel@tonic-gate 			 * optional variable argument at all, we have to
241*7c478bd9Sstevel@tonic-gate 			 * parse this by hand:
242*7c478bd9Sstevel@tonic-gate 			 */
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 			INSERT = PER_LINE = LEGAL = TRUE;
245*7c478bd9Sstevel@tonic-gate 			N_ARGS = 0;
246*7c478bd9Sstevel@tonic-gate 			if (optarg[0] != NULL) {
247*7c478bd9Sstevel@tonic-gate 				INSPAT = optarg;
248*7c478bd9Sstevel@tonic-gate 			} else {
249*7c478bd9Sstevel@tonic-gate 				/*
250*7c478bd9Sstevel@tonic-gate 				 * here, there is no next argument. so
251*7c478bd9Sstevel@tonic-gate 				 * we reset INSPAT to the INSPAT_STR.
252*7c478bd9Sstevel@tonic-gate 				 * we *have* to do this, as -i/I may have
253*7c478bd9Sstevel@tonic-gate 				 * been given previously, and XCU4 requires
254*7c478bd9Sstevel@tonic-gate 				 * that only "the last one specified takes
255*7c478bd9Sstevel@tonic-gate 				 * effect".
256*7c478bd9Sstevel@tonic-gate 				 */
257*7c478bd9Sstevel@tonic-gate 				INSPAT = INSPAT_STR;
258*7c478bd9Sstevel@tonic-gate 			}
259*7c478bd9Sstevel@tonic-gate 			break;
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 		case 'L':
262*7c478bd9Sstevel@tonic-gate 			/*
263*7c478bd9Sstevel@tonic-gate 			 * -L number: # of times cmd is executed
264*7c478bd9Sstevel@tonic-gate 			 * number *is* required here:
265*7c478bd9Sstevel@tonic-gate 			 */
266*7c478bd9Sstevel@tonic-gate 			PER_LINE = TRUE;
267*7c478bd9Sstevel@tonic-gate 			N_ARGS = 0;
268*7c478bd9Sstevel@tonic-gate 			INSERT = FALSE;
269*7c478bd9Sstevel@tonic-gate 			if (optarg && (PER_LINE = atoi(optarg)) <= 0) {
270*7c478bd9Sstevel@tonic-gate 				ermsg(gettext("#lines must be positive "
271*7c478bd9Sstevel@tonic-gate 				    "int: %s\n"), optarg);
272*7c478bd9Sstevel@tonic-gate 			}
273*7c478bd9Sstevel@tonic-gate 			break;
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 		case 'l':
276*7c478bd9Sstevel@tonic-gate 			/*
277*7c478bd9Sstevel@tonic-gate 			 * -l [number]: # of times cmd is executed
278*7c478bd9Sstevel@tonic-gate 			 * N.B. that an argument *isn't* required here; if
279*7c478bd9Sstevel@tonic-gate 			 * it's not given, then 1 is assumed.
280*7c478bd9Sstevel@tonic-gate 			 *
281*7c478bd9Sstevel@tonic-gate 			 * parseargs handles the optional arg processing.
282*7c478bd9Sstevel@tonic-gate 			 */
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 			PER_LINE = LEGAL = TRUE;  /* initialization	*/
285*7c478bd9Sstevel@tonic-gate 			N_ARGS = 0;
286*7c478bd9Sstevel@tonic-gate 			INSERT = FALSE;
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 			if (optarg[0] != NULL) {
289*7c478bd9Sstevel@tonic-gate 				if ((PER_LINE = atoi(optarg)) <= 0)
290*7c478bd9Sstevel@tonic-gate 					PER_LINE = 1;
291*7c478bd9Sstevel@tonic-gate 			}
292*7c478bd9Sstevel@tonic-gate 			break;
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 		case 'n':	/* -n number: # stdin args		*/
295*7c478bd9Sstevel@tonic-gate 			/*
296*7c478bd9Sstevel@tonic-gate 			 * -n number: # stdin args.
297*7c478bd9Sstevel@tonic-gate 			 * number *is* required here:
298*7c478bd9Sstevel@tonic-gate 			 */
299*7c478bd9Sstevel@tonic-gate 			if ((N_ARGS = atoi(optarg)) <= 0) {
300*7c478bd9Sstevel@tonic-gate 				ermsg(gettext("#args must be positive "
301*7c478bd9Sstevel@tonic-gate 				    "int: %s\n"), optarg);
302*7c478bd9Sstevel@tonic-gate 			} else {
303*7c478bd9Sstevel@tonic-gate 				LEGAL = DASHX || N_ARGS == 1;
304*7c478bd9Sstevel@tonic-gate 				INSERT = PER_LINE = FALSE;
305*7c478bd9Sstevel@tonic-gate 			}
306*7c478bd9Sstevel@tonic-gate 			break;
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 		case 's':	/* -s size: set max size of each arg list */
309*7c478bd9Sstevel@tonic-gate 			BUFLIM = atoi(optarg);
310*7c478bd9Sstevel@tonic-gate 			if (BUFLIM > BUFSIZE || BUFLIM <= 0) {
311*7c478bd9Sstevel@tonic-gate 				ermsg(gettext("0 < max-cmd-line-size <= %d: "
312*7c478bd9Sstevel@tonic-gate 				    "%s\n"), BUFSIZE, optarg);
313*7c478bd9Sstevel@tonic-gate 			}
314*7c478bd9Sstevel@tonic-gate 			break;
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 		case 'x':	/* -x: terminate if args > size limit	*/
317*7c478bd9Sstevel@tonic-gate 			DASHX = LEGAL = TRUE;
318*7c478bd9Sstevel@tonic-gate 			break;
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 		default:
321*7c478bd9Sstevel@tonic-gate 			/*
322*7c478bd9Sstevel@tonic-gate 			 * bad argument. complain and get ready to die.
323*7c478bd9Sstevel@tonic-gate 			 */
324*7c478bd9Sstevel@tonic-gate 			ERR = TRUE;
325*7c478bd9Sstevel@tonic-gate 			usage();
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 			exit(2);
328*7c478bd9Sstevel@tonic-gate 			break;
329*7c478bd9Sstevel@tonic-gate 		}
330*7c478bd9Sstevel@tonic-gate 	}
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 	/*
333*7c478bd9Sstevel@tonic-gate 	 * if anything called ermsg(), something screwed up, so
334*7c478bd9Sstevel@tonic-gate 	 * we exit early.
335*7c478bd9Sstevel@tonic-gate 	 */
336*7c478bd9Sstevel@tonic-gate 	if (OK == FALSE) {
337*7c478bd9Sstevel@tonic-gate 		ERR = TRUE;
338*7c478bd9Sstevel@tonic-gate 		usage();
339*7c478bd9Sstevel@tonic-gate 		exit(2);
340*7c478bd9Sstevel@tonic-gate 	}
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	/*
343*7c478bd9Sstevel@tonic-gate 	 * we're finished handling xargs's options, so now pick up
344*7c478bd9Sstevel@tonic-gate 	 * the command name (if any), and it's options.
345*7c478bd9Sstevel@tonic-gate 	 */
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 	mac -= optind;	/* dec arg count by what we've processed 	*/
349*7c478bd9Sstevel@tonic-gate 	mav += optind;	/* inc to current mav				*/
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	if (mac <= 0) {	/* if there're no more args to process,	*/
352*7c478bd9Sstevel@tonic-gate 		cmdname = "/usr/bin/echo";	/* our default command	*/
353*7c478bd9Sstevel@tonic-gate 		*ARGV++ = addarg(cmdname);	/* use the default cmd.	*/
354*7c478bd9Sstevel@tonic-gate 	} else {	/* otherwise keep parsing rest of the string.	*/
355*7c478bd9Sstevel@tonic-gate 		/*
356*7c478bd9Sstevel@tonic-gate 		 * note that we can't use getopts(3C), and *must* parse
357*7c478bd9Sstevel@tonic-gate 		 * this by hand, as we don't know apriori what options the
358*7c478bd9Sstevel@tonic-gate 		 * command will take.
359*7c478bd9Sstevel@tonic-gate 		 */
360*7c478bd9Sstevel@tonic-gate 		cmdname = *mav;	/* get the command name	*/
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 		/* pick up the remaining args from the command line:	*/
364*7c478bd9Sstevel@tonic-gate 		while ((OK == TRUE) && (mac-- > 0)) {
365*7c478bd9Sstevel@tonic-gate 			/*
366*7c478bd9Sstevel@tonic-gate 			 * while we haven't crapped out, and there's
367*7c478bd9Sstevel@tonic-gate 			 * work to do:
368*7c478bd9Sstevel@tonic-gate 			 */
369*7c478bd9Sstevel@tonic-gate 			if (INSERT && ! ERR) {
370*7c478bd9Sstevel@tonic-gate 				if (xindex(*mav, INSPAT) != -1) {
371*7c478bd9Sstevel@tonic-gate 					if (++n_inserts > MAXINSERTS) {
372*7c478bd9Sstevel@tonic-gate 						ermsg(gettext("too many args "
373*7c478bd9Sstevel@tonic-gate 						    "with %s\n"), INSPAT);
374*7c478bd9Sstevel@tonic-gate 						ERR = TRUE;
375*7c478bd9Sstevel@tonic-gate 					}
376*7c478bd9Sstevel@tonic-gate 					psave->p_ARGV = ARGV;
377*7c478bd9Sstevel@tonic-gate 					(psave++)->p_skel = *mav;
378*7c478bd9Sstevel@tonic-gate 				}
379*7c478bd9Sstevel@tonic-gate 			}
380*7c478bd9Sstevel@tonic-gate 			*ARGV++ = addarg(*mav++);
381*7c478bd9Sstevel@tonic-gate 		}
382*7c478bd9Sstevel@tonic-gate 	}
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	/* pick up args from standard input */
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	initbuf = next;
387*7c478bd9Sstevel@tonic-gate 	initlist = ARGV;
388*7c478bd9Sstevel@tonic-gate 	initsize = linesize;
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 	while (OK && MORE) {
391*7c478bd9Sstevel@tonic-gate 		N_args = 0;
392*7c478bd9Sstevel@tonic-gate 		N_lines = 0;
393*7c478bd9Sstevel@tonic-gate 		next = initbuf;
394*7c478bd9Sstevel@tonic-gate 		ARGV = initlist;
395*7c478bd9Sstevel@tonic-gate 		linesize = initsize;
396*7c478bd9Sstevel@tonic-gate 		if (*lastarg) {
397*7c478bd9Sstevel@tonic-gate 			*ARGV++ = addarg(lastarg);
398*7c478bd9Sstevel@tonic-gate 			lastarg = "";
399*7c478bd9Sstevel@tonic-gate 		}
400*7c478bd9Sstevel@tonic-gate 
401*7c478bd9Sstevel@tonic-gate 		while (((ARGV - arglist) < MAXARGS) &&
402*7c478bd9Sstevel@tonic-gate 		    ((*ARGV++ = getarg()) != NULL) && OK)
403*7c478bd9Sstevel@tonic-gate 			;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 		/* insert arg if requested */
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 		if (!ERR && INSERT) {
408*7c478bd9Sstevel@tonic-gate 			if ((!MORE) && (N_lines == 0)) {
409*7c478bd9Sstevel@tonic-gate 				exit(exitstat);
410*7c478bd9Sstevel@tonic-gate 			}
411*7c478bd9Sstevel@tonic-gate 					/* no more input lines */
412*7c478bd9Sstevel@tonic-gate 			p_ibuf = ins_buf;
413*7c478bd9Sstevel@tonic-gate 			ARGV--;
414*7c478bd9Sstevel@tonic-gate 			j = ibufsize = 0;
415*7c478bd9Sstevel@tonic-gate 			for (psave = saveargv; ++j <= n_inserts; ++psave) {
416*7c478bd9Sstevel@tonic-gate 				addibuf(psave);
417*7c478bd9Sstevel@tonic-gate 				if (ERR)
418*7c478bd9Sstevel@tonic-gate 					break;
419*7c478bd9Sstevel@tonic-gate 			}
420*7c478bd9Sstevel@tonic-gate 		}
421*7c478bd9Sstevel@tonic-gate 		*ARGV = 0;
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 		if (n_inserts > 0) {
424*7c478bd9Sstevel@tonic-gate 			int t_ninserts;
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 			/*
427*7c478bd9Sstevel@tonic-gate 			 * if we've done any insertions, re-calculate the
428*7c478bd9Sstevel@tonic-gate 			 * linesize. bomb out if we've exceeded our length.
429*7c478bd9Sstevel@tonic-gate 			 */
430*7c478bd9Sstevel@tonic-gate 			t_ninserts = n_inserts;
431*7c478bd9Sstevel@tonic-gate 			n_inserts = 0;	/* inserts have been done 	*/
432*7c478bd9Sstevel@tonic-gate 			linesize = 0;	/* recalculate this		*/
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 			/* for each current argument in the list:	*/
435*7c478bd9Sstevel@tonic-gate 			for (ARGV = arglist; *ARGV != NULL; ARGV++) {
436*7c478bd9Sstevel@tonic-gate 				/* recalculate everything.		*/
437*7c478bd9Sstevel@tonic-gate 				if (checklen(*ARGV) != 0) {
438*7c478bd9Sstevel@tonic-gate 					if (N_ARGS && (N_args >= N_ARGS)) {
439*7c478bd9Sstevel@tonic-gate 						N_lines = N_args = 0;
440*7c478bd9Sstevel@tonic-gate 						OK = FALSE;
441*7c478bd9Sstevel@tonic-gate 						ERR = TRUE;
442*7c478bd9Sstevel@tonic-gate 					}
443*7c478bd9Sstevel@tonic-gate 				}
444*7c478bd9Sstevel@tonic-gate 			}
445*7c478bd9Sstevel@tonic-gate 			n_inserts = t_ninserts;
446*7c478bd9Sstevel@tonic-gate 		}
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 		/* exec command */
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 		if (!ERR) {
451*7c478bd9Sstevel@tonic-gate 			if (!MORE &&
452*7c478bd9Sstevel@tonic-gate 			    (PER_LINE && N_lines == 0 || N_ARGS && N_args == 0))
453*7c478bd9Sstevel@tonic-gate 				exit(exitstat);
454*7c478bd9Sstevel@tonic-gate 			OK = TRUE;
455*7c478bd9Sstevel@tonic-gate 			j = TRACE ? echoargs() : TRUE;
456*7c478bd9Sstevel@tonic-gate 			if (j) {
457*7c478bd9Sstevel@tonic-gate 				/*
458*7c478bd9Sstevel@tonic-gate 				 * for xcu4, all invocations of cmdname must
459*7c478bd9Sstevel@tonic-gate 				 * return 0, in order for us to return 0.
460*7c478bd9Sstevel@tonic-gate 				 * so if we have a non-zero status here,
461*7c478bd9Sstevel@tonic-gate 				 * quit immediately.
462*7c478bd9Sstevel@tonic-gate 				 */
463*7c478bd9Sstevel@tonic-gate 				if ((exitstat |= lcall(cmdname, arglist)) == 0)
464*7c478bd9Sstevel@tonic-gate 					continue;
465*7c478bd9Sstevel@tonic-gate 			}
466*7c478bd9Sstevel@tonic-gate 		}
467*7c478bd9Sstevel@tonic-gate 	}
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	(void) lseek(0, file_offset, SEEK_SET);
470*7c478bd9Sstevel@tonic-gate 	if (OK) {
471*7c478bd9Sstevel@tonic-gate 		exit(exitstat);
472*7c478bd9Sstevel@tonic-gate 	} else {
473*7c478bd9Sstevel@tonic-gate 		/*
474*7c478bd9Sstevel@tonic-gate 		 * if exitstat was set, to match XCU4 complience,
475*7c478bd9Sstevel@tonic-gate 		 * return that value, otherwise, return 1.
476*7c478bd9Sstevel@tonic-gate 		 */
477*7c478bd9Sstevel@tonic-gate 		exit(exitstat ? exitstat : 1);
478*7c478bd9Sstevel@tonic-gate 	}
479*7c478bd9Sstevel@tonic-gate }
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate static void
482*7c478bd9Sstevel@tonic-gate queue(char *buffer, int len, int where)
483*7c478bd9Sstevel@tonic-gate {
484*7c478bd9Sstevel@tonic-gate 	pio *new, *element;
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 	if ((new = malloc(sizeof (pio))) == NULL) {
487*7c478bd9Sstevel@tonic-gate 		perror(gettext("xargs: Memory allocation failure"));
488*7c478bd9Sstevel@tonic-gate 		exit(1);
489*7c478bd9Sstevel@tonic-gate 	}
490*7c478bd9Sstevel@tonic-gate 	new->cur = new->start = buffer;
491*7c478bd9Sstevel@tonic-gate 	new->length = len;
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	if (where == TAIL) {
494*7c478bd9Sstevel@tonic-gate 		new->next = NULL;
495*7c478bd9Sstevel@tonic-gate 		if (queued_data == NULL) {
496*7c478bd9Sstevel@tonic-gate 			queued_data = new;
497*7c478bd9Sstevel@tonic-gate 		} else {
498*7c478bd9Sstevel@tonic-gate 			element = queued_data;
499*7c478bd9Sstevel@tonic-gate 			while (element->next != NULL) {
500*7c478bd9Sstevel@tonic-gate 				element = element->next;
501*7c478bd9Sstevel@tonic-gate 			}
502*7c478bd9Sstevel@tonic-gate 			element->next = new;
503*7c478bd9Sstevel@tonic-gate 		}
504*7c478bd9Sstevel@tonic-gate 	} else {
505*7c478bd9Sstevel@tonic-gate 		file_offset -= len;
506*7c478bd9Sstevel@tonic-gate 		new->next = queued_data;
507*7c478bd9Sstevel@tonic-gate 		queued_data = new;
508*7c478bd9Sstevel@tonic-gate 	}
509*7c478bd9Sstevel@tonic-gate }
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate static char *
512*7c478bd9Sstevel@tonic-gate checklen(char *arg)
513*7c478bd9Sstevel@tonic-gate {
514*7c478bd9Sstevel@tonic-gate 	int	oklen;
515*7c478bd9Sstevel@tonic-gate 
516*7c478bd9Sstevel@tonic-gate 	oklen = TRUE;
517*7c478bd9Sstevel@tonic-gate 	linesize += strlen(arg) + 1;
518*7c478bd9Sstevel@tonic-gate 	if (linesize >= BUFLIM) {
519*7c478bd9Sstevel@tonic-gate 		/*
520*7c478bd9Sstevel@tonic-gate 		 * we skip this if there're inserts. we'll handle the
521*7c478bd9Sstevel@tonic-gate 		 * argument counting after all the insertions have
522*7c478bd9Sstevel@tonic-gate 		 * been done.
523*7c478bd9Sstevel@tonic-gate 		 */
524*7c478bd9Sstevel@tonic-gate 		if (n_inserts == 0) {
525*7c478bd9Sstevel@tonic-gate 			lastarg = arg;
526*7c478bd9Sstevel@tonic-gate 			oklen = OK = FALSE;
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 			if (LEGAL) {
529*7c478bd9Sstevel@tonic-gate 				ERR = TRUE;
530*7c478bd9Sstevel@tonic-gate 				ermsg(gettext("arg list too long\n"));
531*7c478bd9Sstevel@tonic-gate 			} else if (N_args > 1) {
532*7c478bd9Sstevel@tonic-gate 				N_args = 1;
533*7c478bd9Sstevel@tonic-gate 			} else {
534*7c478bd9Sstevel@tonic-gate 				ermsg(gettext("a single arg was greater than "
535*7c478bd9Sstevel@tonic-gate 				    "the max arglist size of %d characters\n"),
536*7c478bd9Sstevel@tonic-gate 				    BUFLIM);
537*7c478bd9Sstevel@tonic-gate 				ERR = TRUE;
538*7c478bd9Sstevel@tonic-gate 			}
539*7c478bd9Sstevel@tonic-gate 		}
540*7c478bd9Sstevel@tonic-gate 	}
541*7c478bd9Sstevel@tonic-gate 	return (oklen ? arg : 0);
542*7c478bd9Sstevel@tonic-gate }
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate static char *
545*7c478bd9Sstevel@tonic-gate addarg(char *arg)
546*7c478bd9Sstevel@tonic-gate {
547*7c478bd9Sstevel@tonic-gate 	if (checklen(arg) != 0) {
548*7c478bd9Sstevel@tonic-gate 		(void) strcpy(next, arg);
549*7c478bd9Sstevel@tonic-gate 		arg = next;
550*7c478bd9Sstevel@tonic-gate 		next += strlen(arg) + 1;
551*7c478bd9Sstevel@tonic-gate 		return (arg);
552*7c478bd9Sstevel@tonic-gate 	}
553*7c478bd9Sstevel@tonic-gate 	return ((char *)0);
554*7c478bd9Sstevel@tonic-gate }
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate /*
557*7c478bd9Sstevel@tonic-gate  * store_wchr() : append a wchar_t to a char buffer, resize buffer if required.
558*7c478bd9Sstevel@tonic-gate  *
559*7c478bd9Sstevel@tonic-gate  *     Given a pointer to the beginning of a string buffer, the length of the
560*7c478bd9Sstevel@tonic-gate  *     buffer and an offset indicating the next place to write within that
561*7c478bd9Sstevel@tonic-gate  *     buffer, the passed wchar_t will be appended to the buffer if there is
562*7c478bd9Sstevel@tonic-gate  *     enough space. If there is not enough space, an attempt to reallocate the
563*7c478bd9Sstevel@tonic-gate  *     buffer will be made and if successful the passed pointer and size will be
564*7c478bd9Sstevel@tonic-gate  *     updated to describe the reallocated block. Returns the new value for
565*7c478bd9Sstevel@tonic-gate  *     'offset' (it will be incremented by the number of bytes written).
566*7c478bd9Sstevel@tonic-gate  */
567*7c478bd9Sstevel@tonic-gate static size_t
568*7c478bd9Sstevel@tonic-gate store_wchr(char **buffer, size_t *buflen, size_t offset, wchar_t c)
569*7c478bd9Sstevel@tonic-gate {
570*7c478bd9Sstevel@tonic-gate 	int bytes;
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 	/*
573*7c478bd9Sstevel@tonic-gate 	 * Make sure that there is enough room in the buffer to store the
574*7c478bd9Sstevel@tonic-gate 	 * maximum length of c.
575*7c478bd9Sstevel@tonic-gate 	 */
576*7c478bd9Sstevel@tonic-gate 	if ((offset + MB_CUR_MAX) > *buflen) {
577*7c478bd9Sstevel@tonic-gate 		/*
578*7c478bd9Sstevel@tonic-gate 		 * Not enough room so attempt to reallocate. Add 'MB_CUR_MAX' to
579*7c478bd9Sstevel@tonic-gate 		 * buffer length to ensure that there is always enough room to
580*7c478bd9Sstevel@tonic-gate 		 * store 'c' if realloc succeeds, no matter what QBUF_INC is
581*7c478bd9Sstevel@tonic-gate 		 * defined as.
582*7c478bd9Sstevel@tonic-gate 		 */
583*7c478bd9Sstevel@tonic-gate 		*buflen += (QBUF_INC + MB_CUR_MAX);
584*7c478bd9Sstevel@tonic-gate 		if ((*buffer = realloc(*buffer, *buflen)) == NULL) {
585*7c478bd9Sstevel@tonic-gate 			perror(gettext("xargs: Memory allocation failure"));
586*7c478bd9Sstevel@tonic-gate 			exit(1);
587*7c478bd9Sstevel@tonic-gate 		}
588*7c478bd9Sstevel@tonic-gate 	}
589*7c478bd9Sstevel@tonic-gate 	/* store bytes from wchar into buffer */
590*7c478bd9Sstevel@tonic-gate 	bytes = wctomb(*buffer + offset, c);
591*7c478bd9Sstevel@tonic-gate 	if (bytes == -1) {
592*7c478bd9Sstevel@tonic-gate 		/* char was invalid */
593*7c478bd9Sstevel@tonic-gate 		bytes = 1;
594*7c478bd9Sstevel@tonic-gate 		*(*buffer + offset) = (char)c;
595*7c478bd9Sstevel@tonic-gate 	}
596*7c478bd9Sstevel@tonic-gate 
597*7c478bd9Sstevel@tonic-gate 	/* return new value for offset */
598*7c478bd9Sstevel@tonic-gate 	return (offset + bytes);
599*7c478bd9Sstevel@tonic-gate }
600*7c478bd9Sstevel@tonic-gate 
601*7c478bd9Sstevel@tonic-gate static char *
602*7c478bd9Sstevel@tonic-gate getarg()
603*7c478bd9Sstevel@tonic-gate {
604*7c478bd9Sstevel@tonic-gate 	int	bytes;
605*7c478bd9Sstevel@tonic-gate 	wchar_t	c;
606*7c478bd9Sstevel@tonic-gate 	char	*arg;
607*7c478bd9Sstevel@tonic-gate 	char	*retarg, *requeue_buf;
608*7c478bd9Sstevel@tonic-gate 	size_t  requeue_offset = 0, requeue_len;
609*7c478bd9Sstevel@tonic-gate 	char	mbc[MB_LEN_MAX];
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 	while (iswspace(c = getwchr()) || c == '\n')
612*7c478bd9Sstevel@tonic-gate 		;
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 	if (c == '\0') {
615*7c478bd9Sstevel@tonic-gate 		MORE = FALSE;
616*7c478bd9Sstevel@tonic-gate 		return (0);
617*7c478bd9Sstevel@tonic-gate 	}
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 	/*
620*7c478bd9Sstevel@tonic-gate 	 * While we are reading in an argument, it is possible that we will
621*7c478bd9Sstevel@tonic-gate 	 * reach the maximum length of the overflow buffer and we'll have to
622*7c478bd9Sstevel@tonic-gate 	 * requeue what we have read so far. To handle this we allocate an
623*7c478bd9Sstevel@tonic-gate 	 * initial buffer here which will keep an unprocessed copy of the data
624*7c478bd9Sstevel@tonic-gate 	 * that we read in (this buffer will grow as required).
625*7c478bd9Sstevel@tonic-gate 	 */
626*7c478bd9Sstevel@tonic-gate 	requeue_len = (size_t)QBUF_STARTLEN;
627*7c478bd9Sstevel@tonic-gate 	if ((requeue_buf = (char *)malloc(requeue_len)) == NULL) {
628*7c478bd9Sstevel@tonic-gate 		perror(gettext("xargs: Memory allocation failure"));
629*7c478bd9Sstevel@tonic-gate 		exit(1);
630*7c478bd9Sstevel@tonic-gate 	}
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 	for (arg = next; ; c = getwchr()) {
633*7c478bd9Sstevel@tonic-gate 		bytes = wctomb(mbc, c);
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 		/*
636*7c478bd9Sstevel@tonic-gate 		 * Store the char that we have read before processing it in case
637*7c478bd9Sstevel@tonic-gate 		 * the current argument needs to be requeued.
638*7c478bd9Sstevel@tonic-gate 		 */
639*7c478bd9Sstevel@tonic-gate 		requeue_offset = store_wchr(&requeue_buf, &requeue_len,
640*7c478bd9Sstevel@tonic-gate 		    requeue_offset, c);
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 		/* Check for overflow the input buffer */
643*7c478bd9Sstevel@tonic-gate 		if ((next + ((bytes == -1) ? 1 : bytes)) >= &argbuf[BUFLIM]) {
644*7c478bd9Sstevel@tonic-gate 			/*
645*7c478bd9Sstevel@tonic-gate 			 * It's only an error if there are no Args in buffer
646*7c478bd9Sstevel@tonic-gate 			 * already.
647*7c478bd9Sstevel@tonic-gate 			 */
648*7c478bd9Sstevel@tonic-gate 			if ((N_ARGS || PER_LINE) && LEGAL) {
649*7c478bd9Sstevel@tonic-gate 				ERR = TRUE;
650*7c478bd9Sstevel@tonic-gate 				ermsg(gettext("Argument list too long\n"));
651*7c478bd9Sstevel@tonic-gate 				free(requeue_buf);
652*7c478bd9Sstevel@tonic-gate 				return (0);
653*7c478bd9Sstevel@tonic-gate 			} else if (N_args == 0) {
654*7c478bd9Sstevel@tonic-gate 				lastarg = "";
655*7c478bd9Sstevel@tonic-gate 				ERR = TRUE;
656*7c478bd9Sstevel@tonic-gate 				ermsg(gettext("A single arg was greater than "
657*7c478bd9Sstevel@tonic-gate 				    "the max arglist size of %d characters\n"),
658*7c478bd9Sstevel@tonic-gate 				    BUFSIZE);
659*7c478bd9Sstevel@tonic-gate 				free(requeue_buf);
660*7c478bd9Sstevel@tonic-gate 				return (0);
661*7c478bd9Sstevel@tonic-gate 			}
662*7c478bd9Sstevel@tonic-gate 			/*
663*7c478bd9Sstevel@tonic-gate 			 * Otherwise we put back the current argument
664*7c478bd9Sstevel@tonic-gate 			 * and use what we have collected so far...
665*7c478bd9Sstevel@tonic-gate 			 */
666*7c478bd9Sstevel@tonic-gate 			queue(requeue_buf, requeue_offset, HEAD);
667*7c478bd9Sstevel@tonic-gate 			/* reset inquote because we have requeued the quotes */
668*7c478bd9Sstevel@tonic-gate 			inquote = 0;
669*7c478bd9Sstevel@tonic-gate 			return (NULL);
670*7c478bd9Sstevel@tonic-gate 		}
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate 		if (iswctype(c, blank) && inquote == 0) {
674*7c478bd9Sstevel@tonic-gate 			if (INSERT) {
675*7c478bd9Sstevel@tonic-gate 				if (bytes == -1) {
676*7c478bd9Sstevel@tonic-gate 					*next++ = (char)c;
677*7c478bd9Sstevel@tonic-gate 				} else {
678*7c478bd9Sstevel@tonic-gate 					(void) wctomb(next, c);
679*7c478bd9Sstevel@tonic-gate 					next += bytes;
680*7c478bd9Sstevel@tonic-gate 				}
681*7c478bd9Sstevel@tonic-gate 				continue;
682*7c478bd9Sstevel@tonic-gate 			}
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 			/* skip over trailing whitespace till next arg */
685*7c478bd9Sstevel@tonic-gate 			while (iswctype((c = getwchr()), blank) &&
686*7c478bd9Sstevel@tonic-gate 			    (c != '\n') && (c != '\0'))
687*7c478bd9Sstevel@tonic-gate 				;
688*7c478bd9Sstevel@tonic-gate 
689*7c478bd9Sstevel@tonic-gate 			/*
690*7c478bd9Sstevel@tonic-gate 			 * if there was space till end of line then the last
691*7c478bd9Sstevel@tonic-gate 			 * character was really a newline...
692*7c478bd9Sstevel@tonic-gate 			 */
693*7c478bd9Sstevel@tonic-gate 			if (c == L'\n' || c == L'\0') {
694*7c478bd9Sstevel@tonic-gate 				ungetwchr(L'\n');
695*7c478bd9Sstevel@tonic-gate 			} else {
696*7c478bd9Sstevel@tonic-gate 				/* later code needs to know this was a space */
697*7c478bd9Sstevel@tonic-gate 				ungetwchr(c);
698*7c478bd9Sstevel@tonic-gate 				c = L' ';
699*7c478bd9Sstevel@tonic-gate 			}
700*7c478bd9Sstevel@tonic-gate 			goto end_arg;
701*7c478bd9Sstevel@tonic-gate 		}
702*7c478bd9Sstevel@tonic-gate 		switch (c) {
703*7c478bd9Sstevel@tonic-gate 		case L'\0':
704*7c478bd9Sstevel@tonic-gate 		case L'\n':
705*7c478bd9Sstevel@tonic-gate 			if (inquote) {
706*7c478bd9Sstevel@tonic-gate 				*next++ = '\0';
707*7c478bd9Sstevel@tonic-gate 				ermsg(gettext("Missing quote: %s\n"), arg);
708*7c478bd9Sstevel@tonic-gate 				ERR = TRUE;
709*7c478bd9Sstevel@tonic-gate 				free(requeue_buf);
710*7c478bd9Sstevel@tonic-gate 				return (0);
711*7c478bd9Sstevel@tonic-gate 			}
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 			N_lines++;
714*7c478bd9Sstevel@tonic-gate end_arg:		*next++ = '\0';
715*7c478bd9Sstevel@tonic-gate 			/* we finished without requeuing so free requeue_buf */
716*7c478bd9Sstevel@tonic-gate 			free(requeue_buf);
717*7c478bd9Sstevel@tonic-gate 			if (strcmp(arg, LEOF) == 0 || (c == '\0' &&
718*7c478bd9Sstevel@tonic-gate 			    strlen(arg) == 0)) {
719*7c478bd9Sstevel@tonic-gate 				MORE = FALSE;
720*7c478bd9Sstevel@tonic-gate 				/* absorb the rest of the line */
721*7c478bd9Sstevel@tonic-gate 				if ((c != '\n') && (c != '\0'))
722*7c478bd9Sstevel@tonic-gate 					while (c = getwchr())
723*7c478bd9Sstevel@tonic-gate 						if ((c == '\n') || (c == '\0'))
724*7c478bd9Sstevel@tonic-gate 							break;
725*7c478bd9Sstevel@tonic-gate 				return (0);
726*7c478bd9Sstevel@tonic-gate 			} else {
727*7c478bd9Sstevel@tonic-gate 				++N_args;
728*7c478bd9Sstevel@tonic-gate 				if (retarg = checklen(arg)) {
729*7c478bd9Sstevel@tonic-gate 					if ((PER_LINE &&
730*7c478bd9Sstevel@tonic-gate 					    N_lines >= PER_LINE &&
731*7c478bd9Sstevel@tonic-gate 					    (c == '\0' || c == '\n')) ||
732*7c478bd9Sstevel@tonic-gate 					    (N_ARGS && N_args >= N_ARGS)) {
733*7c478bd9Sstevel@tonic-gate 						N_lines = N_args = 0;
734*7c478bd9Sstevel@tonic-gate 						lastarg = "";
735*7c478bd9Sstevel@tonic-gate 						OK = FALSE;
736*7c478bd9Sstevel@tonic-gate 					}
737*7c478bd9Sstevel@tonic-gate 				}
738*7c478bd9Sstevel@tonic-gate 				return (retarg);
739*7c478bd9Sstevel@tonic-gate 			}
740*7c478bd9Sstevel@tonic-gate 
741*7c478bd9Sstevel@tonic-gate 		case '"':
742*7c478bd9Sstevel@tonic-gate 			if (inquote == 1)	/* in single quoted string */
743*7c478bd9Sstevel@tonic-gate 				goto is_default;
744*7c478bd9Sstevel@tonic-gate 			if (inquote == 2)	/* terminating double quote */
745*7c478bd9Sstevel@tonic-gate 				inquote = 0;
746*7c478bd9Sstevel@tonic-gate 			else			/* starting quoted string */
747*7c478bd9Sstevel@tonic-gate 				inquote = 2;
748*7c478bd9Sstevel@tonic-gate 			break;
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 		case '\'':
751*7c478bd9Sstevel@tonic-gate 			if (inquote == 2)	/* in double quoted string */
752*7c478bd9Sstevel@tonic-gate 				goto is_default;
753*7c478bd9Sstevel@tonic-gate 			if (inquote == 1)	/* terminating single quote */
754*7c478bd9Sstevel@tonic-gate 				inquote = 0;
755*7c478bd9Sstevel@tonic-gate 			else			/* starting quoted string */
756*7c478bd9Sstevel@tonic-gate 				inquote = 1;
757*7c478bd9Sstevel@tonic-gate 			break;
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 		case L'\\':
760*7c478bd9Sstevel@tonic-gate 			c = getwchr();
761*7c478bd9Sstevel@tonic-gate 			/* store quoted char for potential requeueing */
762*7c478bd9Sstevel@tonic-gate 			requeue_offset = store_wchr(&requeue_buf, &requeue_len,
763*7c478bd9Sstevel@tonic-gate 			    requeue_offset, c);
764*7c478bd9Sstevel@tonic-gate 
765*7c478bd9Sstevel@tonic-gate 		default:
766*7c478bd9Sstevel@tonic-gate is_default:		if (bytes == -1) {
767*7c478bd9Sstevel@tonic-gate 				*next++ = (char)c;
768*7c478bd9Sstevel@tonic-gate 			} else {
769*7c478bd9Sstevel@tonic-gate 				(void) wctomb(next, c);
770*7c478bd9Sstevel@tonic-gate 				next += bytes;
771*7c478bd9Sstevel@tonic-gate 			}
772*7c478bd9Sstevel@tonic-gate 			break;
773*7c478bd9Sstevel@tonic-gate 		}
774*7c478bd9Sstevel@tonic-gate 	}
775*7c478bd9Sstevel@tonic-gate }
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate /*
779*7c478bd9Sstevel@tonic-gate  * ermsg():	print out an error message, and indicate failure globally.
780*7c478bd9Sstevel@tonic-gate  *
781*7c478bd9Sstevel@tonic-gate  *	Assumes that message has already been gettext()'d. It would be
782*7c478bd9Sstevel@tonic-gate  *	nice if we could just do the gettext() here, but we can't, since
783*7c478bd9Sstevel@tonic-gate  *	since xgettext(1M) wouldn't be able to pick up our error message.
784*7c478bd9Sstevel@tonic-gate  */
785*7c478bd9Sstevel@tonic-gate /* PRINTFLIKE1 */
786*7c478bd9Sstevel@tonic-gate static void
787*7c478bd9Sstevel@tonic-gate ermsg(char *messages, ...)
788*7c478bd9Sstevel@tonic-gate {
789*7c478bd9Sstevel@tonic-gate 	va_list	ap;
790*7c478bd9Sstevel@tonic-gate 
791*7c478bd9Sstevel@tonic-gate 	va_start(ap, messages);
792*7c478bd9Sstevel@tonic-gate 
793*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "xargs: ");
794*7c478bd9Sstevel@tonic-gate 	(void) vfprintf(stderr, messages, ap);
795*7c478bd9Sstevel@tonic-gate 
796*7c478bd9Sstevel@tonic-gate 	va_end(ap);
797*7c478bd9Sstevel@tonic-gate 	OK = FALSE;
798*7c478bd9Sstevel@tonic-gate }
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 
801*7c478bd9Sstevel@tonic-gate /*
802*7c478bd9Sstevel@tonic-gate  * Function: int rpmatch(char *)
803*7c478bd9Sstevel@tonic-gate  *
804*7c478bd9Sstevel@tonic-gate  * Description:
805*7c478bd9Sstevel@tonic-gate  *
806*7c478bd9Sstevel@tonic-gate  *	Internationalized get yes / no answer.
807*7c478bd9Sstevel@tonic-gate  *
808*7c478bd9Sstevel@tonic-gate  * Inputs:
809*7c478bd9Sstevel@tonic-gate  *	s	-> Pointer to answer to compare against.
810*7c478bd9Sstevel@tonic-gate  *
811*7c478bd9Sstevel@tonic-gate  * Returns:
812*7c478bd9Sstevel@tonic-gate  *	TRUE	-> Answer was affirmative
813*7c478bd9Sstevel@tonic-gate  *	FALSE	-> Answer was negative
814*7c478bd9Sstevel@tonic-gate  */
815*7c478bd9Sstevel@tonic-gate 
816*7c478bd9Sstevel@tonic-gate static int
817*7c478bd9Sstevel@tonic-gate rpmatch(char *s)
818*7c478bd9Sstevel@tonic-gate {
819*7c478bd9Sstevel@tonic-gate 	static char	*default_yesexpr = "^[Yy].*";
820*7c478bd9Sstevel@tonic-gate 	static char	*compiled_yesexpr = (char *)NULL;
821*7c478bd9Sstevel@tonic-gate 
822*7c478bd9Sstevel@tonic-gate 	/* Execute once to initialize */
823*7c478bd9Sstevel@tonic-gate 	if (compiled_yesexpr == (char *)NULL) {
824*7c478bd9Sstevel@tonic-gate 		char	*yesexpr;
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate 		/* get yes expression according to current locale */
827*7c478bd9Sstevel@tonic-gate 		yesexpr = nl_langinfo(YESEXPR);
828*7c478bd9Sstevel@tonic-gate 		/*
829*7c478bd9Sstevel@tonic-gate 		 * If the was no expression or if there is a compile error
830*7c478bd9Sstevel@tonic-gate 		 * use default yes expression.  Anchor
831*7c478bd9Sstevel@tonic-gate 		 */
832*7c478bd9Sstevel@tonic-gate 		if ((yesexpr == (char *)NULL) || (*yesexpr == (char)NULL) ||
833*7c478bd9Sstevel@tonic-gate 		    ((compiled_yesexpr =
834*7c478bd9Sstevel@tonic-gate 		    regcmp(yesexpr, 0)) == NULL))
835*7c478bd9Sstevel@tonic-gate 			compiled_yesexpr = regcmp(default_yesexpr, 0);
836*7c478bd9Sstevel@tonic-gate 	}
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate 	/* match yesexpr */
839*7c478bd9Sstevel@tonic-gate 	if (regex(compiled_yesexpr, s) == NULL) {
840*7c478bd9Sstevel@tonic-gate 		return (FALSE);
841*7c478bd9Sstevel@tonic-gate 	}
842*7c478bd9Sstevel@tonic-gate 	return (TRUE);
843*7c478bd9Sstevel@tonic-gate }
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate static int
846*7c478bd9Sstevel@tonic-gate echoargs()
847*7c478bd9Sstevel@tonic-gate {
848*7c478bd9Sstevel@tonic-gate 	char	**anarg;
849*7c478bd9Sstevel@tonic-gate 	char	**tanarg;	/* tmp ptr			*/
850*7c478bd9Sstevel@tonic-gate 	int		i;
851*7c478bd9Sstevel@tonic-gate 	char		reply[LINE_MAX];
852*7c478bd9Sstevel@tonic-gate 
853*7c478bd9Sstevel@tonic-gate 	tanarg = anarg = arglist-1;
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 	/*
856*7c478bd9Sstevel@tonic-gate 	 * write out each argument, separated by a space. the tanarg
857*7c478bd9Sstevel@tonic-gate 	 * nonsense is for xcu4 testsuite compliance - so that an
858*7c478bd9Sstevel@tonic-gate 	 * extra space isn't echoed after the last argument.
859*7c478bd9Sstevel@tonic-gate 	 */
860*7c478bd9Sstevel@tonic-gate 	while (*++anarg) {		/* while there's an argument	*/
861*7c478bd9Sstevel@tonic-gate 		++tanarg;		/* follow anarg			*/
862*7c478bd9Sstevel@tonic-gate 		(void) write(2, *anarg, strlen(*anarg));
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 		if (*++tanarg) {	/* if there's another argument:	*/
865*7c478bd9Sstevel@tonic-gate 			(void) write(2, " ", 1); /* add a space		*/
866*7c478bd9Sstevel@tonic-gate 			--tanarg;	/* reset back to anarg		*/
867*7c478bd9Sstevel@tonic-gate 		}
868*7c478bd9Sstevel@tonic-gate 	}
869*7c478bd9Sstevel@tonic-gate 	if (PROMPT == -1) {
870*7c478bd9Sstevel@tonic-gate 		(void) write(2, "\n", 1);
871*7c478bd9Sstevel@tonic-gate 		return (TRUE);
872*7c478bd9Sstevel@tonic-gate 	}
873*7c478bd9Sstevel@tonic-gate 
874*7c478bd9Sstevel@tonic-gate 	/*
875*7c478bd9Sstevel@tonic-gate 	 * at this point, there may be unexpected input pending on stdin,
876*7c478bd9Sstevel@tonic-gate 	 * if one has used the -n flag. this presents a problem, because
877*7c478bd9Sstevel@tonic-gate 	 * if we simply do a read(), we'll get the extra input, instead
878*7c478bd9Sstevel@tonic-gate 	 * of our desired y/n input. so, we see if there's any extra
879*7c478bd9Sstevel@tonic-gate 	 * input, and if there is, then we will store it.
880*7c478bd9Sstevel@tonic-gate 	 */
881*7c478bd9Sstevel@tonic-gate 
882*7c478bd9Sstevel@tonic-gate 	saveinput();
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate 	(void) write(2, "?...", 4);	/* ask the user for input	*/
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < LINE_MAX && read(PROMPT, &reply[i], 1) > 0; i++) {
887*7c478bd9Sstevel@tonic-gate 		if (reply[i] == '\n') {
888*7c478bd9Sstevel@tonic-gate 			if (i == 0)
889*7c478bd9Sstevel@tonic-gate 				return (FALSE);
890*7c478bd9Sstevel@tonic-gate 			break;
891*7c478bd9Sstevel@tonic-gate 		}
892*7c478bd9Sstevel@tonic-gate 	}
893*7c478bd9Sstevel@tonic-gate 	reply[i] = 0;
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 	/* flush remainder of line if necessary */
896*7c478bd9Sstevel@tonic-gate 	if (i == LINE_MAX) {
897*7c478bd9Sstevel@tonic-gate 		char	bitbucket;
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 		while ((read(PROMPT, &bitbucket, 1) > 0) && (bitbucket != '\n'))
900*7c478bd9Sstevel@tonic-gate 			;
901*7c478bd9Sstevel@tonic-gate 	}
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 	/*
904*7c478bd9Sstevel@tonic-gate 	 * now we have to figure out whether the user typed an
905*7c478bd9Sstevel@tonic-gate 	 * internationalized version of 'y' for yes. note that in some
906*7c478bd9Sstevel@tonic-gate 	 * countries, they've gotten used to typing an ASCII 'y'! so
907*7c478bd9Sstevel@tonic-gate 	 * even if our int'l version fails, we will check for an ASCII
908*7c478bd9Sstevel@tonic-gate 	 * 'y', in order to be backwards compatible.
909*7c478bd9Sstevel@tonic-gate 	 */
910*7c478bd9Sstevel@tonic-gate 	return (rpmatch(reply));
911*7c478bd9Sstevel@tonic-gate }
912*7c478bd9Sstevel@tonic-gate 
913*7c478bd9Sstevel@tonic-gate 
914*7c478bd9Sstevel@tonic-gate static char *
915*7c478bd9Sstevel@tonic-gate insert(char *pattern, char *subst)
916*7c478bd9Sstevel@tonic-gate {
917*7c478bd9Sstevel@tonic-gate 	static char	buffer[MAXSBUF+1];
918*7c478bd9Sstevel@tonic-gate 	int		len, ipatlen;
919*7c478bd9Sstevel@tonic-gate 	char	*pat;
920*7c478bd9Sstevel@tonic-gate 	char	*bufend;
921*7c478bd9Sstevel@tonic-gate 	char	*pbuf;
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 	len = strlen(subst);
924*7c478bd9Sstevel@tonic-gate 	ipatlen = strlen(INSPAT) - 1;
925*7c478bd9Sstevel@tonic-gate 	pat = pattern - 1;
926*7c478bd9Sstevel@tonic-gate 	pbuf = buffer;
927*7c478bd9Sstevel@tonic-gate 	bufend = &buffer[MAXSBUF];
928*7c478bd9Sstevel@tonic-gate 
929*7c478bd9Sstevel@tonic-gate 	while (*++pat) {
930*7c478bd9Sstevel@tonic-gate 		if (xindex(pat, INSPAT) == 0) {
931*7c478bd9Sstevel@tonic-gate 			if (pbuf + len >= bufend) {
932*7c478bd9Sstevel@tonic-gate 				break;
933*7c478bd9Sstevel@tonic-gate 			} else {
934*7c478bd9Sstevel@tonic-gate 				(void) strcpy(pbuf, subst);
935*7c478bd9Sstevel@tonic-gate 				pat += ipatlen;
936*7c478bd9Sstevel@tonic-gate 				pbuf += len;
937*7c478bd9Sstevel@tonic-gate 			}
938*7c478bd9Sstevel@tonic-gate 		} else {
939*7c478bd9Sstevel@tonic-gate 			*pbuf++ = *pat;
940*7c478bd9Sstevel@tonic-gate 			if (pbuf >= bufend)
941*7c478bd9Sstevel@tonic-gate 				break;
942*7c478bd9Sstevel@tonic-gate 		}
943*7c478bd9Sstevel@tonic-gate 	}
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate 	if (!*pat) {
946*7c478bd9Sstevel@tonic-gate 		*pbuf = '\0';
947*7c478bd9Sstevel@tonic-gate 		return (buffer);
948*7c478bd9Sstevel@tonic-gate 	} else {
949*7c478bd9Sstevel@tonic-gate 		ermsg(gettext("Maximum argument size with insertion via %s's "
950*7c478bd9Sstevel@tonic-gate 		    "exceeded\n"), INSPAT);
951*7c478bd9Sstevel@tonic-gate 		ERR = TRUE;
952*7c478bd9Sstevel@tonic-gate 		return (0);
953*7c478bd9Sstevel@tonic-gate 	}
954*7c478bd9Sstevel@tonic-gate }
955*7c478bd9Sstevel@tonic-gate 
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate static void
958*7c478bd9Sstevel@tonic-gate addibuf(struct inserts	*p)
959*7c478bd9Sstevel@tonic-gate {
960*7c478bd9Sstevel@tonic-gate 	char	*newarg, *skel, *sub;
961*7c478bd9Sstevel@tonic-gate 	int		l;
962*7c478bd9Sstevel@tonic-gate 
963*7c478bd9Sstevel@tonic-gate 	skel = p->p_skel;
964*7c478bd9Sstevel@tonic-gate 	sub = *ARGV;
965*7c478bd9Sstevel@tonic-gate 	linesize -= strlen(skel) + 1;
966*7c478bd9Sstevel@tonic-gate 	newarg = insert(skel, sub);
967*7c478bd9Sstevel@tonic-gate 	if (ERR)
968*7c478bd9Sstevel@tonic-gate 	    return;
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 	if (checklen(newarg)) {
971*7c478bd9Sstevel@tonic-gate 		if ((ibufsize += (l = strlen(newarg) + 1)) > MAXIBUF) {
972*7c478bd9Sstevel@tonic-gate 			ermsg(gettext("Insert buffer overflow\n"));
973*7c478bd9Sstevel@tonic-gate 			ERR = TRUE;
974*7c478bd9Sstevel@tonic-gate 		}
975*7c478bd9Sstevel@tonic-gate 		(void) strcpy(p_ibuf, newarg);
976*7c478bd9Sstevel@tonic-gate 		*(p->p_ARGV) = p_ibuf;
977*7c478bd9Sstevel@tonic-gate 		p_ibuf += l;
978*7c478bd9Sstevel@tonic-gate 	}
979*7c478bd9Sstevel@tonic-gate }
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate /*
983*7c478bd9Sstevel@tonic-gate  * getchr():	get the next character.
984*7c478bd9Sstevel@tonic-gate  * description:
985*7c478bd9Sstevel@tonic-gate  *	we get the next character from pio.structure, if there's a character
986*7c478bd9Sstevel@tonic-gate  *	to get. this may happen when we've had to flush stdin=/dev/tty,
987*7c478bd9Sstevel@tonic-gate  *	but still wanted to preserve the characters for later processing.
988*7c478bd9Sstevel@tonic-gate  *
989*7c478bd9Sstevel@tonic-gate  *	otherwise we just get the character from stdin.
990*7c478bd9Sstevel@tonic-gate  */
991*7c478bd9Sstevel@tonic-gate static int
992*7c478bd9Sstevel@tonic-gate getchr(void)
993*7c478bd9Sstevel@tonic-gate {
994*7c478bd9Sstevel@tonic-gate 	char	c;
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 	do {
997*7c478bd9Sstevel@tonic-gate 		if (queued_data == NULL) {
998*7c478bd9Sstevel@tonic-gate 			char	*buffer;
999*7c478bd9Sstevel@tonic-gate 			int	len;
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 			if ((buffer = malloc(BUFSIZE)) == NULL) {
1002*7c478bd9Sstevel@tonic-gate 				perror(gettext(
1003*7c478bd9Sstevel@tonic-gate 				    "xargs: Memory allocation failure"));
1004*7c478bd9Sstevel@tonic-gate 				exit(1);
1005*7c478bd9Sstevel@tonic-gate 			}
1006*7c478bd9Sstevel@tonic-gate 
1007*7c478bd9Sstevel@tonic-gate 			if ((len = read(0, buffer, BUFSIZE)) == 0)
1008*7c478bd9Sstevel@tonic-gate 				return (0);
1009*7c478bd9Sstevel@tonic-gate 			if (len == -1) {
1010*7c478bd9Sstevel@tonic-gate 				perror(gettext("xargs: Read failure"));
1011*7c478bd9Sstevel@tonic-gate 				exit(1);
1012*7c478bd9Sstevel@tonic-gate 			}
1013*7c478bd9Sstevel@tonic-gate 
1014*7c478bd9Sstevel@tonic-gate 			queue(buffer, len, TAIL);
1015*7c478bd9Sstevel@tonic-gate 		}
1016*7c478bd9Sstevel@tonic-gate 
1017*7c478bd9Sstevel@tonic-gate 		file_offset++;
1018*7c478bd9Sstevel@tonic-gate 		c = *queued_data->cur++;	 /* get the next character */
1019*7c478bd9Sstevel@tonic-gate 		if (--queued_data->length == 0) { /* at the end of buffer? */
1020*7c478bd9Sstevel@tonic-gate 			pio	*nxt = queued_data->next;
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate 			free(queued_data->start);
1023*7c478bd9Sstevel@tonic-gate 			free(queued_data);
1024*7c478bd9Sstevel@tonic-gate 			queued_data = nxt;
1025*7c478bd9Sstevel@tonic-gate 		}
1026*7c478bd9Sstevel@tonic-gate 	} while (c == '\0');
1027*7c478bd9Sstevel@tonic-gate 	return (c);
1028*7c478bd9Sstevel@tonic-gate }
1029*7c478bd9Sstevel@tonic-gate 
1030*7c478bd9Sstevel@tonic-gate 
1031*7c478bd9Sstevel@tonic-gate static wchar_t
1032*7c478bd9Sstevel@tonic-gate getwchr(void)
1033*7c478bd9Sstevel@tonic-gate {
1034*7c478bd9Sstevel@tonic-gate 	int		i;
1035*7c478bd9Sstevel@tonic-gate 	wchar_t		wch;
1036*7c478bd9Sstevel@tonic-gate 	unsigned char	buffer[MB_LEN_MAX + 1];
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < (int)MB_CUR_MAX; ) {
1039*7c478bd9Sstevel@tonic-gate 		if ((buffer[i++] = getchr()) == NULL) {
1040*7c478bd9Sstevel@tonic-gate 			/* We have reached  EOF */
1041*7c478bd9Sstevel@tonic-gate 			if (i == 1) {
1042*7c478bd9Sstevel@tonic-gate 				/* TRUE EOF has been reached */
1043*7c478bd9Sstevel@tonic-gate 				return (NULL);
1044*7c478bd9Sstevel@tonic-gate 			}
1045*7c478bd9Sstevel@tonic-gate 			/*
1046*7c478bd9Sstevel@tonic-gate 			 * We have some characters in our buffer still so it
1047*7c478bd9Sstevel@tonic-gate 			 * must be an invalid character right before EOF.
1048*7c478bd9Sstevel@tonic-gate 			 */
1049*7c478bd9Sstevel@tonic-gate 			break;
1050*7c478bd9Sstevel@tonic-gate 		}
1051*7c478bd9Sstevel@tonic-gate 
1052*7c478bd9Sstevel@tonic-gate 		/* If this succeeds then we are done */
1053*7c478bd9Sstevel@tonic-gate 		if (mbtowc(&wch, (char *)buffer, i) != -1)
1054*7c478bd9Sstevel@tonic-gate 			return (wch);
1055*7c478bd9Sstevel@tonic-gate 	}
1056*7c478bd9Sstevel@tonic-gate 
1057*7c478bd9Sstevel@tonic-gate 	/*
1058*7c478bd9Sstevel@tonic-gate 	 * We have now encountered an illegal character sequence.
1059*7c478bd9Sstevel@tonic-gate 	 * There is nothing much we can do at this point but
1060*7c478bd9Sstevel@tonic-gate 	 * return an error.  If we attempt to recover we may in fact
1061*7c478bd9Sstevel@tonic-gate 	 * return garbage as arguments, from the customer's point
1062*7c478bd9Sstevel@tonic-gate 	 * of view.  After all what if they are feeding us a file
1063*7c478bd9Sstevel@tonic-gate 	 * generated in another locale?
1064*7c478bd9Sstevel@tonic-gate 	 */
1065*7c478bd9Sstevel@tonic-gate 	errno = EILSEQ;
1066*7c478bd9Sstevel@tonic-gate 	perror(gettext("xargs: Corrupt input file"));
1067*7c478bd9Sstevel@tonic-gate 	exit(1);
1068*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
1069*7c478bd9Sstevel@tonic-gate }
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 
1072*7c478bd9Sstevel@tonic-gate static void
1073*7c478bd9Sstevel@tonic-gate ungetwchr(wchar_t wch)
1074*7c478bd9Sstevel@tonic-gate {
1075*7c478bd9Sstevel@tonic-gate 	char	*buffer;
1076*7c478bd9Sstevel@tonic-gate 	int	bytes;
1077*7c478bd9Sstevel@tonic-gate 
1078*7c478bd9Sstevel@tonic-gate 	if ((buffer = malloc(MB_LEN_MAX)) == NULL) {
1079*7c478bd9Sstevel@tonic-gate 		perror(gettext("xargs: Memory allocation failure"));
1080*7c478bd9Sstevel@tonic-gate 		exit(1);
1081*7c478bd9Sstevel@tonic-gate 	}
1082*7c478bd9Sstevel@tonic-gate 	bytes = wctomb(buffer, wch);
1083*7c478bd9Sstevel@tonic-gate 	queue(buffer, bytes, HEAD);
1084*7c478bd9Sstevel@tonic-gate }
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate 
1087*7c478bd9Sstevel@tonic-gate static int
1088*7c478bd9Sstevel@tonic-gate lcall(char *sub, char **subargs)
1089*7c478bd9Sstevel@tonic-gate {
1090*7c478bd9Sstevel@tonic-gate 	int retcode, retry = 0;
1091*7c478bd9Sstevel@tonic-gate 	pid_t iwait, child;
1092*7c478bd9Sstevel@tonic-gate 
1093*7c478bd9Sstevel@tonic-gate 	for (; ; ) {
1094*7c478bd9Sstevel@tonic-gate 		switch (child = fork()) {
1095*7c478bd9Sstevel@tonic-gate 		default:
1096*7c478bd9Sstevel@tonic-gate 			while ((iwait = wait(&retcode)) != child &&
1097*7c478bd9Sstevel@tonic-gate 			    iwait != (pid_t)-1)
1098*7c478bd9Sstevel@tonic-gate 				;
1099*7c478bd9Sstevel@tonic-gate 			if (iwait == (pid_t)-1) {
1100*7c478bd9Sstevel@tonic-gate 				perror(gettext("xargs: Wait failure"));
1101*7c478bd9Sstevel@tonic-gate 				exit(122);
1102*7c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
1103*7c478bd9Sstevel@tonic-gate 			}
1104*7c478bd9Sstevel@tonic-gate 			if (WIFSIGNALED(retcode)) {
1105*7c478bd9Sstevel@tonic-gate 				ermsg(gettext("Child killed with signal %d\n"),
1106*7c478bd9Sstevel@tonic-gate 				    WTERMSIG(retcode));
1107*7c478bd9Sstevel@tonic-gate 				exit(125);
1108*7c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
1109*7c478bd9Sstevel@tonic-gate 			}
1110*7c478bd9Sstevel@tonic-gate 			if ((WEXITSTATUS(retcode) & 0377) == 0377) {
1111*7c478bd9Sstevel@tonic-gate 				ermsg(gettext("Command could not continue "
1112*7c478bd9Sstevel@tonic-gate 				    "processing data\n"));
1113*7c478bd9Sstevel@tonic-gate 				exit(124);
1114*7c478bd9Sstevel@tonic-gate 				/* NOTREACHED */
1115*7c478bd9Sstevel@tonic-gate 			}
1116*7c478bd9Sstevel@tonic-gate 			return (WEXITSTATUS(retcode));
1117*7c478bd9Sstevel@tonic-gate 		case 0:
1118*7c478bd9Sstevel@tonic-gate 			(void) execvp(sub, subargs);
1119*7c478bd9Sstevel@tonic-gate 			perror(gettext("xargs: Could not exec command"));
1120*7c478bd9Sstevel@tonic-gate 			if (errno == EACCES)
1121*7c478bd9Sstevel@tonic-gate 				exit(126);
1122*7c478bd9Sstevel@tonic-gate 			exit(127);
1123*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
1124*7c478bd9Sstevel@tonic-gate 		case -1:
1125*7c478bd9Sstevel@tonic-gate 			if (errno != EAGAIN && retry++ < FORK_RETRY) {
1126*7c478bd9Sstevel@tonic-gate 				perror(gettext("xargs: Could not fork child"));
1127*7c478bd9Sstevel@tonic-gate 				exit(123);
1128*7c478bd9Sstevel@tonic-gate 			}
1129*7c478bd9Sstevel@tonic-gate 			(void) sleep(1);
1130*7c478bd9Sstevel@tonic-gate 		}
1131*7c478bd9Sstevel@tonic-gate 	}
1132*7c478bd9Sstevel@tonic-gate }
1133*7c478bd9Sstevel@tonic-gate 
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate /*
1136*7c478bd9Sstevel@tonic-gate  * If `s2' is a substring of `s1' return the offset of the first
1137*7c478bd9Sstevel@tonic-gate  * occurrence of `s2' in `s1', else return -1.
1138*7c478bd9Sstevel@tonic-gate  */
1139*7c478bd9Sstevel@tonic-gate static int
1140*7c478bd9Sstevel@tonic-gate xindex(char *as1, char *as2)
1141*7c478bd9Sstevel@tonic-gate {
1142*7c478bd9Sstevel@tonic-gate 	char	*s1, *s2, c;
1143*7c478bd9Sstevel@tonic-gate 	int		offset;
1144*7c478bd9Sstevel@tonic-gate 
1145*7c478bd9Sstevel@tonic-gate 	s1 = as1;
1146*7c478bd9Sstevel@tonic-gate 	s2 = as2;
1147*7c478bd9Sstevel@tonic-gate 	c = *s2;
1148*7c478bd9Sstevel@tonic-gate 
1149*7c478bd9Sstevel@tonic-gate 	while (*s1) {
1150*7c478bd9Sstevel@tonic-gate 		if (*s1++ == c) {
1151*7c478bd9Sstevel@tonic-gate 			offset = s1 - as1 - 1;
1152*7c478bd9Sstevel@tonic-gate 			s2++;
1153*7c478bd9Sstevel@tonic-gate 			while ((c = *s2++) == *s1++ && c)
1154*7c478bd9Sstevel@tonic-gate 				;
1155*7c478bd9Sstevel@tonic-gate 			if (c == 0)
1156*7c478bd9Sstevel@tonic-gate 				return (offset);
1157*7c478bd9Sstevel@tonic-gate 			s1 = offset + as1 + 1;
1158*7c478bd9Sstevel@tonic-gate 			s2 = as2;
1159*7c478bd9Sstevel@tonic-gate 			c = *s2;
1160*7c478bd9Sstevel@tonic-gate 		}
1161*7c478bd9Sstevel@tonic-gate 	}
1162*7c478bd9Sstevel@tonic-gate 	return (-1);
1163*7c478bd9Sstevel@tonic-gate }
1164*7c478bd9Sstevel@tonic-gate 
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate static void
1167*7c478bd9Sstevel@tonic-gate usage()
1168*7c478bd9Sstevel@tonic-gate {
1169*7c478bd9Sstevel@tonic-gate 	ermsg(gettext(USAGEMSG));
1170*7c478bd9Sstevel@tonic-gate 	OK = FALSE;
1171*7c478bd9Sstevel@tonic-gate }
1172*7c478bd9Sstevel@tonic-gate 
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 
1175*7c478bd9Sstevel@tonic-gate /*
1176*7c478bd9Sstevel@tonic-gate  * parseargs():		modify the args
1177*7c478bd9Sstevel@tonic-gate  *	since the -e, -i and -l flags all take optional subarguments,
1178*7c478bd9Sstevel@tonic-gate  *	and getopts(3C) is clueless about this nonsense, we change the
1179*7c478bd9Sstevel@tonic-gate  *	our local argument count and strings to separate this out,
1180*7c478bd9Sstevel@tonic-gate  *	and make it easier to handle via getopts(3c).
1181*7c478bd9Sstevel@tonic-gate  *
1182*7c478bd9Sstevel@tonic-gate  *	-e	-> "-e ""
1183*7c478bd9Sstevel@tonic-gate  *	-e3	-> "-e "3"
1184*7c478bd9Sstevel@tonic-gate  *	-Estr	-> "-E "str"
1185*7c478bd9Sstevel@tonic-gate  *	-i	-> "-i "{}"
1186*7c478bd9Sstevel@tonic-gate  *	-irep	-> "-i "rep"
1187*7c478bd9Sstevel@tonic-gate  *	-l	-> "-i "1"
1188*7c478bd9Sstevel@tonic-gate  *	-l10	-> "-i "10"
1189*7c478bd9Sstevel@tonic-gate  *
1190*7c478bd9Sstevel@tonic-gate  *	since the -e, -i and -l flags all take optional subarguments,
1191*7c478bd9Sstevel@tonic-gate  */
1192*7c478bd9Sstevel@tonic-gate static void
1193*7c478bd9Sstevel@tonic-gate parseargs(int ac, char **av)
1194*7c478bd9Sstevel@tonic-gate {
1195*7c478bd9Sstevel@tonic-gate 	int i;			/* current argument			*/
1196*7c478bd9Sstevel@tonic-gate 	int cflag;		/* 0 = not processing cmd arg		*/
1197*7c478bd9Sstevel@tonic-gate 
1198*7c478bd9Sstevel@tonic-gate 	if ((mav = malloc((ac * 2 + 1) * sizeof (char *))) == NULL) {
1199*7c478bd9Sstevel@tonic-gate 		perror(gettext("xargs: Memory allocation failure"));
1200*7c478bd9Sstevel@tonic-gate 		exit(1);
1201*7c478bd9Sstevel@tonic-gate 	}
1202*7c478bd9Sstevel@tonic-gate 
1203*7c478bd9Sstevel@tonic-gate 	/* for each argument, see if we need to change things:		*/
1204*7c478bd9Sstevel@tonic-gate 	for (i = mac = cflag = 0; (av[i] != NULL) && i < ac; i++, mac++) {
1205*7c478bd9Sstevel@tonic-gate 		if ((mav[mac] = strdup(av[i])) == NULL) {
1206*7c478bd9Sstevel@tonic-gate 			perror(gettext("xargs: Memory allocation failure"));
1207*7c478bd9Sstevel@tonic-gate 			exit(1);
1208*7c478bd9Sstevel@tonic-gate 		}
1209*7c478bd9Sstevel@tonic-gate 
1210*7c478bd9Sstevel@tonic-gate 		/* -- has been found or argument list is fully processes */
1211*7c478bd9Sstevel@tonic-gate 		if (cflag)
1212*7c478bd9Sstevel@tonic-gate 			continue;
1213*7c478bd9Sstevel@tonic-gate 
1214*7c478bd9Sstevel@tonic-gate 		/*
1215*7c478bd9Sstevel@tonic-gate 		 * if we're doing special processing, and we've got a flag
1216*7c478bd9Sstevel@tonic-gate 		 */
1217*7c478bd9Sstevel@tonic-gate 		else if ((av[i][0] == '-') && (av[i][1] != NULL)) {
1218*7c478bd9Sstevel@tonic-gate 			char	*def;
1219*7c478bd9Sstevel@tonic-gate 
1220*7c478bd9Sstevel@tonic-gate 			switch (av[i][1]) {
1221*7c478bd9Sstevel@tonic-gate 			case	'e':
1222*7c478bd9Sstevel@tonic-gate 				def = ""; /* -e with no arg turns off eof */
1223*7c478bd9Sstevel@tonic-gate 				goto process_special;
1224*7c478bd9Sstevel@tonic-gate 			case	'i':
1225*7c478bd9Sstevel@tonic-gate 				def = INSPAT_STR;
1226*7c478bd9Sstevel@tonic-gate 				goto process_special;
1227*7c478bd9Sstevel@tonic-gate 			case	'l':
1228*7c478bd9Sstevel@tonic-gate 				def = "1";
1229*7c478bd9Sstevel@tonic-gate process_special:
1230*7c478bd9Sstevel@tonic-gate 				/*
1231*7c478bd9Sstevel@tonic-gate 				 * if there's no sub-option, we *must* add
1232*7c478bd9Sstevel@tonic-gate 				 * a default one. this is because xargs must
1233*7c478bd9Sstevel@tonic-gate 				 * be able to distinguish between a valid
1234*7c478bd9Sstevel@tonic-gate 				 * suboption, and a command name.
1235*7c478bd9Sstevel@tonic-gate 				 */
1236*7c478bd9Sstevel@tonic-gate 				if (av[i][2] == NULL) {
1237*7c478bd9Sstevel@tonic-gate 					mav[++mac] = strdup(def);
1238*7c478bd9Sstevel@tonic-gate 				} else {
1239*7c478bd9Sstevel@tonic-gate 					/* clear out our version: */
1240*7c478bd9Sstevel@tonic-gate 					mav[mac][2] = NULL;
1241*7c478bd9Sstevel@tonic-gate 					mav[++mac] = strdup(&av[i][2]);
1242*7c478bd9Sstevel@tonic-gate 				}
1243*7c478bd9Sstevel@tonic-gate 				if (mav[mac] == NULL) {
1244*7c478bd9Sstevel@tonic-gate 					perror(gettext("xargs: Memory"
1245*7c478bd9Sstevel@tonic-gate 					    " allocation failure"));
1246*7c478bd9Sstevel@tonic-gate 					exit(1);
1247*7c478bd9Sstevel@tonic-gate 				}
1248*7c478bd9Sstevel@tonic-gate 				break;
1249*7c478bd9Sstevel@tonic-gate 
1250*7c478bd9Sstevel@tonic-gate 			/* flags with required subarguments:		*/
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 			/*
1253*7c478bd9Sstevel@tonic-gate 			 * there are two separate cases here. either the
1254*7c478bd9Sstevel@tonic-gate 			 * flag can have the normal XCU4 handling
1255*7c478bd9Sstevel@tonic-gate 			 * (of the form: -X subargument); or it can have
1256*7c478bd9Sstevel@tonic-gate 			 * the old solaris 2.[0-4] handling (of the
1257*7c478bd9Sstevel@tonic-gate 			 * form: -Xsubargument). in order to maintain
1258*7c478bd9Sstevel@tonic-gate 			 * backwards compatibility, we must support the
1259*7c478bd9Sstevel@tonic-gate 			 * latter case. we handle the latter possibility
1260*7c478bd9Sstevel@tonic-gate 			 * first so both the old solaris way of handling
1261*7c478bd9Sstevel@tonic-gate 			 * and the new XCU4 way of handling things are allowed.
1262*7c478bd9Sstevel@tonic-gate 			 */
1263*7c478bd9Sstevel@tonic-gate 			case	'n':	/* FALLTHROUGH			*/
1264*7c478bd9Sstevel@tonic-gate 			case	's':	/* FALLTHROUGH			*/
1265*7c478bd9Sstevel@tonic-gate 			case	'E':	/* FALLTHROUGH			*/
1266*7c478bd9Sstevel@tonic-gate 			case	'I':	/* FALLTHROUGH			*/
1267*7c478bd9Sstevel@tonic-gate 			case	'L':
1268*7c478bd9Sstevel@tonic-gate 				/*
1269*7c478bd9Sstevel@tonic-gate 				 * if the second character isn't null, then
1270*7c478bd9Sstevel@tonic-gate 				 * the user has specified the old syntax.
1271*7c478bd9Sstevel@tonic-gate 				 * we move the subargument into our
1272*7c478bd9Sstevel@tonic-gate 				 * mod'd argument list.
1273*7c478bd9Sstevel@tonic-gate 				 */
1274*7c478bd9Sstevel@tonic-gate 				if (av[i][2] != NULL) {
1275*7c478bd9Sstevel@tonic-gate 					/* first clean things up:	*/
1276*7c478bd9Sstevel@tonic-gate 					mav[mac][2] = NULL;
1277*7c478bd9Sstevel@tonic-gate 
1278*7c478bd9Sstevel@tonic-gate 					/* now add the separation:	*/
1279*7c478bd9Sstevel@tonic-gate 					++mac;	/* inc to next mod'd arg */
1280*7c478bd9Sstevel@tonic-gate 					if ((mav[mac] = strdup(&av[i][2])) ==
1281*7c478bd9Sstevel@tonic-gate 					    NULL) {
1282*7c478bd9Sstevel@tonic-gate 						perror(gettext("xargs: Memory"
1283*7c478bd9Sstevel@tonic-gate 						    " allocation failure"));
1284*7c478bd9Sstevel@tonic-gate 						exit(1);
1285*7c478bd9Sstevel@tonic-gate 					}
1286*7c478bd9Sstevel@tonic-gate 					break;
1287*7c478bd9Sstevel@tonic-gate 				}
1288*7c478bd9Sstevel@tonic-gate 				i++;
1289*7c478bd9Sstevel@tonic-gate 				mac++;
1290*7c478bd9Sstevel@tonic-gate #ifdef XPG6
1291*7c478bd9Sstevel@tonic-gate 				if (av[i] != NULL) {
1292*7c478bd9Sstevel@tonic-gate 					if ((mav[mac] = strdup(av[i]))
1293*7c478bd9Sstevel@tonic-gate 						== NULL) {
1294*7c478bd9Sstevel@tonic-gate 						perror(gettext("xargs: Memory"
1295*7c478bd9Sstevel@tonic-gate 						    " allocation failure"));
1296*7c478bd9Sstevel@tonic-gate 						exit(1);
1297*7c478bd9Sstevel@tonic-gate 					}
1298*7c478bd9Sstevel@tonic-gate 				}
1299*7c478bd9Sstevel@tonic-gate #else
1300*7c478bd9Sstevel@tonic-gate 				if (av[i] == NULL) {
1301*7c478bd9Sstevel@tonic-gate 					if ((mav[mac++] = strdup("")) == NULL) {
1302*7c478bd9Sstevel@tonic-gate 						perror(gettext("xargs: Memory "
1303*7c478bd9Sstevel@tonic-gate 						    " allocation failure"));
1304*7c478bd9Sstevel@tonic-gate 						exit(1);
1305*7c478bd9Sstevel@tonic-gate 					}
1306*7c478bd9Sstevel@tonic-gate 					mav[mac] = NULL;
1307*7c478bd9Sstevel@tonic-gate 					return;
1308*7c478bd9Sstevel@tonic-gate 				}
1309*7c478bd9Sstevel@tonic-gate 				if ((mav[mac] = strdup(av[i])) == NULL) {
1310*7c478bd9Sstevel@tonic-gate 					perror(gettext("xargs: Memory"
1311*7c478bd9Sstevel@tonic-gate 						" allocation failure"));
1312*7c478bd9Sstevel@tonic-gate 					exit(1);
1313*7c478bd9Sstevel@tonic-gate 				}
1314*7c478bd9Sstevel@tonic-gate 
1315*7c478bd9Sstevel@tonic-gate #endif
1316*7c478bd9Sstevel@tonic-gate 				break;
1317*7c478bd9Sstevel@tonic-gate 
1318*7c478bd9Sstevel@tonic-gate 			/* flags */
1319*7c478bd9Sstevel@tonic-gate 			case 'p' :
1320*7c478bd9Sstevel@tonic-gate 			case 't' :
1321*7c478bd9Sstevel@tonic-gate 			case 'x' :
1322*7c478bd9Sstevel@tonic-gate 				break;
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 			case '-' :
1325*7c478bd9Sstevel@tonic-gate 			default:
1326*7c478bd9Sstevel@tonic-gate 				/*
1327*7c478bd9Sstevel@tonic-gate 				 * here we've hit the cmd argument. so
1328*7c478bd9Sstevel@tonic-gate 				 * we'll stop special processing, as the
1329*7c478bd9Sstevel@tonic-gate 				 * cmd may have a "-i" etc., argument,
1330*7c478bd9Sstevel@tonic-gate 				 * and we don't want to add a "" to it.
1331*7c478bd9Sstevel@tonic-gate 				 */
1332*7c478bd9Sstevel@tonic-gate 				cflag = 1;
1333*7c478bd9Sstevel@tonic-gate 				break;
1334*7c478bd9Sstevel@tonic-gate 			}
1335*7c478bd9Sstevel@tonic-gate 		} else if (i > 0) {	/* if we're not the 1st arg	*/
1336*7c478bd9Sstevel@tonic-gate 			/*
1337*7c478bd9Sstevel@tonic-gate 			 * if it's not a flag, then it *must* be the cmd.
1338*7c478bd9Sstevel@tonic-gate 			 * set cflag, so we don't mishandle the -[eil] flags.
1339*7c478bd9Sstevel@tonic-gate 			 */
1340*7c478bd9Sstevel@tonic-gate 			cflag = 1;
1341*7c478bd9Sstevel@tonic-gate 		}
1342*7c478bd9Sstevel@tonic-gate 	}
1343*7c478bd9Sstevel@tonic-gate 
1344*7c478bd9Sstevel@tonic-gate 	mav[mac] = NULL;
1345*7c478bd9Sstevel@tonic-gate }
1346*7c478bd9Sstevel@tonic-gate 
1347*7c478bd9Sstevel@tonic-gate 
1348*7c478bd9Sstevel@tonic-gate /*
1349*7c478bd9Sstevel@tonic-gate  * saveinput(): pick up any pending input, so it can be processed later.
1350*7c478bd9Sstevel@tonic-gate  *
1351*7c478bd9Sstevel@tonic-gate  * description:
1352*7c478bd9Sstevel@tonic-gate  *	the purpose of this routine is to allow us to handle the user
1353*7c478bd9Sstevel@tonic-gate  *	typing in a 'y' or 'n', when there's existing characters already
1354*7c478bd9Sstevel@tonic-gate  *	in stdin. this happens when one gives the "-n" option along with
1355*7c478bd9Sstevel@tonic-gate  *	"-p". the problem occurs when the user first types in more arguments
1356*7c478bd9Sstevel@tonic-gate  *	than specified by the -n number. echoargs() wants to read stdin
1357*7c478bd9Sstevel@tonic-gate  *	in order to get the user's response, but if there's already stuff
1358*7c478bd9Sstevel@tonic-gate  *	there, echoargs() won't read the proper character.
1359*7c478bd9Sstevel@tonic-gate  *
1360*7c478bd9Sstevel@tonic-gate  *	the solution provided by this routine is to pick up all characters
1361*7c478bd9Sstevel@tonic-gate  *	(if any), and store them for later processing.
1362*7c478bd9Sstevel@tonic-gate  */
1363*7c478bd9Sstevel@tonic-gate 
1364*7c478bd9Sstevel@tonic-gate void
1365*7c478bd9Sstevel@tonic-gate saveinput()
1366*7c478bd9Sstevel@tonic-gate {
1367*7c478bd9Sstevel@tonic-gate 	char *buffer;		/* ptr to the floating data buffer	*/
1368*7c478bd9Sstevel@tonic-gate 	struct strpeek speek;	/* to see what's on the queue		*/
1369*7c478bd9Sstevel@tonic-gate 	struct strpeek *ps;
1370*7c478bd9Sstevel@tonic-gate 
1371*7c478bd9Sstevel@tonic-gate 	/* if we're not in -p mode, skip				*/
1372*7c478bd9Sstevel@tonic-gate 	if (PROMPT == -1) {
1373*7c478bd9Sstevel@tonic-gate 		return;
1374*7c478bd9Sstevel@tonic-gate 	}
1375*7c478bd9Sstevel@tonic-gate 
1376*7c478bd9Sstevel@tonic-gate 
1377*7c478bd9Sstevel@tonic-gate 	/* now see if there's any activity pending:			*/
1378*7c478bd9Sstevel@tonic-gate 	ps = &speek;
1379*7c478bd9Sstevel@tonic-gate 	ps->ctlbuf.maxlen = 0;
1380*7c478bd9Sstevel@tonic-gate 	ps->ctlbuf.len = 0;
1381*7c478bd9Sstevel@tonic-gate 	ps->ctlbuf.buf = NULL;
1382*7c478bd9Sstevel@tonic-gate 	ps->flags = 0;
1383*7c478bd9Sstevel@tonic-gate 	ps->databuf.maxlen = MAX_INPUT;
1384*7c478bd9Sstevel@tonic-gate 	ps->databuf.len = 0;
1385*7c478bd9Sstevel@tonic-gate 	if ((buffer = malloc((size_t)MAX_INPUT)) == NULL) {
1386*7c478bd9Sstevel@tonic-gate 		perror(gettext("xargs: Memory allocation failure"));
1387*7c478bd9Sstevel@tonic-gate 		exit(1);
1388*7c478bd9Sstevel@tonic-gate 	}
1389*7c478bd9Sstevel@tonic-gate 	ps->databuf.buf = (char *)buffer;
1390*7c478bd9Sstevel@tonic-gate 
1391*7c478bd9Sstevel@tonic-gate 	if (ioctl(PROMPT, I_PEEK, ps) == -1) {
1392*7c478bd9Sstevel@tonic-gate 		perror(gettext("xargs: I_PEEK failure"));
1393*7c478bd9Sstevel@tonic-gate 		exit(1);
1394*7c478bd9Sstevel@tonic-gate 	}
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate 	if (ps->databuf.len > 0) {
1397*7c478bd9Sstevel@tonic-gate 		int	len;
1398*7c478bd9Sstevel@tonic-gate 
1399*7c478bd9Sstevel@tonic-gate 		if ((len = read(PROMPT, buffer, ps->databuf.len)) == -1) {
1400*7c478bd9Sstevel@tonic-gate 			perror(gettext("xargs: read failure"));
1401*7c478bd9Sstevel@tonic-gate 			exit(1);
1402*7c478bd9Sstevel@tonic-gate 		}
1403*7c478bd9Sstevel@tonic-gate 		queue(buffer, len, TAIL);
1404*7c478bd9Sstevel@tonic-gate 	}
1405*7c478bd9Sstevel@tonic-gate }
1406