1da2e3ebdSchin /*********************************************************************** 2da2e3ebdSchin * * 3da2e3ebdSchin * This software is part of the ast package * 4*7c2fbfb3SApril Chin * Copyright (c) 1992-2008 AT&T Intellectual Property * 5da2e3ebdSchin * and is licensed under the * 6da2e3ebdSchin * Common Public License, Version 1.0 * 7*7c2fbfb3SApril 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*7c2fbfb3SApril Chin "[-?\n@(#)$Id: cat (AT&T Research) 2007-07-17 $\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.]" 65da2e3ebdSchin "[S:silent?\bcat\b is silent about non-existent files.]" 66da2e3ebdSchin "[T:show-blank?Causes tabs to be copied as \b^I\b and formfeeds as \b^L\b.]" 67da2e3ebdSchin 68da2e3ebdSchin "\n" 69da2e3ebdSchin "\n[file ...]\n" 70da2e3ebdSchin "\n" 71da2e3ebdSchin 72da2e3ebdSchin "[+SEE ALSO?\bcp\b(1), \bgetconf\b(1), \bpr\b(1)]" 73da2e3ebdSchin ; 74da2e3ebdSchin 75da2e3ebdSchin #define RUBOUT 0177 76da2e3ebdSchin 77da2e3ebdSchin /* control flags */ 78da2e3ebdSchin #define B_FLAG (1<<0) 79da2e3ebdSchin #define E_FLAG (1<<1) 80da2e3ebdSchin #define F_FLAG (1<<2) 81da2e3ebdSchin #define N_FLAG (1<<3) 82da2e3ebdSchin #define S_FLAG (1<<4) 83da2e3ebdSchin #define T_FLAG (1<<5) 84da2e3ebdSchin #define U_FLAG (1<<6) 85da2e3ebdSchin #define V_FLAG (1<<7) 86da2e3ebdSchin #define D_FLAG (1<<8) 87da2e3ebdSchin #define d_FLAG (1<<9) 88da2e3ebdSchin 89da2e3ebdSchin /* character types */ 90da2e3ebdSchin #define T_ENDBUF 1 91da2e3ebdSchin #define T_CONTROL 2 92da2e3ebdSchin #define T_NEWLINE 3 93da2e3ebdSchin #define T_EIGHTBIT 4 94da2e3ebdSchin #define T_CNTL8BIT 5 95da2e3ebdSchin 96da2e3ebdSchin #define printof(c) ((c)^0100) 97da2e3ebdSchin 98da2e3ebdSchin /* 99da2e3ebdSchin * called for any special output processing 100da2e3ebdSchin */ 101da2e3ebdSchin 102da2e3ebdSchin static int 103da2e3ebdSchin vcat(register char* states, Sfio_t *fdin, Sfio_t *fdout, int flags) 104da2e3ebdSchin { 105da2e3ebdSchin register unsigned char* cp; 106da2e3ebdSchin register unsigned char* cpold; 107da2e3ebdSchin register int n; 108da2e3ebdSchin register int m; 109da2e3ebdSchin register int line = 1; 110da2e3ebdSchin register unsigned char* endbuff; 111da2e3ebdSchin unsigned char* inbuff; 112da2e3ebdSchin int printdefer = (flags&(B_FLAG|N_FLAG)); 113da2e3ebdSchin int lastchar; 114*7c2fbfb3SApril Chin int lastline; 115da2e3ebdSchin 116da2e3ebdSchin unsigned char meta[4]; 117da2e3ebdSchin 118da2e3ebdSchin meta[0] = 'M'; 119da2e3ebdSchin meta[1] = '-'; 120da2e3ebdSchin for (;;) 121da2e3ebdSchin { 122da2e3ebdSchin /* read in a buffer full */ 123da2e3ebdSchin if (!(inbuff = (unsigned char*)sfreserve(fdin, SF_UNBOUND, 0))) 124da2e3ebdSchin return sfvalue(fdin) ? -1 : 0; 125da2e3ebdSchin if ((n = sfvalue(fdin)) <= 0) 126da2e3ebdSchin return n; 127da2e3ebdSchin cp = inbuff; 128da2e3ebdSchin lastchar = *(endbuff = cp + --n); 129da2e3ebdSchin *endbuff = 0; 130da2e3ebdSchin if (printdefer) 131da2e3ebdSchin { 132da2e3ebdSchin if (states[*cp]!=T_NEWLINE || !(flags&B_FLAG)) 133da2e3ebdSchin sfprintf(fdout,"%6d\t",line); 134da2e3ebdSchin printdefer = 0; 135da2e3ebdSchin } 136da2e3ebdSchin while (endbuff) 137da2e3ebdSchin { 138da2e3ebdSchin cpold = cp; 139da2e3ebdSchin /* skip over printable characters */ 140da2e3ebdSchin if (mbwide()) 141da2e3ebdSchin while ((n = (m = mbsize(cp)) < 2 ? states[*cp++] : (cp += m, states['a'])) == 0); 142da2e3ebdSchin else 143da2e3ebdSchin while ((n = states[*cp++]) == 0); 144da2e3ebdSchin if (n==T_ENDBUF) 145da2e3ebdSchin { 146da2e3ebdSchin if (cp>endbuff) 147da2e3ebdSchin { 148da2e3ebdSchin if (!(n = states[lastchar])) 149da2e3ebdSchin { 150da2e3ebdSchin *endbuff = lastchar; 151da2e3ebdSchin cp++; 152da2e3ebdSchin } 153da2e3ebdSchin else 154da2e3ebdSchin { 155da2e3ebdSchin if (--cp > cpold) 156da2e3ebdSchin sfwrite(fdout,(char*)cpold,cp-cpold); 157da2e3ebdSchin if (endbuff==inbuff) 158da2e3ebdSchin *++endbuff = 0; 159da2e3ebdSchin cp = cpold = endbuff; 160da2e3ebdSchin cp[-1] = lastchar; 161da2e3ebdSchin if (n==T_ENDBUF) 162da2e3ebdSchin n = T_CONTROL; 163da2e3ebdSchin 164da2e3ebdSchin } 165da2e3ebdSchin endbuff = 0; 166da2e3ebdSchin } 167da2e3ebdSchin else n = T_CONTROL; 168da2e3ebdSchin } 169da2e3ebdSchin if (--cp>cpold) 170da2e3ebdSchin sfwrite(fdout,(char*)cpold,cp-cpold); 171da2e3ebdSchin switch(n) 172da2e3ebdSchin { 173da2e3ebdSchin case T_CNTL8BIT: 174da2e3ebdSchin meta[2] = '^'; 175da2e3ebdSchin do 176da2e3ebdSchin { 177da2e3ebdSchin n = (*cp++)&~0200; 178da2e3ebdSchin meta[3] = printof(n); 179da2e3ebdSchin sfwrite(fdout,(char*)meta,4); 180da2e3ebdSchin } 181da2e3ebdSchin while ((n=states[*cp])==T_CNTL8BIT); 182da2e3ebdSchin break; 183da2e3ebdSchin case T_EIGHTBIT: 184da2e3ebdSchin do 185da2e3ebdSchin { 186da2e3ebdSchin meta[2] = (*cp++)&~0200; 187da2e3ebdSchin sfwrite(fdout,(char*)meta,3); 188da2e3ebdSchin } 189da2e3ebdSchin while ((n=states[*cp])==T_EIGHTBIT); 190da2e3ebdSchin break; 191da2e3ebdSchin case T_CONTROL: 192da2e3ebdSchin do 193da2e3ebdSchin { 194da2e3ebdSchin n = *cp++; 195da2e3ebdSchin sfputc(fdout,'^'); 196da2e3ebdSchin sfputc(fdout,printof(n)); 197da2e3ebdSchin } 198da2e3ebdSchin while ((n=states[*cp])==T_CONTROL); 199da2e3ebdSchin break; 200da2e3ebdSchin case T_NEWLINE: 201*7c2fbfb3SApril Chin lastline = line; 202da2e3ebdSchin if (flags&S_FLAG) 203da2e3ebdSchin { 204da2e3ebdSchin while (states[*++cp]==T_NEWLINE) 205da2e3ebdSchin line++; 206da2e3ebdSchin cp--; 207da2e3ebdSchin } 208da2e3ebdSchin do 209da2e3ebdSchin { 210da2e3ebdSchin cp++; 211da2e3ebdSchin if (flags&E_FLAG) 212da2e3ebdSchin sfputc(fdout,'$'); 213da2e3ebdSchin sfputc(fdout,'\n'); 214*7c2fbfb3SApril Chin if(line > lastline) 215*7c2fbfb3SApril Chin { 216*7c2fbfb3SApril Chin if (flags&E_FLAG) 217*7c2fbfb3SApril Chin sfputc(fdout,'$'); 218*7c2fbfb3SApril Chin sfputc(fdout,'\n'); 219*7c2fbfb3SApril Chin } 220da2e3ebdSchin if (!(flags&(N_FLAG|B_FLAG))) 221da2e3ebdSchin continue; 222da2e3ebdSchin line++; 223da2e3ebdSchin if (cp < endbuff) 224da2e3ebdSchin sfprintf(fdout,"%6d\t",line); 225da2e3ebdSchin else printdefer = 1; 226da2e3ebdSchin } 227da2e3ebdSchin while (states[*cp]==T_NEWLINE); 228da2e3ebdSchin break; 229da2e3ebdSchin } 230da2e3ebdSchin } 231da2e3ebdSchin } 232da2e3ebdSchin } 233da2e3ebdSchin 234da2e3ebdSchin int 235da2e3ebdSchin b_cat(int argc, char** argv, void* context) 236da2e3ebdSchin { 237da2e3ebdSchin register int n; 238da2e3ebdSchin register int flags = 0; 239da2e3ebdSchin register char* cp; 240da2e3ebdSchin register Sfio_t* fp; 241da2e3ebdSchin char* mode; 242da2e3ebdSchin int att; 243da2e3ebdSchin int dovcat=0; 244da2e3ebdSchin char states[UCHAR_MAX+1]; 245da2e3ebdSchin 246da2e3ebdSchin NoP(argc); 247da2e3ebdSchin cmdinit(argc, argv, context, ERROR_CATALOG, 0); 248da2e3ebdSchin att = !strcmp(astconf("UNIVERSE", NiL, NiL), "att"); 249da2e3ebdSchin mode = "r"; 250da2e3ebdSchin for (;;) 251da2e3ebdSchin { 252da2e3ebdSchin switch (optget(argv, usage)) 253da2e3ebdSchin { 254da2e3ebdSchin case 'A': 255da2e3ebdSchin flags |= T_FLAG|E_FLAG|V_FLAG; 256da2e3ebdSchin continue; 257da2e3ebdSchin case 'B': 258da2e3ebdSchin flags |= S_FLAG; 259da2e3ebdSchin continue; 260da2e3ebdSchin case 'b': 261da2e3ebdSchin flags |= B_FLAG; 262da2e3ebdSchin continue; 263da2e3ebdSchin case 'E': 264da2e3ebdSchin flags |= E_FLAG; 265da2e3ebdSchin continue; 266da2e3ebdSchin case 'e': 267da2e3ebdSchin flags |= E_FLAG|V_FLAG; 268da2e3ebdSchin continue; 269da2e3ebdSchin case 'n': 270da2e3ebdSchin flags |= N_FLAG; 271da2e3ebdSchin continue; 272da2e3ebdSchin case 's': 273da2e3ebdSchin flags |= att ? F_FLAG : S_FLAG; 274da2e3ebdSchin continue; 275da2e3ebdSchin case 'S': 276da2e3ebdSchin flags |= F_FLAG; 277da2e3ebdSchin continue; 278da2e3ebdSchin case 'T': 279da2e3ebdSchin flags |= T_FLAG; 280da2e3ebdSchin continue; 281da2e3ebdSchin case 't': 282da2e3ebdSchin flags |= T_FLAG|V_FLAG; 283da2e3ebdSchin continue; 284da2e3ebdSchin case 'u': 285da2e3ebdSchin flags |= U_FLAG; 286da2e3ebdSchin continue; 287da2e3ebdSchin case 'v': 288da2e3ebdSchin flags |= V_FLAG; 289da2e3ebdSchin continue; 290da2e3ebdSchin case 'd': 291da2e3ebdSchin mode = "rt"; 292da2e3ebdSchin continue; 293da2e3ebdSchin case 'D': 294da2e3ebdSchin flags |= d_FLAG; 295da2e3ebdSchin continue; 296da2e3ebdSchin case ':': 297da2e3ebdSchin error(2, "%s", opt_info.arg); 298da2e3ebdSchin break; 299da2e3ebdSchin case '?': 300da2e3ebdSchin error(ERROR_usage(2), "%s", opt_info.arg); 301da2e3ebdSchin break; 302da2e3ebdSchin } 303da2e3ebdSchin break; 304da2e3ebdSchin } 305da2e3ebdSchin argv += opt_info.index; 306da2e3ebdSchin if (error_info.errors) 307da2e3ebdSchin error(ERROR_usage(2), "%s", optusage(NiL)); 308da2e3ebdSchin memset(states, 0, sizeof(states)); 309da2e3ebdSchin if (flags&V_FLAG) 310da2e3ebdSchin { 311da2e3ebdSchin memset(states, T_CONTROL, ' '); 312da2e3ebdSchin states[RUBOUT] = T_CONTROL; 313da2e3ebdSchin memset(states+0200, T_EIGHTBIT, 0200); 314da2e3ebdSchin memset(states+0200, T_CNTL8BIT, ' '); 315da2e3ebdSchin states[RUBOUT|0200] = T_CNTL8BIT; 316da2e3ebdSchin states['\n'] = 0; 317da2e3ebdSchin } 318da2e3ebdSchin if (flags&T_FLAG) 319da2e3ebdSchin states['\t'] = T_CONTROL; 320da2e3ebdSchin states[0] = T_ENDBUF; 321da2e3ebdSchin if (att) 322da2e3ebdSchin { 323da2e3ebdSchin if (flags&V_FLAG) 324da2e3ebdSchin { 325da2e3ebdSchin states['\n'|0200] = T_EIGHTBIT; 326da2e3ebdSchin if (!(flags&T_FLAG)) 327da2e3ebdSchin { 328da2e3ebdSchin states['\t'] = states['\f'] = 0; 329da2e3ebdSchin states['\t'|0200] = states['\f'|0200] = T_EIGHTBIT; 330da2e3ebdSchin } 331da2e3ebdSchin } 332da2e3ebdSchin } 333da2e3ebdSchin else if (flags) 334da2e3ebdSchin { 335da2e3ebdSchin if (!(flags&T_FLAG)) 336da2e3ebdSchin states['\t'] = 0; 337da2e3ebdSchin } 338*7c2fbfb3SApril Chin if (flags&(V_FLAG|T_FLAG|N_FLAG|E_FLAG|B_FLAG|S_FLAG)) 339da2e3ebdSchin { 340da2e3ebdSchin states['\n'] = T_NEWLINE; 341da2e3ebdSchin dovcat = 1; 342da2e3ebdSchin } 343da2e3ebdSchin if (flags&B_FLAG) 344da2e3ebdSchin flags |= S_FLAG; 345da2e3ebdSchin if (flags&d_FLAG) 346da2e3ebdSchin sfopen(sfstdout, NiL, "wt"); 347da2e3ebdSchin if (cp = *argv) 348da2e3ebdSchin argv++; 349da2e3ebdSchin do 350da2e3ebdSchin { 351da2e3ebdSchin if (!cp || streq(cp,"-")) 352da2e3ebdSchin { 353da2e3ebdSchin fp = sfstdin; 354da2e3ebdSchin if (flags&D_FLAG) 355da2e3ebdSchin sfopen(fp, NiL, mode); 356da2e3ebdSchin } 357da2e3ebdSchin else if (!(fp = sfopen(NiL, cp, mode))) 358da2e3ebdSchin { 359da2e3ebdSchin if (!(flags&F_FLAG)) 360da2e3ebdSchin error(ERROR_system(0), "%s: cannot open", cp); 361da2e3ebdSchin error_info.errors = 1; 362da2e3ebdSchin continue; 363da2e3ebdSchin } 364da2e3ebdSchin if (flags&U_FLAG) 365da2e3ebdSchin sfsetbuf(fp, (void*)fp, -1); 366da2e3ebdSchin if (dovcat) 367da2e3ebdSchin n = vcat(states, fp, sfstdout, flags); 368da2e3ebdSchin else if (sfmove(fp, sfstdout, SF_UNBOUND, -1) >= 0 && sfeof(fp)) 369da2e3ebdSchin n = 0; 370da2e3ebdSchin else 371da2e3ebdSchin n = -1; 372da2e3ebdSchin if (fp != sfstdin) 373da2e3ebdSchin sfclose(fp); 374da2e3ebdSchin if (n < 0 && errno != EPIPE) 375da2e3ebdSchin { 376da2e3ebdSchin if (cp) 377da2e3ebdSchin error(ERROR_system(0), "%s: read error", cp); 378da2e3ebdSchin else 379da2e3ebdSchin error(ERROR_system(0), "read error"); 380da2e3ebdSchin } 381da2e3ebdSchin if (sferror(sfstdout)) 382da2e3ebdSchin break; 383da2e3ebdSchin } while (cp = *argv++); 384da2e3ebdSchin if (sfsync(sfstdout)) 385da2e3ebdSchin error(ERROR_system(0), "write error"); 386da2e3ebdSchin if (flags&d_FLAG) 387da2e3ebdSchin sfopen(sfstdout, NiL, "w"); 388da2e3ebdSchin return error_info.errors; 389da2e3ebdSchin } 390