xref: /illumos-gate/usr/src/contrib/ast/src/lib/libcmd/paste.c (revision b30d193948be5a7794d7ae3ba0ed9c2f72c88e0f)
1*b30d1939SAndy Fiddaman /***********************************************************************
2*b30d1939SAndy Fiddaman *                                                                      *
3*b30d1939SAndy Fiddaman *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1992-2012 AT&T Intellectual Property          *
5*b30d1939SAndy Fiddaman *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
7*b30d1939SAndy Fiddaman *                    by AT&T Intellectual Property                     *
8*b30d1939SAndy Fiddaman *                                                                      *
9*b30d1939SAndy Fiddaman *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*b30d1939SAndy Fiddaman *                                                                      *
13*b30d1939SAndy Fiddaman *              Information and Software Systems Research               *
14*b30d1939SAndy Fiddaman *                            AT&T Research                             *
15*b30d1939SAndy Fiddaman *                           Florham Park NJ                            *
16*b30d1939SAndy Fiddaman *                                                                      *
17*b30d1939SAndy Fiddaman *                 Glenn Fowler <gsf@research.att.com>                  *
18*b30d1939SAndy Fiddaman *                  David Korn <dgk@research.att.com>                   *
19*b30d1939SAndy Fiddaman *                                                                      *
20*b30d1939SAndy Fiddaman ***********************************************************************/
21*b30d1939SAndy Fiddaman #pragma prototyped
22*b30d1939SAndy Fiddaman /*
23*b30d1939SAndy Fiddaman  * David Korn
24*b30d1939SAndy Fiddaman  * AT&T Bell Laboratories
25*b30d1939SAndy Fiddaman  *
26*b30d1939SAndy Fiddaman  * paste [-s] [-d delim] [file] ...
27*b30d1939SAndy Fiddaman  *
28*b30d1939SAndy Fiddaman  * paste lines from files together
29*b30d1939SAndy Fiddaman  */
30*b30d1939SAndy Fiddaman 
31*b30d1939SAndy Fiddaman static const char usage[] =
32*b30d1939SAndy Fiddaman "[-?\n@(#)$Id: paste (AT&T Research) 2010-06-12 $\n]"
33*b30d1939SAndy Fiddaman USAGE_LICENSE
34*b30d1939SAndy Fiddaman "[+NAME?paste - merge lines of files]"
35*b30d1939SAndy Fiddaman "[+DESCRIPTION?\bpaste\b concatenates the corresponding lines of a "
36*b30d1939SAndy Fiddaman 	"given input file and writes the resulting lines to standard "
37*b30d1939SAndy Fiddaman 	"output.  By default \bpaste\b replaces the newline character of "
38*b30d1939SAndy Fiddaman 	"every line other than the last input file with the TAB character.]"
39*b30d1939SAndy Fiddaman "[+?Unless the \b-s\b option is specified, if an end-of-file is encountered "
40*b30d1939SAndy Fiddaman 	"on one or more input files, but not all input files, \bpaste\b "
41*b30d1939SAndy Fiddaman 	"behaves as if empty lines were read from the file(s) on which "
42*b30d1939SAndy Fiddaman 	"end-of-file was detected.]"
43*b30d1939SAndy Fiddaman "[+?Unless the \b-s\b option is specified, \bpaste\b is limited by "
44*b30d1939SAndy Fiddaman 	"the underlying operating system on how many \afile\a operands "
45*b30d1939SAndy Fiddaman 	"can be specified.]"
46*b30d1939SAndy Fiddaman "[+?If no \afile\a operands are given or if the \afile\a is \b-\b, \bpaste\b "
47*b30d1939SAndy Fiddaman 	"reads from standard input. The start of the file is defined as the "
48*b30d1939SAndy Fiddaman 	"current offset.]"
49*b30d1939SAndy Fiddaman 
50*b30d1939SAndy Fiddaman "[s:serial?Paste the lines of one file at a time rather than one line "
51*b30d1939SAndy Fiddaman 	"from each file.  In this case if the \b-d\b option is "
52*b30d1939SAndy Fiddaman 	"specified the delimiter will be reset to the first in the "
53*b30d1939SAndy Fiddaman 	"list at the beginning of each file.]"
54*b30d1939SAndy Fiddaman "[d:delimiters]:[list?\alist\a specifies a list of delimiters.  These "
55*b30d1939SAndy Fiddaman 	"delimiters are used circularly instead of TAB to replace "
56*b30d1939SAndy Fiddaman 	"the newline character of the input lines. Unless the \b-s\b "
57*b30d1939SAndy Fiddaman 	"option is specified, the delimiter will be reset to the first "
58*b30d1939SAndy Fiddaman 	"element of \alist\a each time a line is processed from each file.  "
59*b30d1939SAndy Fiddaman 	"The delimiter characters corresponding to \alist\a will be found "
60*b30d1939SAndy Fiddaman 	"by treating \alist\a as an ANSI-C string, except that the \b\\0\b "
61*b30d1939SAndy Fiddaman 	"sequence will insert the empty string instead of the null character.]"
62*b30d1939SAndy Fiddaman "\n"
63*b30d1939SAndy Fiddaman "\n[file ...]\n"
64*b30d1939SAndy Fiddaman "\n"
65*b30d1939SAndy Fiddaman "[+EXIT STATUS?]{"
66*b30d1939SAndy Fiddaman 	"[+0?All files processed successfully.]"
67*b30d1939SAndy Fiddaman 	"[+>0?An error occurred.]"
68*b30d1939SAndy Fiddaman "}"
69*b30d1939SAndy Fiddaman "[+SEE ALSO?\bcut\b(1), \bcat\b(1), \bjoin\b(1)]"
70*b30d1939SAndy Fiddaman ;
71*b30d1939SAndy Fiddaman 
72*b30d1939SAndy Fiddaman #include <cmd.h>
73*b30d1939SAndy Fiddaman 
74*b30d1939SAndy Fiddaman typedef struct Delim_s
75*b30d1939SAndy Fiddaman {
76*b30d1939SAndy Fiddaman 	const char*	chr;
77*b30d1939SAndy Fiddaman 	size_t		len;
78*b30d1939SAndy Fiddaman } Delim_t;
79*b30d1939SAndy Fiddaman 
80*b30d1939SAndy Fiddaman /*
81*b30d1939SAndy Fiddaman  * paste the lines of the <nstreams> defined in <streams> and put results
82*b30d1939SAndy Fiddaman  * to <out>
83*b30d1939SAndy Fiddaman  */
84*b30d1939SAndy Fiddaman 
paste(int nstream,Sfio_t * streams[],Sfio_t * out,register const char * delim,int dsiz,int dlen,Delim_t * mp)85*b30d1939SAndy Fiddaman static int paste(int nstream,Sfio_t* streams[],Sfio_t *out, register const char *delim, int dsiz, int dlen, Delim_t* mp)
86*b30d1939SAndy Fiddaman {
87*b30d1939SAndy Fiddaman 	register const char *cp;
88*b30d1939SAndy Fiddaman 	register int d, n, i, z, more=1;
89*b30d1939SAndy Fiddaman 	register Sfio_t *fp;
90*b30d1939SAndy Fiddaman 	do
91*b30d1939SAndy Fiddaman 	{
92*b30d1939SAndy Fiddaman 		d = (dlen>0?0:-1);
93*b30d1939SAndy Fiddaman 		for(n=more-1,more=0; n < nstream;)
94*b30d1939SAndy Fiddaman 		{
95*b30d1939SAndy Fiddaman 			if(fp=streams[n])
96*b30d1939SAndy Fiddaman 			{
97*b30d1939SAndy Fiddaman 				if(cp = sfgetr(fp,'\n',0))
98*b30d1939SAndy Fiddaman 				{
99*b30d1939SAndy Fiddaman 					if(n==0)
100*b30d1939SAndy Fiddaman 						more = 1;
101*b30d1939SAndy Fiddaman 					else if(!more) /* first stream with output */
102*b30d1939SAndy Fiddaman 					{
103*b30d1939SAndy Fiddaman 						if(dsiz == 1)
104*b30d1939SAndy Fiddaman 							sfnputc(out, *delim, n);
105*b30d1939SAndy Fiddaman 						else if(dlen>0)
106*b30d1939SAndy Fiddaman 						{
107*b30d1939SAndy Fiddaman 							for(d=n; d>dlen; d-=dlen)
108*b30d1939SAndy Fiddaman 								sfwrite(out,delim,dsiz);
109*b30d1939SAndy Fiddaman 							if(d)
110*b30d1939SAndy Fiddaman 							{
111*b30d1939SAndy Fiddaman 								if(mp)
112*b30d1939SAndy Fiddaman 									for (i = z = 0; i < d; i++)
113*b30d1939SAndy Fiddaman 										z += mp[i].len;
114*b30d1939SAndy Fiddaman 								else
115*b30d1939SAndy Fiddaman 									z = d;
116*b30d1939SAndy Fiddaman 								sfwrite(out,delim,z);
117*b30d1939SAndy Fiddaman 							}
118*b30d1939SAndy Fiddaman 						}
119*b30d1939SAndy Fiddaman 						more = n+1;
120*b30d1939SAndy Fiddaman 					}
121*b30d1939SAndy Fiddaman 					if(sfwrite(out,cp,sfvalue(fp)-((n+1)<nstream)) < 0)
122*b30d1939SAndy Fiddaman 						return(-1);
123*b30d1939SAndy Fiddaman 				}
124*b30d1939SAndy Fiddaman 				else
125*b30d1939SAndy Fiddaman 					streams[n] = 0;
126*b30d1939SAndy Fiddaman 			}
127*b30d1939SAndy Fiddaman 			if(++n<nstream && more && d>=0)
128*b30d1939SAndy Fiddaman 			{
129*b30d1939SAndy Fiddaman 				register int c;
130*b30d1939SAndy Fiddaman 				if(d >= dlen)
131*b30d1939SAndy Fiddaman 					d = 0;
132*b30d1939SAndy Fiddaman 				if(mp)
133*b30d1939SAndy Fiddaman 					sfwrite(out,mp[d].chr,mp[d].len);
134*b30d1939SAndy Fiddaman 				else if(c=delim[d])
135*b30d1939SAndy Fiddaman 					sfputc(out,c);
136*b30d1939SAndy Fiddaman 				d++;
137*b30d1939SAndy Fiddaman 			}
138*b30d1939SAndy Fiddaman 			else if(n==nstream && !streams[n-1] && more)
139*b30d1939SAndy Fiddaman 				sfputc(out,'\n');
140*b30d1939SAndy Fiddaman 		}
141*b30d1939SAndy Fiddaman 	} while(more);
142*b30d1939SAndy Fiddaman 	return(0);
143*b30d1939SAndy Fiddaman }
144*b30d1939SAndy Fiddaman 
145*b30d1939SAndy Fiddaman /*
146*b30d1939SAndy Fiddaman  * Handles paste -s, for file <in> to file <out> using delimiters <delim>
147*b30d1939SAndy Fiddaman  */
spaste(Sfio_t * in,register Sfio_t * out,register const char * delim,int dsiz,int dlen,Delim_t * mp)148*b30d1939SAndy Fiddaman static int spaste(Sfio_t *in,register Sfio_t* out,register const char *delim,int dsiz,int dlen,Delim_t* mp)
149*b30d1939SAndy Fiddaman {
150*b30d1939SAndy Fiddaman 	register const char *cp;
151*b30d1939SAndy Fiddaman 	register int d=0;
152*b30d1939SAndy Fiddaman 	if((cp = sfgetr(in,'\n',0)) && sfwrite(out,cp,sfvalue(in)-1) < 0)
153*b30d1939SAndy Fiddaman 		return(-1);
154*b30d1939SAndy Fiddaman 	while(cp=sfgetr(in, '\n',0))
155*b30d1939SAndy Fiddaman 	{
156*b30d1939SAndy Fiddaman 		if(dlen)
157*b30d1939SAndy Fiddaman 		{
158*b30d1939SAndy Fiddaman 			register int c;
159*b30d1939SAndy Fiddaman 			if(d >= dlen)
160*b30d1939SAndy Fiddaman 				d = 0;
161*b30d1939SAndy Fiddaman 			if(mp)
162*b30d1939SAndy Fiddaman 				sfwrite(out,mp[d].chr,mp[d].len);
163*b30d1939SAndy Fiddaman 			else if(c=delim[d])
164*b30d1939SAndy Fiddaman 				sfputc(out,c);
165*b30d1939SAndy Fiddaman 			d++;
166*b30d1939SAndy Fiddaman 		}
167*b30d1939SAndy Fiddaman 		if(sfwrite(out,cp,sfvalue(in)-1) < 0)
168*b30d1939SAndy Fiddaman 			return(-1);
169*b30d1939SAndy Fiddaman 	}
170*b30d1939SAndy Fiddaman 	sfputc(out,'\n');
171*b30d1939SAndy Fiddaman 	return(0);
172*b30d1939SAndy Fiddaman }
173*b30d1939SAndy Fiddaman 
174*b30d1939SAndy Fiddaman int
b_paste(int argc,char ** argv,Shbltin_t * context)175*b30d1939SAndy Fiddaman b_paste(int argc, char** argv, Shbltin_t* context)
176*b30d1939SAndy Fiddaman {
177*b30d1939SAndy Fiddaman 	register int		n, sflag=0;
178*b30d1939SAndy Fiddaman 	register Sfio_t		*fp, **streams;
179*b30d1939SAndy Fiddaman 	register char 		*cp, *delim;
180*b30d1939SAndy Fiddaman 	char			*ep;
181*b30d1939SAndy Fiddaman 	Delim_t			*mp;
182*b30d1939SAndy Fiddaman 	int			dlen, dsiz;
183*b30d1939SAndy Fiddaman 	char			defdelim[2];
184*b30d1939SAndy Fiddaman 
185*b30d1939SAndy Fiddaman 	cmdinit(argc, argv, context, ERROR_CATALOG, 0);
186*b30d1939SAndy Fiddaman 	delim = 0;
187*b30d1939SAndy Fiddaman 	for (;;)
188*b30d1939SAndy Fiddaman 	{
189*b30d1939SAndy Fiddaman 		switch (optget(argv, usage))
190*b30d1939SAndy Fiddaman 		{
191*b30d1939SAndy Fiddaman 		case 'd':
192*b30d1939SAndy Fiddaman 			delim = opt_info.arg;
193*b30d1939SAndy Fiddaman 			continue;
194*b30d1939SAndy Fiddaman 		case 's':
195*b30d1939SAndy Fiddaman 			sflag++;
196*b30d1939SAndy Fiddaman 			continue;
197*b30d1939SAndy Fiddaman 		case ':':
198*b30d1939SAndy Fiddaman 			error(2, "%s", opt_info.arg);
199*b30d1939SAndy Fiddaman 			break;
200*b30d1939SAndy Fiddaman 		case '?':
201*b30d1939SAndy Fiddaman 			error(ERROR_usage(2), "%s", opt_info.arg);
202*b30d1939SAndy Fiddaman 			break;
203*b30d1939SAndy Fiddaman 		}
204*b30d1939SAndy Fiddaman 		break;
205*b30d1939SAndy Fiddaman 	}
206*b30d1939SAndy Fiddaman 	argv += opt_info.index;
207*b30d1939SAndy Fiddaman 	if(error_info.errors)
208*b30d1939SAndy Fiddaman 		error(ERROR_usage(2),"%s", optusage(NiL));
209*b30d1939SAndy Fiddaman 	if(!delim || !*delim)
210*b30d1939SAndy Fiddaman 	{
211*b30d1939SAndy Fiddaman 		delim = defdelim;
212*b30d1939SAndy Fiddaman 		delim[0] = '\t';
213*b30d1939SAndy Fiddaman 		delim[1] = 0;
214*b30d1939SAndy Fiddaman 	}
215*b30d1939SAndy Fiddaman 	if (!(delim = strdup(delim)))
216*b30d1939SAndy Fiddaman 		error(ERROR_system(1), "out of space");
217*b30d1939SAndy Fiddaman 	dlen = dsiz = stresc(delim);
218*b30d1939SAndy Fiddaman 	mp = 0;
219*b30d1939SAndy Fiddaman 	if (mbwide())
220*b30d1939SAndy Fiddaman 	{
221*b30d1939SAndy Fiddaman 		cp = delim;
222*b30d1939SAndy Fiddaman 		ep = delim + dlen;
223*b30d1939SAndy Fiddaman 		dlen = 0;
224*b30d1939SAndy Fiddaman 		while (cp < ep)
225*b30d1939SAndy Fiddaman 		{
226*b30d1939SAndy Fiddaman 			mbchar(cp);
227*b30d1939SAndy Fiddaman 			dlen++;
228*b30d1939SAndy Fiddaman 		}
229*b30d1939SAndy Fiddaman 		if(dlen < dsiz)
230*b30d1939SAndy Fiddaman 		{
231*b30d1939SAndy Fiddaman 			if (!(mp = newof(0, Delim_t, dlen, 0)))
232*b30d1939SAndy Fiddaman 			{
233*b30d1939SAndy Fiddaman 				free(delim);
234*b30d1939SAndy Fiddaman 				error(ERROR_system(1), "out of space");
235*b30d1939SAndy Fiddaman 			}
236*b30d1939SAndy Fiddaman 			cp = delim;
237*b30d1939SAndy Fiddaman 			dlen = 0;
238*b30d1939SAndy Fiddaman 			while (cp < ep)
239*b30d1939SAndy Fiddaman 			{
240*b30d1939SAndy Fiddaman 				mp[dlen].chr = cp;
241*b30d1939SAndy Fiddaman 				mbchar(cp);
242*b30d1939SAndy Fiddaman 				mp[dlen].len = cp - mp[dlen].chr;
243*b30d1939SAndy Fiddaman 				dlen++;
244*b30d1939SAndy Fiddaman 			}
245*b30d1939SAndy Fiddaman 		}
246*b30d1939SAndy Fiddaman 	}
247*b30d1939SAndy Fiddaman 	if(cp = *argv)
248*b30d1939SAndy Fiddaman 	{
249*b30d1939SAndy Fiddaman 		n = argc - opt_info.index;
250*b30d1939SAndy Fiddaman 		argv++;
251*b30d1939SAndy Fiddaman 	}
252*b30d1939SAndy Fiddaman 	else
253*b30d1939SAndy Fiddaman 		n = 1;
254*b30d1939SAndy Fiddaman 	if(!sflag)
255*b30d1939SAndy Fiddaman 	{
256*b30d1939SAndy Fiddaman 		if (!(streams = (Sfio_t**)stakalloc(n*sizeof(Sfio_t*))))
257*b30d1939SAndy Fiddaman 			error(ERROR_exit(1), "out of space");
258*b30d1939SAndy Fiddaman 		n = 0;
259*b30d1939SAndy Fiddaman 	}
260*b30d1939SAndy Fiddaman 	do
261*b30d1939SAndy Fiddaman 	{
262*b30d1939SAndy Fiddaman 		if(!cp || streq(cp,"-"))
263*b30d1939SAndy Fiddaman 			fp = sfstdin;
264*b30d1939SAndy Fiddaman 		else if(!(fp = sfopen(NiL,cp,"r")))
265*b30d1939SAndy Fiddaman 			error(ERROR_system(0),"%s: cannot open",cp);
266*b30d1939SAndy Fiddaman 		if(fp && sflag)
267*b30d1939SAndy Fiddaman 		{
268*b30d1939SAndy Fiddaman 			if(spaste(fp,sfstdout,delim,dsiz,dlen,mp) < 0)
269*b30d1939SAndy Fiddaman 				error(ERROR_system(0),"write failed");
270*b30d1939SAndy Fiddaman 			if(fp!=sfstdin)
271*b30d1939SAndy Fiddaman 				sfclose(fp);
272*b30d1939SAndy Fiddaman 		}
273*b30d1939SAndy Fiddaman 		else if(!sflag)
274*b30d1939SAndy Fiddaman 			streams[n++] = fp;
275*b30d1939SAndy Fiddaman 	} while(cp= *argv++);
276*b30d1939SAndy Fiddaman 	if(!sflag)
277*b30d1939SAndy Fiddaman 	{
278*b30d1939SAndy Fiddaman 		if(error_info.errors==0 && paste(n,streams,sfstdout,delim,dsiz,dlen,mp) < 0)
279*b30d1939SAndy Fiddaman 			error(ERROR_system(0),"write failed");
280*b30d1939SAndy Fiddaman 		while(--n>=0)
281*b30d1939SAndy Fiddaman 			if((fp=streams[n]) && fp!=sfstdin)
282*b30d1939SAndy Fiddaman 				sfclose(fp);
283*b30d1939SAndy Fiddaman 	}
284*b30d1939SAndy Fiddaman 	if (mp)
285*b30d1939SAndy Fiddaman 		free(mp);
286*b30d1939SAndy Fiddaman 	free(delim);
287*b30d1939SAndy Fiddaman 	return(error_info.errors);
288*b30d1939SAndy Fiddaman }
289