14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1992-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.Chin@Sun.COM * by AT&T Intellectual Property * 84887Schin * * 94887Schin * A copy of the License is available at * 104887Schin * http://www.opensource.org/licenses/cpl1.0.txt * 114887Schin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 124887Schin * * 134887Schin * Information and Software Systems Research * 144887Schin * AT&T Research * 154887Schin * Florham Park NJ * 164887Schin * * 174887Schin * Glenn Fowler <gsf@research.att.com> * 184887Schin * David Korn <dgk@research.att.com> * 194887Schin * * 204887Schin ***********************************************************************/ 214887Schin #pragma prototyped 224887Schin /* 234887Schin * David Korn 244887Schin * Glenn Fowler 254887Schin * AT&T Bell Laboratories 264887Schin * 274887Schin * cat 284887Schin */ 294887Schin 304887Schin #include <cmd.h> 314887Schin #include <fcntl.h> 324887Schin 334887Schin static const char usage[] = 34*8462SApril.Chin@Sun.COM "[-?\n@(#)$Id: cat (AT&T Research) 2007-07-17 $\n]" 354887Schin USAGE_LICENSE 364887Schin "[+NAME?cat - concatenate files]" 374887Schin "[+DESCRIPTION?\bcat\b copies each \afile\a in sequence to the standard" 384887Schin " output. If no \afile\a is given, or if the \afile\a is \b-\b," 394887Schin " \bcat\b copies from standard input starting at the current location.]" 404887Schin 414887Schin "[b:number-nonblank?Number lines as with \b-n\b but omit line numbers from" 424887Schin " blank lines.]" 434887Schin "[d:dos-input?Input files are opened in \atext\amode which removes carriage" 444887Schin " returns in front of new-lines on some systems.]" 454887Schin "[e?Equivalent to \b-vE\b.]" 464887Schin "[n:number?Causes a line number to be inserted at the beginning of each line.]" 474887Schin "[s?Equivalent to \b-S\b for \aatt\a universe and \b-B\b otherwise.]" 484887Schin "[t?Equivalent to \b-vT\b.]" 494887Schin "[u:unbuffer?The output is not delayed by buffering.]" 504887Schin "[v:show-nonprinting?Causes non-printing characters (whith the exception of" 514887Schin " tabs, new-lines, and form-feeds) to be output as printable charater" 524887Schin " sequences. ASCII control characters are printed as \b^\b\an\a," 534887Schin " where \an\a is the corresponding ASCII character in the range" 544887Schin " octal 100-137. The DEL character (octal 0177) is copied" 554887Schin " as \b^?\b. Other non-printable characters are copied as \bM-\b\ax\a" 564887Schin " where \ax\a is the ASCII character specified by the low-order seven" 574887Schin " bits. Multibyte characters in the current locale are treated as" 584887Schin " printable characters.]" 594887Schin "[A:show-all?Equivalent to \b-vET\b.]" 604887Schin "[B:squeeze-blank?Multiple adjacent new-line characters are replace by one" 614887Schin " new-line.]" 624887Schin "[D:dos-output?Output files are opened in \atext\amode which inserts carriage" 634887Schin " returns in front of new-lines on some systems.]" 644887Schin "[E:show-ends?Causes a \b$\b to be inserted before each new-line.]" 654887Schin "[S:silent?\bcat\b is silent about non-existent files.]" 664887Schin "[T:show-blank?Causes tabs to be copied as \b^I\b and formfeeds as \b^L\b.]" 674887Schin 684887Schin "\n" 694887Schin "\n[file ...]\n" 704887Schin "\n" 714887Schin 724887Schin "[+SEE ALSO?\bcp\b(1), \bgetconf\b(1), \bpr\b(1)]" 734887Schin ; 744887Schin 754887Schin #define RUBOUT 0177 764887Schin 774887Schin /* control flags */ 784887Schin #define B_FLAG (1<<0) 794887Schin #define E_FLAG (1<<1) 804887Schin #define F_FLAG (1<<2) 814887Schin #define N_FLAG (1<<3) 824887Schin #define S_FLAG (1<<4) 834887Schin #define T_FLAG (1<<5) 844887Schin #define U_FLAG (1<<6) 854887Schin #define V_FLAG (1<<7) 864887Schin #define D_FLAG (1<<8) 874887Schin #define d_FLAG (1<<9) 884887Schin 894887Schin /* character types */ 904887Schin #define T_ENDBUF 1 914887Schin #define T_CONTROL 2 924887Schin #define T_NEWLINE 3 934887Schin #define T_EIGHTBIT 4 944887Schin #define T_CNTL8BIT 5 954887Schin 964887Schin #define printof(c) ((c)^0100) 974887Schin 984887Schin /* 994887Schin * called for any special output processing 1004887Schin */ 1014887Schin 1024887Schin static int 1034887Schin vcat(register char* states, Sfio_t *fdin, Sfio_t *fdout, int flags) 1044887Schin { 1054887Schin register unsigned char* cp; 1064887Schin register unsigned char* cpold; 1074887Schin register int n; 1084887Schin register int m; 1094887Schin register int line = 1; 1104887Schin register unsigned char* endbuff; 1114887Schin unsigned char* inbuff; 1124887Schin int printdefer = (flags&(B_FLAG|N_FLAG)); 1134887Schin int lastchar; 114*8462SApril.Chin@Sun.COM int lastline; 1154887Schin 1164887Schin unsigned char meta[4]; 1174887Schin 1184887Schin meta[0] = 'M'; 1194887Schin meta[1] = '-'; 1204887Schin for (;;) 1214887Schin { 1224887Schin /* read in a buffer full */ 1234887Schin if (!(inbuff = (unsigned char*)sfreserve(fdin, SF_UNBOUND, 0))) 1244887Schin return sfvalue(fdin) ? -1 : 0; 1254887Schin if ((n = sfvalue(fdin)) <= 0) 1264887Schin return n; 1274887Schin cp = inbuff; 1284887Schin lastchar = *(endbuff = cp + --n); 1294887Schin *endbuff = 0; 1304887Schin if (printdefer) 1314887Schin { 1324887Schin if (states[*cp]!=T_NEWLINE || !(flags&B_FLAG)) 1334887Schin sfprintf(fdout,"%6d\t",line); 1344887Schin printdefer = 0; 1354887Schin } 1364887Schin while (endbuff) 1374887Schin { 1384887Schin cpold = cp; 1394887Schin /* skip over printable characters */ 1404887Schin if (mbwide()) 1414887Schin while ((n = (m = mbsize(cp)) < 2 ? states[*cp++] : (cp += m, states['a'])) == 0); 1424887Schin else 1434887Schin while ((n = states[*cp++]) == 0); 1444887Schin if (n==T_ENDBUF) 1454887Schin { 1464887Schin if (cp>endbuff) 1474887Schin { 1484887Schin if (!(n = states[lastchar])) 1494887Schin { 1504887Schin *endbuff = lastchar; 1514887Schin cp++; 1524887Schin } 1534887Schin else 1544887Schin { 1554887Schin if (--cp > cpold) 1564887Schin sfwrite(fdout,(char*)cpold,cp-cpold); 1574887Schin if (endbuff==inbuff) 1584887Schin *++endbuff = 0; 1594887Schin cp = cpold = endbuff; 1604887Schin cp[-1] = lastchar; 1614887Schin if (n==T_ENDBUF) 1624887Schin n = T_CONTROL; 1634887Schin 1644887Schin } 1654887Schin endbuff = 0; 1664887Schin } 1674887Schin else n = T_CONTROL; 1684887Schin } 1694887Schin if (--cp>cpold) 1704887Schin sfwrite(fdout,(char*)cpold,cp-cpold); 1714887Schin switch(n) 1724887Schin { 1734887Schin case T_CNTL8BIT: 1744887Schin meta[2] = '^'; 1754887Schin do 1764887Schin { 1774887Schin n = (*cp++)&~0200; 1784887Schin meta[3] = printof(n); 1794887Schin sfwrite(fdout,(char*)meta,4); 1804887Schin } 1814887Schin while ((n=states[*cp])==T_CNTL8BIT); 1824887Schin break; 1834887Schin case T_EIGHTBIT: 1844887Schin do 1854887Schin { 1864887Schin meta[2] = (*cp++)&~0200; 1874887Schin sfwrite(fdout,(char*)meta,3); 1884887Schin } 1894887Schin while ((n=states[*cp])==T_EIGHTBIT); 1904887Schin break; 1914887Schin case T_CONTROL: 1924887Schin do 1934887Schin { 1944887Schin n = *cp++; 1954887Schin sfputc(fdout,'^'); 1964887Schin sfputc(fdout,printof(n)); 1974887Schin } 1984887Schin while ((n=states[*cp])==T_CONTROL); 1994887Schin break; 2004887Schin case T_NEWLINE: 201*8462SApril.Chin@Sun.COM lastline = line; 2024887Schin if (flags&S_FLAG) 2034887Schin { 2044887Schin while (states[*++cp]==T_NEWLINE) 2054887Schin line++; 2064887Schin cp--; 2074887Schin } 2084887Schin do 2094887Schin { 2104887Schin cp++; 2114887Schin if (flags&E_FLAG) 2124887Schin sfputc(fdout,'$'); 2134887Schin sfputc(fdout,'\n'); 214*8462SApril.Chin@Sun.COM if(line > lastline) 215*8462SApril.Chin@Sun.COM { 216*8462SApril.Chin@Sun.COM if (flags&E_FLAG) 217*8462SApril.Chin@Sun.COM sfputc(fdout,'$'); 218*8462SApril.Chin@Sun.COM sfputc(fdout,'\n'); 219*8462SApril.Chin@Sun.COM } 2204887Schin if (!(flags&(N_FLAG|B_FLAG))) 2214887Schin continue; 2224887Schin line++; 2234887Schin if (cp < endbuff) 2244887Schin sfprintf(fdout,"%6d\t",line); 2254887Schin else printdefer = 1; 2264887Schin } 2274887Schin while (states[*cp]==T_NEWLINE); 2284887Schin break; 2294887Schin } 2304887Schin } 2314887Schin } 2324887Schin } 2334887Schin 2344887Schin int 2354887Schin b_cat(int argc, char** argv, void* context) 2364887Schin { 2374887Schin register int n; 2384887Schin register int flags = 0; 2394887Schin register char* cp; 2404887Schin register Sfio_t* fp; 2414887Schin char* mode; 2424887Schin int att; 2434887Schin int dovcat=0; 2444887Schin char states[UCHAR_MAX+1]; 2454887Schin 2464887Schin NoP(argc); 2474887Schin cmdinit(argc, argv, context, ERROR_CATALOG, 0); 2484887Schin att = !strcmp(astconf("UNIVERSE", NiL, NiL), "att"); 2494887Schin mode = "r"; 2504887Schin for (;;) 2514887Schin { 2524887Schin switch (optget(argv, usage)) 2534887Schin { 2544887Schin case 'A': 2554887Schin flags |= T_FLAG|E_FLAG|V_FLAG; 2564887Schin continue; 2574887Schin case 'B': 2584887Schin flags |= S_FLAG; 2594887Schin continue; 2604887Schin case 'b': 2614887Schin flags |= B_FLAG; 2624887Schin continue; 2634887Schin case 'E': 2644887Schin flags |= E_FLAG; 2654887Schin continue; 2664887Schin case 'e': 2674887Schin flags |= E_FLAG|V_FLAG; 2684887Schin continue; 2694887Schin case 'n': 2704887Schin flags |= N_FLAG; 2714887Schin continue; 2724887Schin case 's': 2734887Schin flags |= att ? F_FLAG : S_FLAG; 2744887Schin continue; 2754887Schin case 'S': 2764887Schin flags |= F_FLAG; 2774887Schin continue; 2784887Schin case 'T': 2794887Schin flags |= T_FLAG; 2804887Schin continue; 2814887Schin case 't': 2824887Schin flags |= T_FLAG|V_FLAG; 2834887Schin continue; 2844887Schin case 'u': 2854887Schin flags |= U_FLAG; 2864887Schin continue; 2874887Schin case 'v': 2884887Schin flags |= V_FLAG; 2894887Schin continue; 2904887Schin case 'd': 2914887Schin mode = "rt"; 2924887Schin continue; 2934887Schin case 'D': 2944887Schin flags |= d_FLAG; 2954887Schin continue; 2964887Schin case ':': 2974887Schin error(2, "%s", opt_info.arg); 2984887Schin break; 2994887Schin case '?': 3004887Schin error(ERROR_usage(2), "%s", opt_info.arg); 3014887Schin break; 3024887Schin } 3034887Schin break; 3044887Schin } 3054887Schin argv += opt_info.index; 3064887Schin if (error_info.errors) 3074887Schin error(ERROR_usage(2), "%s", optusage(NiL)); 3084887Schin memset(states, 0, sizeof(states)); 3094887Schin if (flags&V_FLAG) 3104887Schin { 3114887Schin memset(states, T_CONTROL, ' '); 3124887Schin states[RUBOUT] = T_CONTROL; 3134887Schin memset(states+0200, T_EIGHTBIT, 0200); 3144887Schin memset(states+0200, T_CNTL8BIT, ' '); 3154887Schin states[RUBOUT|0200] = T_CNTL8BIT; 3164887Schin states['\n'] = 0; 3174887Schin } 3184887Schin if (flags&T_FLAG) 3194887Schin states['\t'] = T_CONTROL; 3204887Schin states[0] = T_ENDBUF; 3214887Schin if (att) 3224887Schin { 3234887Schin if (flags&V_FLAG) 3244887Schin { 3254887Schin states['\n'|0200] = T_EIGHTBIT; 3264887Schin if (!(flags&T_FLAG)) 3274887Schin { 3284887Schin states['\t'] = states['\f'] = 0; 3294887Schin states['\t'|0200] = states['\f'|0200] = T_EIGHTBIT; 3304887Schin } 3314887Schin } 3324887Schin } 3334887Schin else if (flags) 3344887Schin { 3354887Schin if (!(flags&T_FLAG)) 3364887Schin states['\t'] = 0; 3374887Schin } 338*8462SApril.Chin@Sun.COM if (flags&(V_FLAG|T_FLAG|N_FLAG|E_FLAG|B_FLAG|S_FLAG)) 3394887Schin { 3404887Schin states['\n'] = T_NEWLINE; 3414887Schin dovcat = 1; 3424887Schin } 3434887Schin if (flags&B_FLAG) 3444887Schin flags |= S_FLAG; 3454887Schin if (flags&d_FLAG) 3464887Schin sfopen(sfstdout, NiL, "wt"); 3474887Schin if (cp = *argv) 3484887Schin argv++; 3494887Schin do 3504887Schin { 3514887Schin if (!cp || streq(cp,"-")) 3524887Schin { 3534887Schin fp = sfstdin; 3544887Schin if (flags&D_FLAG) 3554887Schin sfopen(fp, NiL, mode); 3564887Schin } 3574887Schin else if (!(fp = sfopen(NiL, cp, mode))) 3584887Schin { 3594887Schin if (!(flags&F_FLAG)) 3604887Schin error(ERROR_system(0), "%s: cannot open", cp); 3614887Schin error_info.errors = 1; 3624887Schin continue; 3634887Schin } 3644887Schin if (flags&U_FLAG) 3654887Schin sfsetbuf(fp, (void*)fp, -1); 3664887Schin if (dovcat) 3674887Schin n = vcat(states, fp, sfstdout, flags); 3684887Schin else if (sfmove(fp, sfstdout, SF_UNBOUND, -1) >= 0 && sfeof(fp)) 3694887Schin n = 0; 3704887Schin else 3714887Schin n = -1; 3724887Schin if (fp != sfstdin) 3734887Schin sfclose(fp); 3744887Schin if (n < 0 && errno != EPIPE) 3754887Schin { 3764887Schin if (cp) 3774887Schin error(ERROR_system(0), "%s: read error", cp); 3784887Schin else 3794887Schin error(ERROR_system(0), "read error"); 3804887Schin } 3814887Schin if (sferror(sfstdout)) 3824887Schin break; 3834887Schin } while (cp = *argv++); 3844887Schin if (sfsync(sfstdout)) 3854887Schin error(ERROR_system(0), "write error"); 3864887Schin if (flags&d_FLAG) 3874887Schin sfopen(sfstdout, NiL, "w"); 3884887Schin return error_info.errors; 3894887Schin } 390