Instantly share code, notes, and snippets.

Embed
What would you like to do?
cat through the ages
" 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
/ 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
/*
* 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);
}
/*
* 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;
}
/*
* 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;
}
/* $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;
}
}
/*-
* 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
@priyadarshan

This comment has been minimized.

Copy link

priyadarshan commented Nov 13, 2018

Very instructive, thank you.

You might wish to add illumos (Solaris) version.

@nilname

This comment has been minimized.

Copy link

nilname commented Jan 3, 2019

nice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment