xref: /titanic_51/usr/src/lib/libcmd/common/cat.c (revision 34f9b3eef6fdadbda0a846aa4d68691ac40eace5)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*34f9b3eeSRoland Mainz *          Copyright (c) 1992-2009 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                                                                      *
20da2e3ebdSchin ***********************************************************************/
21da2e3ebdSchin #pragma prototyped
22da2e3ebdSchin /*
23da2e3ebdSchin  * David Korn
24da2e3ebdSchin  * Glenn Fowler
25da2e3ebdSchin  * AT&T Bell Laboratories
26da2e3ebdSchin  *
27da2e3ebdSchin  * cat
28da2e3ebdSchin  */
29da2e3ebdSchin 
30da2e3ebdSchin #include <cmd.h>
31da2e3ebdSchin #include <fcntl.h>
32da2e3ebdSchin 
33da2e3ebdSchin static const char usage[] =
34*34f9b3eeSRoland Mainz "[-?\n@(#)$Id: cat (AT&T Research) 2009-03-31 $\n]"
35da2e3ebdSchin USAGE_LICENSE
36da2e3ebdSchin "[+NAME?cat - concatenate files]"
37da2e3ebdSchin "[+DESCRIPTION?\bcat\b copies each \afile\a in sequence to the standard"
38da2e3ebdSchin "	output. If no \afile\a is given, or if the \afile\a is \b-\b,"
39da2e3ebdSchin "	\bcat\b copies from standard input starting at the current location.]"
40da2e3ebdSchin 
41da2e3ebdSchin "[b:number-nonblank?Number lines as with \b-n\b but omit line numbers from"
42da2e3ebdSchin "	blank lines.]"
43da2e3ebdSchin "[d:dos-input?Input files are opened in \atext\amode which removes carriage"
44da2e3ebdSchin "	returns in front of new-lines on some systems.]"
45da2e3ebdSchin "[e?Equivalent to \b-vE\b.]"
46da2e3ebdSchin "[n:number?Causes a line number to be inserted at the beginning of each line.]"
47da2e3ebdSchin "[s?Equivalent to \b-S\b for \aatt\a universe and \b-B\b otherwise.]"
48da2e3ebdSchin "[t?Equivalent to \b-vT\b.]"
49da2e3ebdSchin "[u:unbuffer?The output is not delayed by buffering.]"
50da2e3ebdSchin "[v:show-nonprinting?Causes non-printing characters (whith the exception of"
51da2e3ebdSchin "	tabs, new-lines, and form-feeds) to be output as printable charater"
52da2e3ebdSchin "	sequences. ASCII control characters are printed as \b^\b\an\a,"
53da2e3ebdSchin "	where \an\a is the corresponding ASCII character in the range"
54da2e3ebdSchin "	octal 100-137. The DEL character (octal 0177) is copied"
55da2e3ebdSchin "	as \b^?\b. Other non-printable characters are copied as \bM-\b\ax\a"
56da2e3ebdSchin "	where \ax\a is the ASCII character specified by the low-order seven"
57da2e3ebdSchin "	bits.  Multibyte characters in the current locale are treated as"
58da2e3ebdSchin "	printable characters.]"
59da2e3ebdSchin "[A:show-all?Equivalent to \b-vET\b.]"
60da2e3ebdSchin "[B:squeeze-blank?Multiple adjacent new-line characters are replace by one"
61da2e3ebdSchin "	new-line.]"
62da2e3ebdSchin "[D:dos-output?Output files are opened in \atext\amode which inserts carriage"
63da2e3ebdSchin "	returns in front of new-lines on some systems.]"
64da2e3ebdSchin "[E:show-ends?Causes a \b$\b to be inserted before each new-line.]"
65*34f9b3eeSRoland Mainz "[R:regress?Regression test defaults: \b-v\b buffer size 4.]"
66da2e3ebdSchin "[S:silent?\bcat\b is silent about non-existent files.]"
67da2e3ebdSchin "[T:show-blank?Causes tabs to be copied as \b^I\b and formfeeds as \b^L\b.]"
68da2e3ebdSchin 
69da2e3ebdSchin "\n"
70da2e3ebdSchin "\n[file ...]\n"
71da2e3ebdSchin "\n"
72da2e3ebdSchin 
73da2e3ebdSchin "[+SEE ALSO?\bcp\b(1), \bgetconf\b(1), \bpr\b(1)]"
74da2e3ebdSchin ;
75da2e3ebdSchin 
76da2e3ebdSchin #define RUBOUT	0177
77da2e3ebdSchin 
78da2e3ebdSchin /* control flags */
79da2e3ebdSchin #define B_FLAG		(1<<0)
80da2e3ebdSchin #define E_FLAG		(1<<1)
81da2e3ebdSchin #define F_FLAG		(1<<2)
82da2e3ebdSchin #define N_FLAG		(1<<3)
83da2e3ebdSchin #define S_FLAG		(1<<4)
84da2e3ebdSchin #define T_FLAG		(1<<5)
85da2e3ebdSchin #define U_FLAG		(1<<6)
86da2e3ebdSchin #define V_FLAG		(1<<7)
87da2e3ebdSchin #define D_FLAG		(1<<8)
88da2e3ebdSchin #define d_FLAG		(1<<9)
89da2e3ebdSchin 
90da2e3ebdSchin /* character types */
91*34f9b3eeSRoland Mainz #define T_ERROR		1
92*34f9b3eeSRoland Mainz #define T_EOF		2
93*34f9b3eeSRoland Mainz #define T_ENDBUF	3
94*34f9b3eeSRoland Mainz #define T_NEWLINE	4
95*34f9b3eeSRoland Mainz #define T_CONTROL	5
96*34f9b3eeSRoland Mainz #define T_EIGHTBIT	6
97*34f9b3eeSRoland Mainz #define T_CNTL8BIT	7
98da2e3ebdSchin 
99da2e3ebdSchin #define printof(c)	((c)^0100)
100da2e3ebdSchin 
101*34f9b3eeSRoland Mainz typedef void* (*Reserve_f)(Sfio_t*, ssize_t, int);
102*34f9b3eeSRoland Mainz 
103*34f9b3eeSRoland Mainz #ifndef sfvalue
104*34f9b3eeSRoland Mainz #define sfvalue(f)	((f)->_val)
105*34f9b3eeSRoland Mainz #endif
106*34f9b3eeSRoland Mainz 
107*34f9b3eeSRoland Mainz static void*
108*34f9b3eeSRoland Mainz regress(Sfio_t* sp, ssize_t n, int f)
109*34f9b3eeSRoland Mainz {
110*34f9b3eeSRoland Mainz 	void*	r;
111*34f9b3eeSRoland Mainz 
112*34f9b3eeSRoland Mainz 	if (!(r = sfreserve(sp, 4, f)))
113*34f9b3eeSRoland Mainz 		r = sfreserve(sp, n, f);
114*34f9b3eeSRoland Mainz 	else if (sfvalue(sp) > 4)
115*34f9b3eeSRoland Mainz 		sfvalue(sp) = 4;
116*34f9b3eeSRoland Mainz 	return r;
117*34f9b3eeSRoland Mainz }
118*34f9b3eeSRoland Mainz 
119da2e3ebdSchin /*
120da2e3ebdSchin  * called for any special output processing
121da2e3ebdSchin  */
122da2e3ebdSchin 
123da2e3ebdSchin static int
124*34f9b3eeSRoland Mainz vcat(register char* states, Sfio_t* ip, Sfio_t* op, Reserve_f reserve, int flags)
125da2e3ebdSchin {
126da2e3ebdSchin 	register unsigned char*	cp;
127*34f9b3eeSRoland Mainz 	register unsigned char*	pp;
128*34f9b3eeSRoland Mainz 	unsigned char*		cur;
129*34f9b3eeSRoland Mainz 	unsigned char*		end;
130*34f9b3eeSRoland Mainz 	unsigned char*		buf;
131*34f9b3eeSRoland Mainz 	unsigned char*		nxt;
132da2e3ebdSchin 	register int		n;
133*34f9b3eeSRoland Mainz 	register int		line;
134*34f9b3eeSRoland Mainz 	register int		raw;
135*34f9b3eeSRoland Mainz 	int			last;
136*34f9b3eeSRoland Mainz 	int			c;
137*34f9b3eeSRoland Mainz 	int			m;
138*34f9b3eeSRoland Mainz 	int			any;
139*34f9b3eeSRoland Mainz 	int			header;
140da2e3ebdSchin 
141da2e3ebdSchin 	unsigned char		meta[4];
142*34f9b3eeSRoland Mainz 	unsigned char		tmp[32];
143da2e3ebdSchin 
144da2e3ebdSchin 	meta[0] = 'M';
145da2e3ebdSchin 	meta[1] = '-';
146*34f9b3eeSRoland Mainz 	last = -1;
147*34f9b3eeSRoland Mainz 	*(cp = buf = end = tmp) = 0;
148*34f9b3eeSRoland Mainz 	any = 0;
149*34f9b3eeSRoland Mainz 	header = flags & (B_FLAG|N_FLAG);
150*34f9b3eeSRoland Mainz 	line = 1;
151*34f9b3eeSRoland Mainz 	states[0] = T_ENDBUF;
152*34f9b3eeSRoland Mainz 	raw = !mbwide();
153da2e3ebdSchin 	for (;;)
154da2e3ebdSchin 	{
155*34f9b3eeSRoland Mainz 		cur = cp;
156*34f9b3eeSRoland Mainz 		if (raw)
157*34f9b3eeSRoland Mainz 			while (!(n = states[*cp++]));
158da2e3ebdSchin 		else
159*34f9b3eeSRoland Mainz 			for (;;)
160da2e3ebdSchin 			{
161*34f9b3eeSRoland Mainz 				while (!(n = states[*cp++]));
162*34f9b3eeSRoland Mainz 				if (n < T_CONTROL)
163*34f9b3eeSRoland Mainz 					break;
164*34f9b3eeSRoland Mainz 				if ((m = mbsize(pp = cp - 1)) > 1)
165*34f9b3eeSRoland Mainz 					cp += m - 1;
166*34f9b3eeSRoland Mainz 				else
167da2e3ebdSchin 				{
168*34f9b3eeSRoland Mainz 					if (m <= 0)
169da2e3ebdSchin 					{
170*34f9b3eeSRoland Mainz 						if (cur == pp)
171*34f9b3eeSRoland Mainz 						{
172*34f9b3eeSRoland Mainz 							if (last > 0)
173*34f9b3eeSRoland Mainz 							{
174*34f9b3eeSRoland Mainz 								*end = last;
175*34f9b3eeSRoland Mainz 								last = -1;
176*34f9b3eeSRoland Mainz 								c = end - pp + 1;
177*34f9b3eeSRoland Mainz 								if ((m = mbsize(pp)) == c)
178*34f9b3eeSRoland Mainz 								{
179*34f9b3eeSRoland Mainz 									any = 1;
180*34f9b3eeSRoland Mainz 									if (header)
181*34f9b3eeSRoland Mainz 									{
182*34f9b3eeSRoland Mainz 										header = 0;
183*34f9b3eeSRoland Mainz 										sfprintf(op, "%6d\t", line);
184*34f9b3eeSRoland Mainz 									}
185*34f9b3eeSRoland Mainz 									sfwrite(op, cur, m);
186*34f9b3eeSRoland Mainz 									*(cp = cur = end) = 0;
187da2e3ebdSchin 								}
188da2e3ebdSchin 								else
189da2e3ebdSchin 								{
190*34f9b3eeSRoland Mainz 									memcpy(tmp, pp, c);
191*34f9b3eeSRoland Mainz 									if (!(nxt = (unsigned char*)(*reserve)(ip, SF_UNBOUND, 0)))
192*34f9b3eeSRoland Mainz 									{
193*34f9b3eeSRoland Mainz 										states[0] = sfvalue(ip) ? T_ERROR : T_EOF;
194*34f9b3eeSRoland Mainz 										*(cp = end = tmp + sizeof(tmp) - 1) = 0;
195*34f9b3eeSRoland Mainz 										last = -1;
196da2e3ebdSchin 									}
197*34f9b3eeSRoland Mainz 									else if ((n = sfvalue(ip)) <= 0)
198*34f9b3eeSRoland Mainz 									{
199*34f9b3eeSRoland Mainz 										states[0] = n ? T_ERROR : T_EOF;
200*34f9b3eeSRoland Mainz 										*(cp = end = tmp + sizeof(tmp) - 1) = 0;
201*34f9b3eeSRoland Mainz 										last = -1;
202da2e3ebdSchin 									}
203*34f9b3eeSRoland Mainz 									else
204*34f9b3eeSRoland Mainz 									{
205*34f9b3eeSRoland Mainz 										cp = buf = nxt;
206*34f9b3eeSRoland Mainz 										end = buf + n - 1;
207*34f9b3eeSRoland Mainz 										last = *end;
208*34f9b3eeSRoland Mainz 										*end = 0;
209da2e3ebdSchin 									}
210*34f9b3eeSRoland Mainz  mb:
211*34f9b3eeSRoland Mainz 									if ((n = end - cp + 1) >= (sizeof(tmp) - c))
212*34f9b3eeSRoland Mainz 										n = sizeof(tmp) - c - 1;
213*34f9b3eeSRoland Mainz 									memcpy(tmp + c, cp, n);
214*34f9b3eeSRoland Mainz 									if ((m = mbsize(tmp)) >= c)
215*34f9b3eeSRoland Mainz 									{
216*34f9b3eeSRoland Mainz 										any = 1;
217*34f9b3eeSRoland Mainz 										if (header)
218*34f9b3eeSRoland Mainz 										{
219*34f9b3eeSRoland Mainz 											header = 0;
220*34f9b3eeSRoland Mainz 											sfprintf(op, "%6d\t", line);
221*34f9b3eeSRoland Mainz 										}
222*34f9b3eeSRoland Mainz 										sfwrite(op, tmp, m);
223*34f9b3eeSRoland Mainz 										cur = cp += m - c;
224*34f9b3eeSRoland Mainz 									}
225*34f9b3eeSRoland Mainz 								}
226*34f9b3eeSRoland Mainz 								continue;
227*34f9b3eeSRoland Mainz 							}
228*34f9b3eeSRoland Mainz 						}
229*34f9b3eeSRoland Mainz 						else
230*34f9b3eeSRoland Mainz 						{
231*34f9b3eeSRoland Mainz 							cp = pp + 1;
232*34f9b3eeSRoland Mainz 							n = 0;
233*34f9b3eeSRoland Mainz 						}
234*34f9b3eeSRoland Mainz 					}
235*34f9b3eeSRoland Mainz 					break;
236*34f9b3eeSRoland Mainz 				}
237*34f9b3eeSRoland Mainz 			}
238*34f9b3eeSRoland Mainz 		c = *--cp;
239*34f9b3eeSRoland Mainz 		if ((m = cp - cur) || n >= T_CONTROL)
240*34f9b3eeSRoland Mainz 		{
241*34f9b3eeSRoland Mainz  flush:
242*34f9b3eeSRoland Mainz 			any = 1;
243*34f9b3eeSRoland Mainz 			if (header)
244*34f9b3eeSRoland Mainz 			{
245*34f9b3eeSRoland Mainz 				header = 0;
246*34f9b3eeSRoland Mainz 				sfprintf(op, "%6d\t", line);
247*34f9b3eeSRoland Mainz 			}
248*34f9b3eeSRoland Mainz 			if (m)
249*34f9b3eeSRoland Mainz 				sfwrite(op, cur, m);
250*34f9b3eeSRoland Mainz 		}
251*34f9b3eeSRoland Mainz  special:
252da2e3ebdSchin 		switch (n)
253da2e3ebdSchin 		{
254*34f9b3eeSRoland Mainz 		case T_ERROR:
255*34f9b3eeSRoland Mainz 			if (cp != end)
256da2e3ebdSchin 			{
257*34f9b3eeSRoland Mainz 				n = T_CONTROL;
258*34f9b3eeSRoland Mainz 				goto flush;
259da2e3ebdSchin 			}
260*34f9b3eeSRoland Mainz 			return -1;
261*34f9b3eeSRoland Mainz 		case T_EOF:
262*34f9b3eeSRoland Mainz 			if (cp != end)
263da2e3ebdSchin 			{
264*34f9b3eeSRoland Mainz 				n = T_CONTROL;
265*34f9b3eeSRoland Mainz 				goto flush;
266da2e3ebdSchin 			}
267*34f9b3eeSRoland Mainz 			return 0;
268*34f9b3eeSRoland Mainz 		case T_ENDBUF:
269*34f9b3eeSRoland Mainz 			if (cp != end)
270*34f9b3eeSRoland Mainz 			{
271*34f9b3eeSRoland Mainz 				n = T_CONTROL;
272*34f9b3eeSRoland Mainz 				goto flush;
273*34f9b3eeSRoland Mainz 			}
274*34f9b3eeSRoland Mainz 			c = last;
275*34f9b3eeSRoland Mainz 			if (!(nxt = (unsigned char*)(*reserve)(ip, SF_UNBOUND, 0)))
276*34f9b3eeSRoland Mainz 			{
277*34f9b3eeSRoland Mainz 				*(cp = end = tmp) = 0;
278*34f9b3eeSRoland Mainz 				states[0] = sfvalue(ip) ? T_ERROR : T_EOF;
279*34f9b3eeSRoland Mainz 				last = -1;
280*34f9b3eeSRoland Mainz 			}
281*34f9b3eeSRoland Mainz 			else if ((m = sfvalue(ip)) <= 0)
282*34f9b3eeSRoland Mainz 			{
283*34f9b3eeSRoland Mainz 				*(cp = end = tmp) = 0;
284*34f9b3eeSRoland Mainz 				states[0] = m ? T_ERROR : T_EOF;
285*34f9b3eeSRoland Mainz 				last = -1;
286*34f9b3eeSRoland Mainz 			}
287*34f9b3eeSRoland Mainz 			else
288*34f9b3eeSRoland Mainz 			{
289*34f9b3eeSRoland Mainz 				buf = nxt;
290*34f9b3eeSRoland Mainz 				end = buf + m - 1;
291*34f9b3eeSRoland Mainz 				last = *end;
292*34f9b3eeSRoland Mainz 				*end = 0;
293*34f9b3eeSRoland Mainz 				cp = buf;
294*34f9b3eeSRoland Mainz 			}
295*34f9b3eeSRoland Mainz 			if (c >= 0)
296*34f9b3eeSRoland Mainz 			{
297*34f9b3eeSRoland Mainz 				if (!(n = states[c]))
298*34f9b3eeSRoland Mainz 				{
299*34f9b3eeSRoland Mainz 					*(cur = tmp) = c;
300*34f9b3eeSRoland Mainz 					m = 1;
301*34f9b3eeSRoland Mainz 					goto flush;
302*34f9b3eeSRoland Mainz 				}
303*34f9b3eeSRoland Mainz 				if (raw || n < T_CONTROL)
304*34f9b3eeSRoland Mainz 				{
305*34f9b3eeSRoland Mainz 					cp--;
306*34f9b3eeSRoland Mainz 					goto special;
307*34f9b3eeSRoland Mainz 				}
308*34f9b3eeSRoland Mainz 				tmp[0] = c;
309*34f9b3eeSRoland Mainz 				c = 1;
310*34f9b3eeSRoland Mainz 				goto mb;
311*34f9b3eeSRoland Mainz 			}
312da2e3ebdSchin 			break;
313da2e3ebdSchin 		case T_CONTROL:
314da2e3ebdSchin 			do
315da2e3ebdSchin 			{
316*34f9b3eeSRoland Mainz 				sfputc(op, '^');
317*34f9b3eeSRoland Mainz 				sfputc(op, printof(c));
318*34f9b3eeSRoland Mainz 			} while (states[c = *++cp] == T_CONTROL);
319da2e3ebdSchin 			break;
320*34f9b3eeSRoland Mainz 		case T_CNTL8BIT:
321*34f9b3eeSRoland Mainz 			meta[2] = '^';
322da2e3ebdSchin 			do
323da2e3ebdSchin 			{
324*34f9b3eeSRoland Mainz 				n = c & ~0200;
325*34f9b3eeSRoland Mainz 				meta[3] = printof(n);
326*34f9b3eeSRoland Mainz 				sfwrite(op, (char*)meta, 4);
327*34f9b3eeSRoland Mainz 			} while (states[c = *++cp] == T_CNTL8BIT && raw);
328da2e3ebdSchin 			break;
329*34f9b3eeSRoland Mainz 		case T_EIGHTBIT:
330*34f9b3eeSRoland Mainz 			do
331*34f9b3eeSRoland Mainz 			{
332*34f9b3eeSRoland Mainz 				meta[2] = c & ~0200;
333*34f9b3eeSRoland Mainz 				sfwrite(op, (char*)meta, 3);
334*34f9b3eeSRoland Mainz 			} while (states[c = *++cp] == T_EIGHTBIT && raw);
335*34f9b3eeSRoland Mainz 			break;
336*34f9b3eeSRoland Mainz 		case T_NEWLINE:
337*34f9b3eeSRoland Mainz 			if (header && !(flags & B_FLAG))
338*34f9b3eeSRoland Mainz 				sfprintf(op, "%6d\t", line);
339*34f9b3eeSRoland Mainz 			if (flags & E_FLAG)
340*34f9b3eeSRoland Mainz 				sfputc(op, '$');
341*34f9b3eeSRoland Mainz 			sfputc(op, '\n');
342*34f9b3eeSRoland Mainz 			if (!header || !(flags & B_FLAG))
343*34f9b3eeSRoland Mainz 				line++;
344*34f9b3eeSRoland Mainz 			header = !(flags & S_FLAG);
345*34f9b3eeSRoland Mainz 			for (;;)
346*34f9b3eeSRoland Mainz 			{
347*34f9b3eeSRoland Mainz 				if ((n = states[*++cp]) == T_ENDBUF)
348*34f9b3eeSRoland Mainz 				{
349*34f9b3eeSRoland Mainz 					if (cp != end || last != '\n')
350*34f9b3eeSRoland Mainz 						break;
351*34f9b3eeSRoland Mainz 					if (!(nxt = (unsigned char*)(*reserve)(ip, SF_UNBOUND, 0)))
352*34f9b3eeSRoland Mainz 					{
353*34f9b3eeSRoland Mainz 						states[0] = sfvalue(ip) ? T_ERROR : T_EOF;
354*34f9b3eeSRoland Mainz 						cp = end = tmp;
355*34f9b3eeSRoland Mainz 						*cp-- = 0;
356*34f9b3eeSRoland Mainz 						last = -1;
357da2e3ebdSchin 					}
358*34f9b3eeSRoland Mainz 					else if ((n = sfvalue(ip)) <= 0)
359*34f9b3eeSRoland Mainz 					{
360*34f9b3eeSRoland Mainz 						states[0] = n ? T_ERROR : T_EOF;
361*34f9b3eeSRoland Mainz 						cp = end = tmp;
362*34f9b3eeSRoland Mainz 						*cp-- = 0;
363*34f9b3eeSRoland Mainz 						last = -1;
364*34f9b3eeSRoland Mainz 					}
365*34f9b3eeSRoland Mainz 					else
366*34f9b3eeSRoland Mainz 					{
367*34f9b3eeSRoland Mainz 						buf = nxt;
368*34f9b3eeSRoland Mainz 						end = buf + n - 1;
369*34f9b3eeSRoland Mainz 						last = *end;
370*34f9b3eeSRoland Mainz 						*end = 0;
371*34f9b3eeSRoland Mainz 						cp = buf - 1;
372*34f9b3eeSRoland Mainz 					}
373*34f9b3eeSRoland Mainz 				}
374*34f9b3eeSRoland Mainz 				else if (n != T_NEWLINE)
375*34f9b3eeSRoland Mainz 					break;
376*34f9b3eeSRoland Mainz 				if (!(flags & S_FLAG) || any || header)
377*34f9b3eeSRoland Mainz 				{
378*34f9b3eeSRoland Mainz 					any = 0;
379*34f9b3eeSRoland Mainz 					header = 0;
380*34f9b3eeSRoland Mainz 					if ((flags & (B_FLAG|N_FLAG)) == N_FLAG)
381*34f9b3eeSRoland Mainz 						sfprintf(op, "%6d\t", line);
382*34f9b3eeSRoland Mainz 					if (flags & E_FLAG)
383*34f9b3eeSRoland Mainz 						sfputc(op, '$');
384*34f9b3eeSRoland Mainz 					sfputc(op, '\n');
385*34f9b3eeSRoland Mainz 				}
386*34f9b3eeSRoland Mainz 				if (!(flags & B_FLAG))
387*34f9b3eeSRoland Mainz 					line++;
388*34f9b3eeSRoland Mainz 			}
389*34f9b3eeSRoland Mainz 			header = flags & (B_FLAG|N_FLAG);
390*34f9b3eeSRoland Mainz 			break;
391da2e3ebdSchin 		}
392da2e3ebdSchin 	}
393da2e3ebdSchin }
394da2e3ebdSchin 
395da2e3ebdSchin int
396da2e3ebdSchin b_cat(int argc, char** argv, void* context)
397da2e3ebdSchin {
398da2e3ebdSchin 	register int		n;
399da2e3ebdSchin 	register int		flags = 0;
400da2e3ebdSchin 	register char*		cp;
401da2e3ebdSchin 	register Sfio_t*	fp;
402da2e3ebdSchin 	char*			mode;
403*34f9b3eeSRoland Mainz 	Reserve_f		reserve = sfreserve;
404da2e3ebdSchin 	int			att;
405da2e3ebdSchin 	int			dovcat = 0;
406da2e3ebdSchin 	char			states[UCHAR_MAX+1];
407da2e3ebdSchin 
408da2e3ebdSchin 	cmdinit(argc, argv, context, ERROR_CATALOG, 0);
409*34f9b3eeSRoland Mainz 	setlocale(LC_ALL, "");
410da2e3ebdSchin 	att = !strcmp(astconf("UNIVERSE", NiL, NiL), "att");
411da2e3ebdSchin 	mode = "r";
412da2e3ebdSchin 	for (;;)
413da2e3ebdSchin 	{
414*34f9b3eeSRoland Mainz 		n = 0;
415da2e3ebdSchin 		switch (optget(argv, usage))
416da2e3ebdSchin 		{
417da2e3ebdSchin 		case 'A':
418*34f9b3eeSRoland Mainz 			n = T_FLAG|E_FLAG|V_FLAG;
419*34f9b3eeSRoland Mainz 			break;
420da2e3ebdSchin 		case 'B':
421*34f9b3eeSRoland Mainz 			n = S_FLAG;
422*34f9b3eeSRoland Mainz 			break;
423da2e3ebdSchin 		case 'b':
424*34f9b3eeSRoland Mainz 			n = B_FLAG;
425*34f9b3eeSRoland Mainz 			break;
426da2e3ebdSchin 		case 'd':
427*34f9b3eeSRoland Mainz 			mode = opt_info.num ? "rt" : "r";
428da2e3ebdSchin 			continue;
429da2e3ebdSchin 		case 'D':
430*34f9b3eeSRoland Mainz 			n = d_FLAG;
431*34f9b3eeSRoland Mainz 			break;
432*34f9b3eeSRoland Mainz 		case 'E':
433*34f9b3eeSRoland Mainz 			n = E_FLAG;
434*34f9b3eeSRoland Mainz 			break;
435*34f9b3eeSRoland Mainz 		case 'e':
436*34f9b3eeSRoland Mainz 			n = E_FLAG|V_FLAG;
437*34f9b3eeSRoland Mainz 			break;
438*34f9b3eeSRoland Mainz 		case 'n':
439*34f9b3eeSRoland Mainz 			n = N_FLAG;
440*34f9b3eeSRoland Mainz 			break;
441*34f9b3eeSRoland Mainz 		case 'R':
442*34f9b3eeSRoland Mainz 			reserve = opt_info.num ? regress : sfreserve;
443da2e3ebdSchin 			continue;
444*34f9b3eeSRoland Mainz 		case 's':
445*34f9b3eeSRoland Mainz 			n = att ? F_FLAG : S_FLAG;
446*34f9b3eeSRoland Mainz 			break;
447*34f9b3eeSRoland Mainz 		case 'S':
448*34f9b3eeSRoland Mainz 			n = F_FLAG;
449*34f9b3eeSRoland Mainz 			break;
450*34f9b3eeSRoland Mainz 		case 'T':
451*34f9b3eeSRoland Mainz 			n = T_FLAG;
452*34f9b3eeSRoland Mainz 			break;
453*34f9b3eeSRoland Mainz 		case 't':
454*34f9b3eeSRoland Mainz 			n = T_FLAG|V_FLAG;
455*34f9b3eeSRoland Mainz 			break;
456*34f9b3eeSRoland Mainz 		case 'u':
457*34f9b3eeSRoland Mainz 			n = U_FLAG;
458*34f9b3eeSRoland Mainz 			break;
459*34f9b3eeSRoland Mainz 		case 'v':
460*34f9b3eeSRoland Mainz 			n = V_FLAG;
461*34f9b3eeSRoland Mainz 			break;
462da2e3ebdSchin 		case ':':
463da2e3ebdSchin 			error(2, "%s", opt_info.arg);
464da2e3ebdSchin 			break;
465da2e3ebdSchin 		case '?':
466da2e3ebdSchin 			error(ERROR_usage(2), "%s", opt_info.arg);
467da2e3ebdSchin 			break;
468da2e3ebdSchin 		}
469*34f9b3eeSRoland Mainz 		if (!n)
470da2e3ebdSchin 			break;
471*34f9b3eeSRoland Mainz 		if (opt_info.num)
472*34f9b3eeSRoland Mainz 			flags |= n;
473*34f9b3eeSRoland Mainz 		else
474*34f9b3eeSRoland Mainz 			flags &= ~n;
475da2e3ebdSchin 	}
476da2e3ebdSchin 	argv += opt_info.index;
477da2e3ebdSchin 	if (error_info.errors)
478da2e3ebdSchin 		error(ERROR_usage(2), "%s", optusage(NiL));
479da2e3ebdSchin 	memset(states, 0, sizeof(states));
480da2e3ebdSchin 	if (flags&V_FLAG)
481da2e3ebdSchin 	{
482da2e3ebdSchin 		memset(states, T_CONTROL, ' ');
483da2e3ebdSchin 		states[RUBOUT] = T_CONTROL;
484da2e3ebdSchin 		memset(states+0200, T_EIGHTBIT, 0200);
485da2e3ebdSchin 		memset(states+0200, T_CNTL8BIT, ' ');
486da2e3ebdSchin 		states[RUBOUT|0200] = T_CNTL8BIT;
487da2e3ebdSchin 		states['\n'] = 0;
488da2e3ebdSchin 	}
489da2e3ebdSchin 	if (flags&T_FLAG)
490da2e3ebdSchin 		states['\t'] = T_CONTROL;
491da2e3ebdSchin 	states[0] = T_ENDBUF;
492da2e3ebdSchin 	if (att)
493da2e3ebdSchin 	{
494da2e3ebdSchin 		if (flags&V_FLAG)
495da2e3ebdSchin 		{
496da2e3ebdSchin 			states['\n'|0200] = T_EIGHTBIT;
497da2e3ebdSchin 			if (!(flags&T_FLAG))
498da2e3ebdSchin 			{
499da2e3ebdSchin 				states['\t'] = states['\f'] = 0;
500da2e3ebdSchin 				states['\t'|0200] = states['\f'|0200] = T_EIGHTBIT;
501da2e3ebdSchin 			}
502da2e3ebdSchin 		}
503da2e3ebdSchin 	}
504da2e3ebdSchin 	else if (flags)
505da2e3ebdSchin 	{
506da2e3ebdSchin 		if (!(flags&T_FLAG))
507da2e3ebdSchin 			states['\t'] = 0;
508da2e3ebdSchin 	}
5097c2fbfb3SApril Chin 	if (flags&(V_FLAG|T_FLAG|N_FLAG|E_FLAG|B_FLAG|S_FLAG))
510da2e3ebdSchin 	{
511da2e3ebdSchin 		states['\n'] = T_NEWLINE;
512da2e3ebdSchin 		dovcat = 1;
513da2e3ebdSchin 	}
514da2e3ebdSchin 	if (flags&d_FLAG)
515da2e3ebdSchin 		sfopen(sfstdout, NiL, "wt");
516da2e3ebdSchin 	if (cp = *argv)
517da2e3ebdSchin 		argv++;
518da2e3ebdSchin 	do
519da2e3ebdSchin 	{
520da2e3ebdSchin 		if (!cp || streq(cp, "-"))
521da2e3ebdSchin 		{
522da2e3ebdSchin 			fp = sfstdin;
523da2e3ebdSchin 			if (flags&D_FLAG)
524da2e3ebdSchin 				sfopen(fp, NiL, mode);
525da2e3ebdSchin 		}
526da2e3ebdSchin 		else if (!(fp = sfopen(NiL, cp, mode)))
527da2e3ebdSchin 		{
528da2e3ebdSchin 			if (!(flags&F_FLAG))
529da2e3ebdSchin 				error(ERROR_system(0), "%s: cannot open", cp);
530da2e3ebdSchin 			error_info.errors = 1;
531da2e3ebdSchin 			continue;
532da2e3ebdSchin 		}
533da2e3ebdSchin 		if (flags&U_FLAG)
534da2e3ebdSchin 			sfsetbuf(fp, (void*)fp, -1);
535da2e3ebdSchin 		if (dovcat)
536*34f9b3eeSRoland Mainz 			n = vcat(states, fp, sfstdout, reserve, flags);
537da2e3ebdSchin 		else if (sfmove(fp, sfstdout, SF_UNBOUND, -1) >= 0 && sfeof(fp))
538da2e3ebdSchin 			n = 0;
539da2e3ebdSchin 		else
540da2e3ebdSchin 			n = -1;
541da2e3ebdSchin 		if (fp != sfstdin)
542da2e3ebdSchin 			sfclose(fp);
543da2e3ebdSchin 		if (n < 0 && errno != EPIPE)
544da2e3ebdSchin 		{
545da2e3ebdSchin 			if (cp)
546da2e3ebdSchin 				error(ERROR_system(0), "%s: read error", cp);
547da2e3ebdSchin 			else
548da2e3ebdSchin 				error(ERROR_system(0), "read error");
549da2e3ebdSchin 		}
550da2e3ebdSchin 		if (sferror(sfstdout))
551da2e3ebdSchin 			break;
552da2e3ebdSchin 	} while (cp = *argv++);
553da2e3ebdSchin 	if (sfsync(sfstdout))
554da2e3ebdSchin 		error(ERROR_system(0), "write error");
555da2e3ebdSchin 	if (flags&d_FLAG)
556da2e3ebdSchin 		sfopen(sfstdout, NiL, "w");
557da2e3ebdSchin 	return error_info.errors;
558da2e3ebdSchin }
559