Last active
September 27, 2024 05:42
-
-
Save sinclairtarget/47143ba52b9d9e360d8db3762ee0cbf5 to your computer and use it in GitHub Desktop.
cat through the ages
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
" cat | |
lac 017777 i " Load accumulator (AC) with argument count | |
sad d4 " Skip next if we have more than 4 words of args | |
jmp nofiles " Otherwise, jump to nofiles | |
lac 017777 " Load AC with address of args | |
tad d1 " Increment AC by 1, past argument count | |
tad d4 " Increment AC by 4, now AC points to first real arg | |
dac name " Save arg pointer from AC into 'name' | |
loop: | |
sys open; name: 0; 0 " Open filename in 'name' in read mode | |
spa " Skip next if AC is greater than 0 | |
jmp badfile " File descriptor is not positive, jump to badfile | |
dac fi " Save AC, now the file descriptor, in 'fi' | |
1: | |
jms getc " Call subroutine getc | |
sad o4 " Skip next if getc did not read EOF | |
jmp 1f " Read EOF, jump forward to 1 | |
jms putc " Call subroutine putc | |
jmp 1b " Jump back to 1 | |
1: | |
lac fi " Load AC with file descriptor | |
sys close " Close file | |
loop1: " Below we basically subtract 4 from our arg count | |
-4 " Maybe this should be 'lac -4'? Not sure | |
tad 017777 i " Increment AC by count of args left | |
dac 017777 i " Save AC to count of args left | |
sad d4 " Skip next if AC is not 4 | |
jmp done " No args left, jump to done | |
lac name " Load AC from name | |
tad d4 " Increment by 4 words | |
dac name " Save AC to name, name is now next arg | |
jmp loop " Jump back to loop | |
badfile: | |
lac name " Load AC with bad filename | |
dac 1f " Save filename to label 1 below | |
lac d8 " Load 8 into AC (point write to stderr?) | |
sys write; 1:0; 4 " Write four words of filename | |
lac d8 " Load 8 into AC again | |
sys write; 1f; 2 " Write ' ?\n' | |
jmp loop1 " Jump back to loop1 | |
1: 040;077012 " String literal ' ?\n' | |
nofiles: | |
lac d8 " Load 8 into AC (point write to stderr?) | |
sys write; 1f; 5 " Write 'no files\n' | |
sys exit | |
1: <no>; 040; <fi>;<le>;<s 012 " String literal 'no files\n' | |
done: " Flush the output buffer if necessary before exit | |
lac noc " Load AC with num chars left | |
sns " Skip next if num chars left is not zero (sna?) | |
sys exit " No chars left, exit | |
and d1 " binary AND with 1, check num chars left is odd? | |
sna cla " skip next if AC is not zero (num chars left is odd) | |
jmp 1f " num chars left is even, jump forward to 1 | |
jms putc " call putc | |
jmp done " go back up to 1 | |
1: | |
lac noc " Load AC with num chars left | |
rcr " Divide by two? | |
dac 1f " Store AC in label 1 below | |
lac fo " Load AC with file out descriptor | |
sys write; iopt+1; 1:.. " Write remaining chars | |
sys exit | |
getc: 0 | |
lac ipt " Load pointer to next word in buffer | |
sad eipt " Is pointer at end of input buffer? | |
jmp 1f " Yes, jump forward to 1, we need to read more | |
dac 2f " Not | |
add o400000 " so | |
dac ipt " sure | |
ral " about | |
lac 2f i " all | |
szl " this | |
lrss 9 | |
and o177 | |
sna | |
jmp getc+1 | |
jmp getc i | |
1: | |
lac fi " Buffer empty, load file descriptor into AC | |
sys read; iipt+1; 64 " Read into input buffer | |
sna " Skip next if AC is not zero | |
jmp 1f " We read zero characters, jump forward to 1 | |
tad iipt " Add chars read to input buffer base | |
dac eipt " Save result in end buffer pointer | |
lac iipt " Load base input buffer pointer | |
dac ipt " Store in input pointer (so reset ipt to iipt) | |
jmp getc+1 " Jump back to beginning of subroutine | |
1: | |
lac o4 " No chars left, return 4 (EOF?) | |
jmp getc i " Return | |
putc: 0 " Also not sure I understand what is going on here | |
and o177 | |
dac 2f+1 | |
lac opt | |
dac 2f | |
add o400000 | |
dac opt | |
spa | |
jmp 1f | |
lac 2f i | |
xor 2f+1 | |
jmp 3f | |
1: | |
lac 2f+1 | |
alss 9 | |
3: | |
dac 2f i | |
isz noc | |
lac noc | |
sad d128 | |
skp | |
jmp putc i | |
lac fo | |
sys write; iopt+1; 64 | |
lac iopt | |
dac opt | |
dzm noc | |
jmp putc i | |
2: 0;0 | |
ipt: 0 " Input pointer (points to next word) | |
eipt: 0 " Input buffer end pointer | |
iipt: .+1; .=.+64 " Input buffer base pointer and input buffer | |
fi: 0 | |
opt: .+2 | |
iopt: .+1; .=.+64 " Output buffer base pointer and output buffer | |
noc: 0 " num chars queued to write | |
fo: 1 | |
d1: 1 " Octal and decimal constants? | |
o4:d4: 4 | |
d8: 8 | |
o400000: 0400000 | |
o177: 0177 | |
d128: 128 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/ cat -- concatinate files | |
mov (sp)+,r5 / Pop argument count off stack and save in r5 | |
tst (sp)+ / Pop first argument and discard it | |
mov $obuf,r2 / Store address of output buffer in r2 | |
cmp r5,$1 / Is argument count 1? | |
beq 3f / If argument count was 1, jump to 3 below | |
loop: | |
dec r5 / Decrement argument count | |
ble done / If argument count is <= 0, jump to done | |
mov (sp)+,r0 / Pop next argument and save in r0 | |
cmpb (r0),$'- / Is next argument "-"? | |
bne 2f / If next argument was not "-", jump down to 2 | |
clr fin / Clear file descriptor | |
br 3f / Jump down to 3 | |
2: | |
mov r0,0f / Store file name in r0 at label 0 right below | |
sys open; 0:..; 0 / Open file in read mode (r0 now file descriptor) | |
bes loop / If error opening file, jump to loop | |
mov r0,fin / Save file descriptor to fin | |
3: | |
mov fin,r0 / Copy file descriptor to r0 | |
sys read; ibuf; 512. / Read from file descriptor in r0 into input buffer | |
bes 3f / Jump forward to 3 on error | |
mov r0,r4 / r0 now contains bytes read, save in r4 | |
beq 3f / If bytes read was zero, jump down to 3 | |
mov $ibuf,r3 / Copy address of input buffer to r3 | |
4: | |
movb (r3)+,r0 / Copy byte from input buffer to r0, auto-increment | |
jsr pc,putc / Call putc subroutine | |
dec r4 / Decrement r4 (bytes read/left to write) | |
bne 4b / If there are bytes left, jump back to 4 | |
br 3b / Otherwise, jump back to 3 | |
3: | |
mov fin,r0 / Copy file descriptor to r0 | |
beq loop / If file descriptor was 0 (stdin), jump to loop | |
sys close / Otherwise close file descriptor | |
br loop / Jump to loop | |
done: | |
sub $obuf,r2 / Do we still have anything in the output buffer? | |
beq 1f / If no, jump down to 1 | |
mov r2,0f / Copy bytes left to flush to label 0 below | |
mov $1,r0 / Set up to write to stdout | |
sys write; obuf; 0:.. / Write remaining bytes to stdout | |
1: | |
sys exit | |
putc: | |
movb r0,(r2)+ / Copy byte from input to output buffer | |
cmp r2,$obuf+512. / Check output buffer size | |
blo 1f / If output buffer is not full, jump down to 1 | |
mov $1,r0 / Set up to write to stdout | |
sys write; obuf; 512. / Write output buffer | |
mov $obuf,r2 / Reset output buffer index | |
1: | |
rts pc / Return from subroutine | |
.bss | |
ibuf: .=.+512. / Input buffer | |
obuf: .=.+512. / Output buffer | |
fin: .=.+2 / Input file descriptor | |
.text | |
/ Not sure why this is here, seems to just repeat code from above? | |
/ Next line doesn't look like a complete statement | |
,$'- | |
bne 2f | |
clr fin | |
br 3f | |
2: | |
mov r0,0f | |
sys open; 0:..; 0 | |
bes loop | |
mov r0,fin | |
3: | |
mov fin,r0 | |
sys read; ibuf; 512. | |
bes 3f | |
mov r0,r4 | |
beq 3f | |
mov $ibuf,r3 | |
4: | |
movb (r3)+,r0 | |
jsr pc,putc | |
dec r4 | |
bne 4b | |
br 3b | |
3: | |
mov fin,r0 | |
beq loop | |
sys close | |
br loop | |
done: | |
sub $obuf,r2 | |
beq 1f | |
mov r2,0f | |
mov $1,r0 | |
sys write; obuf; 0:.. | |
1: | |
sys exit | |
putc: | |
movb r0,(r2)+ | |
cmp r2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Concatenate files. | |
*/ | |
#include <stdio.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
/* All comments below this one not in the original file. */ | |
char stdbuf[BUFSIZ]; /* BUFSIZ is typically 512, according to man page. */ | |
/* Old style function declaration. Return type defaults to int. Param types | |
* default to int. You can specify param types (when not int) after the | |
* parentheses like below. | |
*/ | |
main(argc, argv) | |
char **argv; | |
{ | |
int fflg = 0; /* Flag set to 1 if reading from stdin */ | |
register FILE *fi; /* File handle */ | |
register c; /* Current char */ | |
int dev, ino = -1; /* Keep track of file inodes */ | |
struct stat statb; /* File status struct */ | |
/* Handle -u flag */ | |
setbuf(stdout, stdbuf); | |
for( ; argc>1 && argv[1][0]=='-'; argc--,argv++) { | |
switch(argv[1][1]) { | |
case 0: | |
break; | |
case 'u': /* -u flag means don't buffer */ | |
setbuf(stdout, (char *)NULL); | |
continue; | |
} | |
break; | |
} | |
fstat(fileno(stdout), &statb); /* Get file status. */ | |
statb.st_mode &= S_IFMT; /* Use mask to get file type. */ | |
/* If file is not "character special" or "block special"... */ | |
if (statb.st_mode!=S_IFCHR && statb.st_mode!=S_IFBLK) { | |
/* Save file inode data in local vars */ | |
dev = statb.st_dev; | |
ino = statb.st_ino; | |
} | |
if (argc < 2) { | |
argc = 2; | |
fflg++; /* We're reading from stdin */ | |
} | |
while (--argc > 0) { | |
if (fflg || (*++argv)[0]=='-' && (*argv)[1]=='\0') | |
fi = stdin; | |
else { | |
if ((fi = fopen(*argv, "r")) == NULL) { | |
fprintf(stderr, "cat: can't open %s\n", *argv); | |
continue; | |
} | |
} | |
fstat(fileno(fi), &statb); | |
/* Check if we're reading from and writing to same file */ | |
if (statb.st_dev==dev && statb.st_ino==ino) { | |
fprintf(stderr, "cat: input %s is output\n", | |
fflg?"-": *argv); | |
fclose(fi); | |
continue; | |
} | |
while ((c = getc(fi)) != EOF) | |
putchar(c); | |
if (fi!=stdin) | |
fclose(fi); | |
} | |
return(0); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Concatenate files. | |
*/ | |
static char *Sccsid = "@(#)cat.c 4.2 (Berkeley) 10/9/80"; | |
#include <stdio.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
/* All comments below this one not in the original file. */ | |
char stdbuf[BUFSIZ]; | |
int bflg, eflg, nflg, sflg, tflg, vflg; | |
int spaced, col, lno, inline; | |
main(argc, argv) | |
char **argv; | |
{ | |
int fflg = 0; | |
register FILE *fi; | |
register c; | |
int dev, ino = -1; | |
struct stat statb; | |
lno = 1; | |
setbuf(stdout, stdbuf); | |
for( ; argc>1 && argv[1][0]=='-'; argc--,argv++) { | |
switch(argv[1][1]) { | |
case 0: | |
break; | |
case 'u': /* Don't buffer */ | |
setbuf(stdout, (char *)NULL); | |
continue; | |
case 'n': /* Print with line numbers */ | |
nflg++; | |
continue; | |
case 'b': /* Omit line numbers from blank lines */ | |
bflg++; | |
nflg++; | |
continue; | |
case 'v': /* Print control characters */ | |
vflg++; | |
continue; | |
case 's': /* Collapse multiple adjacent blank lines */ | |
sflg++; | |
continue; | |
case 'e': /* Print '$' after lines */ | |
eflg++; | |
vflg++; | |
continue; | |
case 't': /* Print tabs as '^I' */ | |
tflg++; | |
vflg++; | |
continue; | |
} | |
break; | |
} | |
fstat(fileno(stdout), &statb); | |
statb.st_mode &= S_IFMT; | |
if (statb.st_mode!=S_IFCHR && statb.st_mode!=S_IFBLK) { | |
dev = statb.st_dev; | |
ino = statb.st_ino; | |
} | |
if (argc < 2) { | |
argc = 2; | |
fflg++; | |
} | |
while (--argc > 0) { | |
if (fflg || (*++argv)[0]=='-' && (*argv)[1]=='\0') | |
fi = stdin; | |
else { | |
if ((fi = fopen(*argv, "r")) == NULL) { | |
fprintf(stderr, "cat: can't open %s\n", *argv); | |
continue; | |
} | |
} | |
fstat(fileno(fi), &statb); | |
if (statb.st_dev==dev && statb.st_ino==ino) { | |
fprintf(stderr, "cat: input %s is output\n", | |
fflg?"-": *argv); | |
fclose(fi); | |
continue; | |
} | |
if (nflg||sflg||vflg) | |
copyopt(fi); | |
else { | |
while ((c = getc(fi)) != EOF) | |
putchar(c); | |
} | |
if (fi!=stdin) | |
fclose(fi); | |
} | |
if (ferror(stdout)) | |
fprintf(stderr, "cat: output write error\n"); | |
return(0); | |
} | |
copyopt(f) | |
register FILE *f; | |
{ | |
register int c; | |
top: | |
c = getc(f); | |
if (c == EOF) | |
return; | |
if (c == '\n') { | |
if (inline == 0) { | |
if (sflg && spaced) | |
goto top; | |
spaced = 1; | |
} | |
if (nflg && bflg==0 && inline == 0) | |
printf("%6d\t", lno++); | |
if (eflg) | |
putchar('$'); | |
putchar('\n'); | |
inline = 0; | |
goto top; | |
} | |
if (nflg && inline == 0) | |
printf("%6d\t", lno++); | |
inline = 1; | |
if (vflg) { | |
if (tflg==0 && c == '\t') | |
putchar(c); | |
else { | |
if (c > 0177) { | |
printf("M-"); | |
c &= 0177; | |
} | |
if (c < ' ') | |
printf("^%c", c+'@'); | |
else if (c == 0177) | |
printf("^?"); | |
else | |
putchar(c); | |
} | |
} else | |
putchar(c); | |
spaced = 0; | |
goto top; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 1989 The Regents of the University of California. | |
* All rights reserved. | |
* | |
* This code is derived from software contributed to Berkeley by | |
* Kevin Fall. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* 3. All advertising materials mentioning features or use of this software | |
* must display the following acknowledgement: | |
* This product includes software developed by the University of | |
* California, Berkeley and its contributors. | |
* 4. Neither the name of the University nor the names of its contributors | |
* may be used to endorse or promote products derived from this software | |
* without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
* SUCH DAMAGE. | |
*/ | |
#ifndef lint | |
char copyright[] = | |
"@(#) Copyright (c) 1989 The Regents of the University of California.\n\ | |
All rights reserved.\n"; | |
#endif /* not lint */ | |
#ifndef lint | |
static char sccsid[] = "@(#)cat.c 5.15 (Berkeley) 5/23/91"; | |
#endif /* not lint */ | |
#include <sys/param.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <errno.h> | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <ctype.h> | |
/* Most comments after this one not in the original */ | |
int bflag, eflag, nflag, sflag, tflag, vflag; | |
int rval; /* Program exit code */ | |
char *filename; | |
void cook_args(), cook_buf(), raw_args(), raw_cat(); | |
void err __P((int, const char *, ...)); | |
main(argc, argv) | |
int argc; | |
char **argv; | |
{ | |
extern int optind; /* Set by getopt() to number of options passed */ | |
int ch; /* Command-line flag character */ | |
while ((ch = getopt(argc, argv, "benstuv")) != EOF) | |
switch (ch) { | |
case 'b': | |
bflag = nflag = 1; /* -b implies -n */ | |
break; | |
case 'e': | |
eflag = vflag = 1; /* -e implies -v */ | |
break; | |
case 'n': | |
nflag = 1; | |
break; | |
case 's': | |
sflag = 1; | |
break; | |
case 't': | |
tflag = vflag = 1; /* -t implies -v */ | |
break; | |
case 'u': | |
setbuf(stdout, (char *)NULL); | |
break; | |
case 'v': | |
vflag = 1; | |
break; | |
case '?': | |
(void)fprintf(stderr, | |
"usage: cat [-benstuv] [-] [file ...]\n"); | |
exit(1); | |
} | |
argv += optind; /* Increment past all options */ | |
if (bflag || eflag || nflag || sflag || tflag || vflag) | |
cook_args(argv); | |
else | |
raw_args(argv); | |
if (fclose(stdout)) | |
err(1, "stdout: %s", strerror(errno)); | |
exit(rval); | |
} | |
/* Process file arguments and feed to "cooked" mode of cat */ | |
void | |
cook_args(argv) | |
char **argv; | |
{ | |
register FILE *fp; | |
fp = stdin; | |
filename = "stdin"; | |
do { | |
if (*argv) { | |
if (!strcmp(*argv, "-")) | |
fp = stdin; | |
else if (!(fp = fopen(*argv, "r"))) { | |
err(0, "%s: %s", *argv, strerror(errno)); | |
++argv; | |
continue; | |
} | |
filename = *argv++; | |
} | |
cook_buf(fp); | |
if (fp != stdin) | |
(void)fclose(fp); | |
} while (*argv); | |
} | |
/* "Cooked" mode of cat, i.e. prepared and seasoned. Have to handle all the | |
* different combinations of command-line flags */ | |
void | |
cook_buf(fp) | |
register FILE *fp; | |
{ | |
register int ch, gobble, line, prev; | |
line = gobble = 0; | |
for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { | |
if (prev == '\n') { | |
if (ch == '\n') { | |
if (sflag) { | |
if (!gobble && putchar(ch) == EOF) | |
break; | |
gobble = 1; | |
continue; | |
} | |
if (nflag && !bflag) { | |
(void)fprintf(stdout, "%6d\t", ++line); | |
if (ferror(stdout)) | |
break; | |
} | |
} else if (nflag) { | |
(void)fprintf(stdout, "%6d\t", ++line); | |
if (ferror(stdout)) | |
break; | |
} | |
} | |
gobble = 0; | |
if (ch == '\n') { | |
if (eflag) | |
if (putchar('$') == EOF) | |
break; | |
} else if (ch == '\t') { | |
if (tflag) { | |
if (putchar('^') == EOF || putchar('I') == EOF) | |
break; | |
continue; | |
} | |
} else if (vflag) { | |
if (!isascii(ch)) { | |
if (putchar('M') == EOF || putchar('-') == EOF) | |
break; | |
ch = toascii(ch); | |
} | |
if (iscntrl(ch)) { | |
if (putchar('^') == EOF || | |
putchar(ch == '\177' ? '?' : | |
ch | 0100) == EOF) | |
break; | |
continue; | |
} | |
} | |
if (putchar(ch) == EOF) | |
break; | |
} | |
if (ferror(fp)) { | |
err(0, "%s: %s", strerror(errno)); | |
clearerr(fp); | |
} | |
if (ferror(stdout)) | |
err(1, "stdout: %s", strerror(errno)); | |
} | |
/* Process file arguments and feed to "raw" mode of cat */ | |
void | |
raw_args(argv) | |
char **argv; | |
{ | |
register int fd; | |
fd = fileno(stdin); | |
filename = "stdin"; | |
do { | |
if (*argv) { | |
if (!strcmp(*argv, "-")) | |
fd = fileno(stdin); | |
else if ((fd = open(*argv, O_RDONLY, 0)) < 0) { | |
err(0, "%s: %s", *argv, strerror(errno)); | |
++argv; | |
continue; | |
} | |
filename = *argv++; | |
} | |
raw_cat(fd); | |
if (fd != fileno(stdin)) | |
(void)close(fd); | |
} while (*argv); | |
} | |
/* "Raw" mode cat -- no special handling, just print char for char */ | |
void | |
raw_cat(rfd) | |
register int rfd; | |
{ | |
register int nr, nw, off, wfd; | |
static int bsize; | |
static char *buf; | |
struct stat sbuf; | |
wfd = fileno(stdout); | |
if (!buf) { | |
if (fstat(wfd, &sbuf)) | |
err(1, "%s: %s", filename, strerror(errno)); | |
bsize = MAX(sbuf.st_blksize, 1024); | |
if (!(buf = malloc((u_int)bsize))) | |
err(1, "%s", strerror(errno)); | |
} | |
while ((nr = read(rfd, buf, bsize)) > 0) | |
for (off = 0; off < nr; nr -= nw, off += nw) | |
if ((nw = write(wfd, buf + off, nr)) < 0) | |
err(1, "stdout"); | |
if (nr < 0) | |
err(0, "%s: %s", filename, strerror(errno)); | |
} | |
/* Error handling function err(), with some conditional compilation based on | |
* available libraries, it looks like */ | |
#if __STDC__ | |
#include <stdarg.h> | |
#else | |
#include <varargs.h> | |
#endif | |
void | |
#if __STDC__ | |
err(int ex, const char *fmt, ...) | |
#else | |
err(ex, fmt, va_alist) | |
int ex; | |
char *fmt; | |
va_dcl | |
#endif | |
{ | |
va_list ap; | |
#if __STDC__ | |
va_start(ap, fmt); | |
#else | |
va_start(ap); | |
#endif | |
(void)fprintf(stderr, "cat: "); | |
(void)vfprintf(stderr, fmt, ap); | |
va_end(ap); | |
(void)fprintf(stderr, "\n"); | |
if (ex) | |
exit(1); | |
rval = 1; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* $NetBSD: cat.c,v 1.18 1998/07/28 05:31:22 mycroft Exp $ */ | |
/* | |
* Copyright (c) 1989, 1993 | |
* The Regents of the University of California. All rights reserved. | |
* | |
* This code is derived from software contributed to Berkeley by | |
* Kevin Fall. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* 3. All advertising materials mentioning features or use of this software | |
* must display the following acknowledgement: | |
* This product includes software developed by the University of | |
* California, Berkeley and its contributors. | |
* 4. Neither the name of the University nor the names of its contributors | |
* may be used to endorse or promote products derived from this software | |
* without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
* SUCH DAMAGE. | |
*/ | |
#include <sys/cdefs.h> | |
#ifndef lint | |
__COPYRIGHT( | |
"@(#) Copyright (c) 1989, 1993\n\ | |
The Regents of the University of California. All rights reserved.\n"); | |
#endif /* not lint */ | |
#ifndef lint | |
#if 0 | |
static char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95"; | |
#else | |
__RCSID("$NetBSD: cat.c,v 1.18 1998/07/28 05:31:22 mycroft Exp $"); | |
#endif | |
#endif /* not lint */ | |
#include <sys/param.h> | |
#include <sys/stat.h> | |
#include <locale.h> | |
#include <ctype.h> | |
#include <err.h> | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
int bflag, eflag, nflag, sflag, tflag, vflag; | |
int rval; | |
char *filename; | |
int main __P((int, char *[])); | |
void cook_args __P((char *argv[])); | |
void cook_buf __P((FILE *)); | |
void raw_args __P((char *argv[])); | |
void raw_cat __P((int)); | |
int | |
main(argc, argv) | |
int argc; | |
char *argv[]; | |
{ | |
extern int optind; | |
int ch; | |
(void)setlocale(LC_ALL, ""); | |
while ((ch = getopt(argc, argv, "benstuv")) != -1) | |
switch (ch) { | |
case 'b': | |
bflag = nflag = 1; /* -b implies -n */ | |
break; | |
case 'e': | |
eflag = vflag = 1; /* -e implies -v */ | |
break; | |
case 'n': | |
nflag = 1; | |
break; | |
case 's': | |
sflag = 1; | |
break; | |
case 't': | |
tflag = vflag = 1; /* -t implies -v */ | |
break; | |
case 'u': | |
setbuf(stdout, (char *)NULL); | |
break; | |
case 'v': | |
vflag = 1; | |
break; | |
default: | |
case '?': | |
(void)fprintf(stderr, | |
"usage: cat [-benstuv] [-] [file ...]\n"); | |
exit(1); | |
/* NOTREACHED */ | |
} | |
argv += optind; | |
if (bflag || eflag || nflag || sflag || tflag || vflag) | |
cook_args(argv); | |
else | |
raw_args(argv); | |
if (fclose(stdout)) | |
err(1, "stdout"); | |
exit(rval); | |
/* NOTREACHED */ | |
} | |
void | |
cook_args(argv) | |
char **argv; | |
{ | |
FILE *fp; | |
fp = stdin; | |
filename = "stdin"; | |
do { | |
if (*argv) { | |
if (!strcmp(*argv, "-")) | |
fp = stdin; | |
else if ((fp = fopen(*argv, "r")) == NULL) { | |
warn("%s", *argv); | |
rval = 1; | |
++argv; | |
continue; | |
} | |
filename = *argv++; | |
} | |
cook_buf(fp); | |
if (fp != stdin) | |
(void)fclose(fp); | |
} while (*argv); | |
} | |
void | |
cook_buf(fp) | |
FILE *fp; | |
{ | |
int ch, gobble, line, prev; | |
line = gobble = 0; | |
for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { | |
if (prev == '\n') { | |
if (ch == '\n') { | |
if (sflag) { | |
if (!gobble && putchar(ch) == EOF) | |
break; | |
gobble = 1; | |
continue; | |
} | |
if (nflag) { | |
if (!bflag) { | |
(void)fprintf(stdout, | |
"%6d\t", ++line); | |
if (ferror(stdout)) | |
break; | |
} else if (eflag) { | |
(void)fprintf(stdout, | |
"%6s\t", ""); | |
if (ferror(stdout)) | |
break; | |
} | |
} | |
} else if (nflag) { | |
(void)fprintf(stdout, "%6d\t", ++line); | |
if (ferror(stdout)) | |
break; | |
} | |
} | |
gobble = 0; | |
if (ch == '\n') { | |
if (eflag) | |
if (putchar('$') == EOF) | |
break; | |
} else if (ch == '\t') { | |
if (tflag) { | |
if (putchar('^') == EOF || putchar('I') == EOF) | |
break; | |
continue; | |
} | |
} else if (vflag) { | |
if (!isascii(ch)) { | |
if (putchar('M') == EOF || putchar('-') == EOF) | |
break; | |
ch = toascii(ch); | |
} | |
if (iscntrl(ch)) { | |
if (putchar('^') == EOF || | |
putchar(ch == '\177' ? '?' : | |
ch | 0100) == EOF) | |
break; | |
continue; | |
} | |
} | |
if (putchar(ch) == EOF) | |
break; | |
} | |
if (ferror(fp)) { | |
warn("%s", filename); | |
rval = 1; | |
clearerr(fp); | |
} | |
if (ferror(stdout)) | |
err(1, "stdout"); | |
} | |
void | |
raw_args(argv) | |
char **argv; | |
{ | |
int fd; | |
fd = fileno(stdin); | |
filename = "stdin"; | |
do { | |
if (*argv) { | |
if (!strcmp(*argv, "-")) | |
fd = fileno(stdin); | |
else if ((fd = open(*argv, O_RDONLY, 0)) < 0) { | |
warn("%s", *argv); | |
rval = 1; | |
++argv; | |
continue; | |
} | |
filename = *argv++; | |
} | |
raw_cat(fd); | |
if (fd != fileno(stdin)) | |
(void)close(fd); | |
} while (*argv); | |
} | |
void | |
raw_cat(rfd) | |
int rfd; | |
{ | |
int nr, nw, off, wfd; | |
static int bsize; | |
static char *buf; | |
struct stat sbuf; | |
wfd = fileno(stdout); | |
if (buf == NULL) { | |
if (fstat(wfd, &sbuf)) | |
err(1, "%s", filename); | |
bsize = MAX(sbuf.st_blksize, 1024); | |
if ((buf = malloc((u_int)bsize)) == NULL) | |
err(1, "cannot allocate buffer"); | |
} | |
while ((nr = read(rfd, buf, (u_int)bsize)) > 0) | |
for (off = 0; nr; nr -= nw, off += nw) | |
if ((nw = write(wfd, buf + off, (u_int)nr)) < 0) | |
err(1, "stdout"); | |
if (nr < 0) { | |
warn("%s", filename); | |
rval = 1; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*- | |
* Copyright (c) 1989, 1993 | |
* The Regents of the University of California. All rights reserved. | |
* | |
* This code is derived from software contributed to Berkeley by | |
* Kevin Fall. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* 4. Neither the name of the University nor the names of its contributors | |
* may be used to endorse or promote products derived from this software | |
* without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
* SUCH DAMAGE. | |
*/ | |
#if 0 | |
#ifndef lint | |
static char const copyright[] = | |
"@(#) Copyright (c) 1989, 1993\n\ | |
The Regents of the University of California. All rights reserved.\n"; | |
#endif /* not lint */ | |
#endif | |
#ifndef lint | |
#if 0 | |
static char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95"; | |
#endif | |
#endif /* not lint */ | |
#include <sys/cdefs.h> | |
__FBSDID("$FreeBSD: src/bin/cat/cat.c,v 1.32 2005/01/10 08:39:20 imp Exp $"); | |
#include <sys/param.h> | |
#include <sys/stat.h> | |
#ifndef NO_UDOM_SUPPORT | |
#include <sys/socket.h> | |
#include <sys/un.h> | |
#include <errno.h> | |
#endif | |
#include <ctype.h> | |
#include <err.h> | |
#include <fcntl.h> | |
#include <locale.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <stddef.h> | |
int bflag, eflag, nflag, sflag, tflag, vflag; | |
int rval; | |
const char *filename; | |
static void usage(void); | |
static void scanfiles(char *argv[], int cooked); | |
static void cook_cat(FILE *); | |
static void raw_cat(int); | |
#ifndef NO_UDOM_SUPPORT | |
static int udom_open(const char *path, int flags); | |
#endif | |
int | |
main(int argc, char *argv[]) | |
{ | |
int ch; | |
setlocale(LC_CTYPE, ""); | |
while ((ch = getopt(argc, argv, "benstuv")) != -1) | |
switch (ch) { | |
case 'b': | |
bflag = nflag = 1; /* -b implies -n */ | |
break; | |
case 'e': | |
eflag = vflag = 1; /* -e implies -v */ | |
break; | |
case 'n': | |
nflag = 1; | |
break; | |
case 's': | |
sflag = 1; | |
break; | |
case 't': | |
tflag = vflag = 1; /* -t implies -v */ | |
break; | |
case 'u': | |
setbuf(stdout, NULL); | |
break; | |
case 'v': | |
vflag = 1; | |
break; | |
default: | |
usage(); | |
} | |
argv += optind; | |
if (bflag || eflag || nflag || sflag || tflag || vflag) | |
scanfiles(argv, 1); | |
else | |
scanfiles(argv, 0); | |
if (fclose(stdout)) | |
err(1, "stdout"); | |
exit(rval); | |
/* NOTREACHED */ | |
} | |
static void | |
usage(void) | |
{ | |
fprintf(stderr, "usage: cat [-benstuv] [file ...]\n"); | |
exit(1); | |
/* NOTREACHED */ | |
} | |
static void | |
scanfiles(char *argv[], int cooked) | |
{ | |
int i = 0; | |
char *path; | |
FILE *fp; | |
while ((path = argv[i]) != NULL || i == 0) { | |
int fd; | |
if (path == NULL || strcmp(path, "-") == 0) { | |
filename = "stdin"; | |
fd = STDIN_FILENO; | |
} else { | |
filename = path; | |
fd = open(path, O_RDONLY); | |
#ifndef NO_UDOM_SUPPORT | |
if (fd < 0 && errno == EOPNOTSUPP) | |
fd = udom_open(path, O_RDONLY); | |
#endif | |
} | |
if (fd < 0) { | |
warn("%s", path); | |
rval = 1; | |
} else if (cooked) { | |
if (fd == STDIN_FILENO) | |
cook_cat(stdin); | |
else { | |
fp = fdopen(fd, "r"); | |
cook_cat(fp); | |
fclose(fp); | |
} | |
} else { | |
raw_cat(fd); | |
if (fd != STDIN_FILENO) | |
close(fd); | |
} | |
if (path == NULL) | |
break; | |
++i; | |
} | |
} | |
static void | |
cook_cat(FILE *fp) | |
{ | |
int ch, gobble, line, prev; | |
/* Reset EOF condition on stdin. */ | |
if (fp == stdin && feof(stdin)) | |
clearerr(stdin); | |
line = gobble = 0; | |
for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) { | |
if (prev == '\n') { | |
if (sflag) { | |
if (ch == '\n') { | |
if (gobble) | |
continue; | |
gobble = 1; | |
} else | |
gobble = 0; | |
} | |
if (nflag && (!bflag || ch != '\n')) { | |
(void)fprintf(stdout, "%6d\t", ++line); | |
if (ferror(stdout)) | |
break; | |
} | |
} | |
if (ch == '\n') { | |
if (eflag && putchar('$') == EOF) | |
break; | |
} else if (ch == '\t') { | |
if (tflag) { | |
if (putchar('^') == EOF || putchar('I') == EOF) | |
break; | |
continue; | |
} | |
} else if (vflag) { | |
if (!isascii(ch) && !isprint(ch)) { | |
if (putchar('M') == EOF || putchar('-') == EOF) | |
break; | |
ch = toascii(ch); | |
} | |
if (iscntrl(ch)) { | |
if (putchar('^') == EOF || | |
putchar(ch == '\177' ? '?' : | |
ch | 0100) == EOF) | |
break; | |
continue; | |
} | |
} | |
if (putchar(ch) == EOF) | |
break; | |
} | |
if (ferror(fp)) { | |
warn("%s", filename); | |
rval = 1; | |
clearerr(fp); | |
} | |
if (ferror(stdout)) | |
err(1, "stdout"); | |
} | |
static void | |
raw_cat(int rfd) | |
{ | |
int off, wfd; | |
ssize_t nr, nw; | |
static size_t bsize; | |
static char *buf = NULL; | |
struct stat sbuf; | |
wfd = fileno(stdout); | |
if (buf == NULL) { | |
if (fstat(wfd, &sbuf)) | |
err(1, "%s", filename); | |
bsize = MAX(sbuf.st_blksize, 1024); | |
if ((buf = malloc(bsize)) == NULL) | |
err(1, "buffer"); | |
} | |
while ((nr = read(rfd, buf, bsize)) > 0) | |
for (off = 0; nr; nr -= nw, off += nw) | |
if ((nw = write(wfd, buf + off, (size_t)nr)) < 0) | |
err(1, "stdout"); | |
if (nr < 0) { | |
warn("%s", filename); | |
rval = 1; | |
} | |
} | |
#ifndef NO_UDOM_SUPPORT | |
static int | |
udom_open(const char *path, int flags) | |
{ | |
struct sockaddr_un sou; | |
int fd; | |
unsigned int len; | |
bzero(&sou, sizeof(sou)); | |
/* | |
* Construct the unix domain socket address and attempt to connect | |
*/ | |
fd = socket(AF_UNIX, SOCK_STREAM, 0); | |
if (fd >= 0) { | |
sou.sun_family = AF_UNIX; | |
if ((len = strlcpy(sou.sun_path, path, | |
sizeof(sou.sun_path))) >= sizeof(sou.sun_path)) { | |
errno = ENAMETOOLONG; | |
return (-1); | |
} | |
len = offsetof(struct sockaddr_un, sun_path[len+1]); | |
if (connect(fd, (void *)&sou, len) < 0) { | |
close(fd); | |
fd = -1; | |
} | |
} | |
/* | |
* handle the open flags by shutting down appropriate directions | |
*/ | |
if (fd >= 0) { | |
switch(flags & O_ACCMODE) { | |
case O_RDONLY: | |
if (shutdown(fd, SHUT_WR) == -1) | |
warn(NULL); | |
break; | |
case O_WRONLY: | |
if (shutdown(fd, SHUT_RD) == -1) | |
warn(NULL); | |
break; | |
default: | |
break; | |
} | |
} | |
return(fd); | |
} | |
#endif |
nice
666 ,thanks.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Very instructive, thank you.
You might wish to add illumos (Solaris) version.