1*da2e3ebdSchin /*********************************************************************** 2*da2e3ebdSchin * * 3*da2e3ebdSchin * This software is part of the ast package * 4*da2e3ebdSchin * Copyright (c) 1992-2007 AT&T Knowledge Ventures * 5*da2e3ebdSchin * and is licensed under the * 6*da2e3ebdSchin * Common Public License, Version 1.0 * 7*da2e3ebdSchin * by AT&T Knowledge Ventures * 8*da2e3ebdSchin * * 9*da2e3ebdSchin * A copy of the License is available at * 10*da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt * 11*da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12*da2e3ebdSchin * * 13*da2e3ebdSchin * Information and Software Systems Research * 14*da2e3ebdSchin * AT&T Research * 15*da2e3ebdSchin * Florham Park NJ * 16*da2e3ebdSchin * * 17*da2e3ebdSchin * Glenn Fowler <gsf@research.att.com> * 18*da2e3ebdSchin * David Korn <dgk@research.att.com> * 19*da2e3ebdSchin * * 20*da2e3ebdSchin ***********************************************************************/ 21*da2e3ebdSchin #pragma prototyped 22*da2e3ebdSchin /* 23*da2e3ebdSchin * David Korn 24*da2e3ebdSchin * Glenn Fowler 25*da2e3ebdSchin * AT&T Bell Laboratories 26*da2e3ebdSchin * 27*da2e3ebdSchin * cat 28*da2e3ebdSchin */ 29*da2e3ebdSchin 30*da2e3ebdSchin #include <cmd.h> 31*da2e3ebdSchin #include <fcntl.h> 32*da2e3ebdSchin 33*da2e3ebdSchin static const char usage[] = 34*da2e3ebdSchin "[-?\n@(#)$Id: cat (AT&T Research) 2006-05-17 $\n]" 35*da2e3ebdSchin USAGE_LICENSE 36*da2e3ebdSchin "[+NAME?cat - concatenate files]" 37*da2e3ebdSchin "[+DESCRIPTION?\bcat\b copies each \afile\a in sequence to the standard" 38*da2e3ebdSchin " output. If no \afile\a is given, or if the \afile\a is \b-\b," 39*da2e3ebdSchin " \bcat\b copies from standard input starting at the current location.]" 40*da2e3ebdSchin 41*da2e3ebdSchin "[b:number-nonblank?Number lines as with \b-n\b but omit line numbers from" 42*da2e3ebdSchin " blank lines.]" 43*da2e3ebdSchin "[d:dos-input?Input files are opened in \atext\amode which removes carriage" 44*da2e3ebdSchin " returns in front of new-lines on some systems.]" 45*da2e3ebdSchin "[e?Equivalent to \b-vE\b.]" 46*da2e3ebdSchin "[n:number?Causes a line number to be inserted at the beginning of each line.]" 47*da2e3ebdSchin "[s?Equivalent to \b-S\b for \aatt\a universe and \b-B\b otherwise.]" 48*da2e3ebdSchin "[t?Equivalent to \b-vT\b.]" 49*da2e3ebdSchin "[u:unbuffer?The output is not delayed by buffering.]" 50*da2e3ebdSchin "[v:show-nonprinting?Causes non-printing characters (whith the exception of" 51*da2e3ebdSchin " tabs, new-lines, and form-feeds) to be output as printable charater" 52*da2e3ebdSchin " sequences. ASCII control characters are printed as \b^\b\an\a," 53*da2e3ebdSchin " where \an\a is the corresponding ASCII character in the range" 54*da2e3ebdSchin " octal 100-137. The DEL character (octal 0177) is copied" 55*da2e3ebdSchin " as \b^?\b. Other non-printable characters are copied as \bM-\b\ax\a" 56*da2e3ebdSchin " where \ax\a is the ASCII character specified by the low-order seven" 57*da2e3ebdSchin " bits. Multibyte characters in the current locale are treated as" 58*da2e3ebdSchin " printable characters.]" 59*da2e3ebdSchin "[A:show-all?Equivalent to \b-vET\b.]" 60*da2e3ebdSchin "[B:squeeze-blank?Multiple adjacent new-line characters are replace by one" 61*da2e3ebdSchin " new-line.]" 62*da2e3ebdSchin "[D:dos-output?Output files are opened in \atext\amode which inserts carriage" 63*da2e3ebdSchin " returns in front of new-lines on some systems.]" 64*da2e3ebdSchin "[E:show-ends?Causes a \b$\b to be inserted before each new-line.]" 65*da2e3ebdSchin "[S:silent?\bcat\b is silent about non-existent files.]" 66*da2e3ebdSchin "[T:show-blank?Causes tabs to be copied as \b^I\b and formfeeds as \b^L\b.]" 67*da2e3ebdSchin 68*da2e3ebdSchin "\n" 69*da2e3ebdSchin "\n[file ...]\n" 70*da2e3ebdSchin "\n" 71*da2e3ebdSchin 72*da2e3ebdSchin "[+SEE ALSO?\bcp\b(1), \bgetconf\b(1), \bpr\b(1)]" 73*da2e3ebdSchin ; 74*da2e3ebdSchin 75*da2e3ebdSchin #define RUBOUT 0177 76*da2e3ebdSchin 77*da2e3ebdSchin /* control flags */ 78*da2e3ebdSchin #define B_FLAG (1<<0) 79*da2e3ebdSchin #define E_FLAG (1<<1) 80*da2e3ebdSchin #define F_FLAG (1<<2) 81*da2e3ebdSchin #define N_FLAG (1<<3) 82*da2e3ebdSchin #define S_FLAG (1<<4) 83*da2e3ebdSchin #define T_FLAG (1<<5) 84*da2e3ebdSchin #define U_FLAG (1<<6) 85*da2e3ebdSchin #define V_FLAG (1<<7) 86*da2e3ebdSchin #define D_FLAG (1<<8) 87*da2e3ebdSchin #define d_FLAG (1<<9) 88*da2e3ebdSchin 89*da2e3ebdSchin /* character types */ 90*da2e3ebdSchin #define T_ENDBUF 1 91*da2e3ebdSchin #define T_CONTROL 2 92*da2e3ebdSchin #define T_NEWLINE 3 93*da2e3ebdSchin #define T_EIGHTBIT 4 94*da2e3ebdSchin #define T_CNTL8BIT 5 95*da2e3ebdSchin 96*da2e3ebdSchin #define printof(c) ((c)^0100) 97*da2e3ebdSchin 98*da2e3ebdSchin /* 99*da2e3ebdSchin * called for any special output processing 100*da2e3ebdSchin */ 101*da2e3ebdSchin 102*da2e3ebdSchin static int 103*da2e3ebdSchin vcat(register char* states, Sfio_t *fdin, Sfio_t *fdout, int flags) 104*da2e3ebdSchin { 105*da2e3ebdSchin register unsigned char* cp; 106*da2e3ebdSchin register unsigned char* cpold; 107*da2e3ebdSchin register int n; 108*da2e3ebdSchin register int m; 109*da2e3ebdSchin register int line = 1; 110*da2e3ebdSchin register unsigned char* endbuff; 111*da2e3ebdSchin unsigned char* inbuff; 112*da2e3ebdSchin int printdefer = (flags&(B_FLAG|N_FLAG)); 113*da2e3ebdSchin int lastchar; 114*da2e3ebdSchin 115*da2e3ebdSchin unsigned char meta[4]; 116*da2e3ebdSchin 117*da2e3ebdSchin meta[0] = 'M'; 118*da2e3ebdSchin meta[1] = '-'; 119*da2e3ebdSchin for (;;) 120*da2e3ebdSchin { 121*da2e3ebdSchin /* read in a buffer full */ 122*da2e3ebdSchin if (!(inbuff = (unsigned char*)sfreserve(fdin, SF_UNBOUND, 0))) 123*da2e3ebdSchin return sfvalue(fdin) ? -1 : 0; 124*da2e3ebdSchin if ((n = sfvalue(fdin)) <= 0) 125*da2e3ebdSchin return n; 126*da2e3ebdSchin cp = inbuff; 127*da2e3ebdSchin lastchar = *(endbuff = cp + --n); 128*da2e3ebdSchin *endbuff = 0; 129*da2e3ebdSchin if (printdefer) 130*da2e3ebdSchin { 131*da2e3ebdSchin if (states[*cp]!=T_NEWLINE || !(flags&B_FLAG)) 132*da2e3ebdSchin sfprintf(fdout,"%6d\t",line); 133*da2e3ebdSchin printdefer = 0; 134*da2e3ebdSchin } 135*da2e3ebdSchin while (endbuff) 136*da2e3ebdSchin { 137*da2e3ebdSchin cpold = cp; 138*da2e3ebdSchin /* skip over printable characters */ 139*da2e3ebdSchin if (mbwide()) 140*da2e3ebdSchin while ((n = (m = mbsize(cp)) < 2 ? states[*cp++] : (cp += m, states['a'])) == 0); 141*da2e3ebdSchin else 142*da2e3ebdSchin while ((n = states[*cp++]) == 0); 143*da2e3ebdSchin if (n==T_ENDBUF) 144*da2e3ebdSchin { 145*da2e3ebdSchin if (cp>endbuff) 146*da2e3ebdSchin { 147*da2e3ebdSchin if (!(n = states[lastchar])) 148*da2e3ebdSchin { 149*da2e3ebdSchin *endbuff = lastchar; 150*da2e3ebdSchin cp++; 151*da2e3ebdSchin } 152*da2e3ebdSchin else 153*da2e3ebdSchin { 154*da2e3ebdSchin if (--cp > cpold) 155*da2e3ebdSchin sfwrite(fdout,(char*)cpold,cp-cpold); 156*da2e3ebdSchin if (endbuff==inbuff) 157*da2e3ebdSchin *++endbuff = 0; 158*da2e3ebdSchin cp = cpold = endbuff; 159*da2e3ebdSchin cp[-1] = lastchar; 160*da2e3ebdSchin if (n==T_ENDBUF) 161*da2e3ebdSchin n = T_CONTROL; 162*da2e3ebdSchin 163*da2e3ebdSchin } 164*da2e3ebdSchin endbuff = 0; 165*da2e3ebdSchin } 166*da2e3ebdSchin else n = T_CONTROL; 167*da2e3ebdSchin } 168*da2e3ebdSchin if (--cp>cpold) 169*da2e3ebdSchin sfwrite(fdout,(char*)cpold,cp-cpold); 170*da2e3ebdSchin switch(n) 171*da2e3ebdSchin { 172*da2e3ebdSchin case T_CNTL8BIT: 173*da2e3ebdSchin meta[2] = '^'; 174*da2e3ebdSchin do 175*da2e3ebdSchin { 176*da2e3ebdSchin n = (*cp++)&~0200; 177*da2e3ebdSchin meta[3] = printof(n); 178*da2e3ebdSchin sfwrite(fdout,(char*)meta,4); 179*da2e3ebdSchin } 180*da2e3ebdSchin while ((n=states[*cp])==T_CNTL8BIT); 181*da2e3ebdSchin break; 182*da2e3ebdSchin case T_EIGHTBIT: 183*da2e3ebdSchin do 184*da2e3ebdSchin { 185*da2e3ebdSchin meta[2] = (*cp++)&~0200; 186*da2e3ebdSchin sfwrite(fdout,(char*)meta,3); 187*da2e3ebdSchin } 188*da2e3ebdSchin while ((n=states[*cp])==T_EIGHTBIT); 189*da2e3ebdSchin break; 190*da2e3ebdSchin case T_CONTROL: 191*da2e3ebdSchin do 192*da2e3ebdSchin { 193*da2e3ebdSchin n = *cp++; 194*da2e3ebdSchin sfputc(fdout,'^'); 195*da2e3ebdSchin sfputc(fdout,printof(n)); 196*da2e3ebdSchin } 197*da2e3ebdSchin while ((n=states[*cp])==T_CONTROL); 198*da2e3ebdSchin break; 199*da2e3ebdSchin case T_NEWLINE: 200*da2e3ebdSchin if (flags&S_FLAG) 201*da2e3ebdSchin { 202*da2e3ebdSchin while (states[*++cp]==T_NEWLINE) 203*da2e3ebdSchin line++; 204*da2e3ebdSchin cp--; 205*da2e3ebdSchin } 206*da2e3ebdSchin do 207*da2e3ebdSchin { 208*da2e3ebdSchin cp++; 209*da2e3ebdSchin if (flags&E_FLAG) 210*da2e3ebdSchin sfputc(fdout,'$'); 211*da2e3ebdSchin sfputc(fdout,'\n'); 212*da2e3ebdSchin if (!(flags&(N_FLAG|B_FLAG))) 213*da2e3ebdSchin continue; 214*da2e3ebdSchin line++; 215*da2e3ebdSchin if (cp < endbuff) 216*da2e3ebdSchin sfprintf(fdout,"%6d\t",line); 217*da2e3ebdSchin else printdefer = 1; 218*da2e3ebdSchin } 219*da2e3ebdSchin while (states[*cp]==T_NEWLINE); 220*da2e3ebdSchin break; 221*da2e3ebdSchin } 222*da2e3ebdSchin } 223*da2e3ebdSchin } 224*da2e3ebdSchin } 225*da2e3ebdSchin 226*da2e3ebdSchin int 227*da2e3ebdSchin b_cat(int argc, char** argv, void* context) 228*da2e3ebdSchin { 229*da2e3ebdSchin register int n; 230*da2e3ebdSchin register int flags = 0; 231*da2e3ebdSchin register char* cp; 232*da2e3ebdSchin register Sfio_t* fp; 233*da2e3ebdSchin char* mode; 234*da2e3ebdSchin int att; 235*da2e3ebdSchin int dovcat=0; 236*da2e3ebdSchin char states[UCHAR_MAX+1]; 237*da2e3ebdSchin 238*da2e3ebdSchin NoP(argc); 239*da2e3ebdSchin cmdinit(argc, argv, context, ERROR_CATALOG, 0); 240*da2e3ebdSchin att = !strcmp(astconf("UNIVERSE", NiL, NiL), "att"); 241*da2e3ebdSchin mode = "r"; 242*da2e3ebdSchin for (;;) 243*da2e3ebdSchin { 244*da2e3ebdSchin switch (optget(argv, usage)) 245*da2e3ebdSchin { 246*da2e3ebdSchin case 'A': 247*da2e3ebdSchin flags |= T_FLAG|E_FLAG|V_FLAG; 248*da2e3ebdSchin continue; 249*da2e3ebdSchin case 'B': 250*da2e3ebdSchin flags |= S_FLAG; 251*da2e3ebdSchin continue; 252*da2e3ebdSchin case 'b': 253*da2e3ebdSchin flags |= B_FLAG; 254*da2e3ebdSchin continue; 255*da2e3ebdSchin case 'E': 256*da2e3ebdSchin flags |= E_FLAG; 257*da2e3ebdSchin continue; 258*da2e3ebdSchin case 'e': 259*da2e3ebdSchin flags |= E_FLAG|V_FLAG; 260*da2e3ebdSchin continue; 261*da2e3ebdSchin case 'n': 262*da2e3ebdSchin flags |= N_FLAG; 263*da2e3ebdSchin continue; 264*da2e3ebdSchin case 's': 265*da2e3ebdSchin flags |= att ? F_FLAG : S_FLAG; 266*da2e3ebdSchin continue; 267*da2e3ebdSchin case 'S': 268*da2e3ebdSchin flags |= F_FLAG; 269*da2e3ebdSchin continue; 270*da2e3ebdSchin case 'T': 271*da2e3ebdSchin flags |= T_FLAG; 272*da2e3ebdSchin continue; 273*da2e3ebdSchin case 't': 274*da2e3ebdSchin flags |= T_FLAG|V_FLAG; 275*da2e3ebdSchin continue; 276*da2e3ebdSchin case 'u': 277*da2e3ebdSchin flags |= U_FLAG; 278*da2e3ebdSchin continue; 279*da2e3ebdSchin case 'v': 280*da2e3ebdSchin flags |= V_FLAG; 281*da2e3ebdSchin continue; 282*da2e3ebdSchin case 'd': 283*da2e3ebdSchin mode = "rt"; 284*da2e3ebdSchin continue; 285*da2e3ebdSchin case 'D': 286*da2e3ebdSchin flags |= d_FLAG; 287*da2e3ebdSchin continue; 288*da2e3ebdSchin case ':': 289*da2e3ebdSchin error(2, "%s", opt_info.arg); 290*da2e3ebdSchin break; 291*da2e3ebdSchin case '?': 292*da2e3ebdSchin error(ERROR_usage(2), "%s", opt_info.arg); 293*da2e3ebdSchin break; 294*da2e3ebdSchin } 295*da2e3ebdSchin break; 296*da2e3ebdSchin } 297*da2e3ebdSchin argv += opt_info.index; 298*da2e3ebdSchin if (error_info.errors) 299*da2e3ebdSchin error(ERROR_usage(2), "%s", optusage(NiL)); 300*da2e3ebdSchin memset(states, 0, sizeof(states)); 301*da2e3ebdSchin if (flags&V_FLAG) 302*da2e3ebdSchin { 303*da2e3ebdSchin memset(states, T_CONTROL, ' '); 304*da2e3ebdSchin states[RUBOUT] = T_CONTROL; 305*da2e3ebdSchin memset(states+0200, T_EIGHTBIT, 0200); 306*da2e3ebdSchin memset(states+0200, T_CNTL8BIT, ' '); 307*da2e3ebdSchin states[RUBOUT|0200] = T_CNTL8BIT; 308*da2e3ebdSchin states['\n'] = 0; 309*da2e3ebdSchin } 310*da2e3ebdSchin if (flags&T_FLAG) 311*da2e3ebdSchin states['\t'] = T_CONTROL; 312*da2e3ebdSchin states[0] = T_ENDBUF; 313*da2e3ebdSchin if (att) 314*da2e3ebdSchin { 315*da2e3ebdSchin if (flags&V_FLAG) 316*da2e3ebdSchin { 317*da2e3ebdSchin states['\n'|0200] = T_EIGHTBIT; 318*da2e3ebdSchin if (!(flags&T_FLAG)) 319*da2e3ebdSchin { 320*da2e3ebdSchin states['\t'] = states['\f'] = 0; 321*da2e3ebdSchin states['\t'|0200] = states['\f'|0200] = T_EIGHTBIT; 322*da2e3ebdSchin } 323*da2e3ebdSchin } 324*da2e3ebdSchin } 325*da2e3ebdSchin else if (flags) 326*da2e3ebdSchin { 327*da2e3ebdSchin if (!(flags&T_FLAG)) 328*da2e3ebdSchin states['\t'] = 0; 329*da2e3ebdSchin } 330*da2e3ebdSchin if (flags&(V_FLAG|T_FLAG|N_FLAG|E_FLAG|B_FLAG)) 331*da2e3ebdSchin { 332*da2e3ebdSchin states['\n'] = T_NEWLINE; 333*da2e3ebdSchin dovcat = 1; 334*da2e3ebdSchin } 335*da2e3ebdSchin if (flags&B_FLAG) 336*da2e3ebdSchin flags |= S_FLAG; 337*da2e3ebdSchin if (flags&d_FLAG) 338*da2e3ebdSchin sfopen(sfstdout, NiL, "wt"); 339*da2e3ebdSchin if (cp = *argv) 340*da2e3ebdSchin argv++; 341*da2e3ebdSchin do 342*da2e3ebdSchin { 343*da2e3ebdSchin if (!cp || streq(cp,"-")) 344*da2e3ebdSchin { 345*da2e3ebdSchin fp = sfstdin; 346*da2e3ebdSchin if (flags&D_FLAG) 347*da2e3ebdSchin sfopen(fp, NiL, mode); 348*da2e3ebdSchin } 349*da2e3ebdSchin else if (!(fp = sfopen(NiL, cp, mode))) 350*da2e3ebdSchin { 351*da2e3ebdSchin if (!(flags&F_FLAG)) 352*da2e3ebdSchin error(ERROR_system(0), "%s: cannot open", cp); 353*da2e3ebdSchin error_info.errors = 1; 354*da2e3ebdSchin continue; 355*da2e3ebdSchin } 356*da2e3ebdSchin if (flags&U_FLAG) 357*da2e3ebdSchin sfsetbuf(fp, (void*)fp, -1); 358*da2e3ebdSchin if (dovcat) 359*da2e3ebdSchin n = vcat(states, fp, sfstdout, flags); 360*da2e3ebdSchin else if (sfmove(fp, sfstdout, SF_UNBOUND, -1) >= 0 && sfeof(fp)) 361*da2e3ebdSchin n = 0; 362*da2e3ebdSchin else 363*da2e3ebdSchin n = -1; 364*da2e3ebdSchin if (fp != sfstdin) 365*da2e3ebdSchin sfclose(fp); 366*da2e3ebdSchin if (n < 0 && errno != EPIPE) 367*da2e3ebdSchin { 368*da2e3ebdSchin if (cp) 369*da2e3ebdSchin error(ERROR_system(0), "%s: read error", cp); 370*da2e3ebdSchin else 371*da2e3ebdSchin error(ERROR_system(0), "read error"); 372*da2e3ebdSchin } 373*da2e3ebdSchin if (sferror(sfstdout)) 374*da2e3ebdSchin break; 375*da2e3ebdSchin } while (cp = *argv++); 376*da2e3ebdSchin if (sfsync(sfstdout)) 377*da2e3ebdSchin error(ERROR_system(0), "write error"); 378*da2e3ebdSchin if (flags&d_FLAG) 379*da2e3ebdSchin sfopen(sfstdout, NiL, "w"); 380*da2e3ebdSchin return error_info.errors; 381*da2e3ebdSchin } 382