mirror of
https://git.suckless.org/9base
synced 2025-08-29 19:33:47 -07:00
added read to 9base
This commit is contained in:
2
Makefile
2
Makefile
@@ -4,7 +4,7 @@
|
||||
include config.mk
|
||||
|
||||
SUBDIRS = lib9 yacc awk basename bc dc cat cleanname date echo grep mk \
|
||||
rc sed seq sleep sort tee test touch tr uniq
|
||||
rc read sed seq sleep sort tee test touch tr uniq
|
||||
|
||||
all:
|
||||
@echo 9base build options:
|
||||
|
6
read/Makefile
Normal file
6
read/Makefile
Normal file
@@ -0,0 +1,6 @@
|
||||
# read - read unix port from plan9
|
||||
# Depends on ../lib9
|
||||
|
||||
TARG = read
|
||||
|
||||
include ../std.mk
|
108
read/read.1
Normal file
108
read/read.1
Normal file
@@ -0,0 +1,108 @@
|
||||
.TH CAT 1
|
||||
.SH NAME
|
||||
cat, read, nobs \- catenate files
|
||||
.SH SYNOPSIS
|
||||
.B cat
|
||||
[
|
||||
.I file ...
|
||||
]
|
||||
.br
|
||||
.B read
|
||||
[
|
||||
.B -m
|
||||
] [
|
||||
.B -n
|
||||
.I nline
|
||||
] [
|
||||
.I file ...
|
||||
]
|
||||
.br
|
||||
.B nobs
|
||||
[
|
||||
.I file ...
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.I Cat
|
||||
reads each
|
||||
.I file
|
||||
in sequence and writes it on the standard output.
|
||||
Thus
|
||||
.IP
|
||||
.L
|
||||
cat file
|
||||
.LP
|
||||
prints a file and
|
||||
.IP
|
||||
.L
|
||||
cat file1 file2 >file3
|
||||
.LP
|
||||
concatenates the first two files and places the result
|
||||
on the third.
|
||||
.PP
|
||||
If no
|
||||
.I file
|
||||
is given,
|
||||
.I cat
|
||||
reads from the standard input.
|
||||
Output is buffered in blocks matching the input.
|
||||
.PP
|
||||
.I Read
|
||||
copies to standard output exactly one line from the named
|
||||
.IR file ,
|
||||
default standard input.
|
||||
It is useful in interactive
|
||||
.IR rc (1)
|
||||
scripts.
|
||||
.PP
|
||||
The
|
||||
.B -m
|
||||
flag causes it to continue reading and writing multiple lines until end of file;
|
||||
.B -n
|
||||
causes it to read no more than
|
||||
.I nline
|
||||
lines.
|
||||
.PP
|
||||
.I Read
|
||||
always executes a single
|
||||
.B write
|
||||
for each line of input, which can be helpful when
|
||||
preparing input to programs that expect line-at-a-time data.
|
||||
It never reads any more data from the input than it prints to the output.
|
||||
.PP
|
||||
.I Nobs
|
||||
copies the named files to
|
||||
standard output except that it removes all backspace
|
||||
characters and the characters that precede them.
|
||||
It is useful to use as
|
||||
.B $PAGER
|
||||
with the Unix version of
|
||||
.IR man (1)
|
||||
when run inside a
|
||||
.I win
|
||||
(see
|
||||
.IR acme (1))
|
||||
window.
|
||||
.SH SOURCE
|
||||
.B \*9/src/cmd/cat.c
|
||||
.br
|
||||
.B \*9/src/cmd/read.c
|
||||
.br
|
||||
.B \*9/bin/nobs
|
||||
.SH SEE ALSO
|
||||
.IR cp (1)
|
||||
.SH DIAGNOSTICS
|
||||
.I Read
|
||||
exits with status
|
||||
.B eof
|
||||
on end of file or, in the
|
||||
.B -n
|
||||
case, if it doesn't read
|
||||
.I nlines
|
||||
lines.
|
||||
.SH BUGS
|
||||
Beware of
|
||||
.L "cat a b >a"
|
||||
and
|
||||
.LR "cat a b >b" ,
|
||||
which
|
||||
destroy input files before reading them.
|
91
read/read.c
Normal file
91
read/read.c
Normal file
@@ -0,0 +1,91 @@
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
int multi;
|
||||
int nlines;
|
||||
char *status = nil;
|
||||
|
||||
int
|
||||
line(int fd, char *file)
|
||||
{
|
||||
char c;
|
||||
int m, n, nalloc;
|
||||
char *buf;
|
||||
|
||||
nalloc = 0;
|
||||
buf = nil;
|
||||
for(m=0; ; ){
|
||||
n = read(fd, &c, 1);
|
||||
if(n < 0){
|
||||
fprint(2, "read: error reading %s: %r\n", file);
|
||||
exits("read error");
|
||||
}
|
||||
if(n == 0){
|
||||
if(m == 0)
|
||||
status = "eof";
|
||||
break;
|
||||
}
|
||||
if(m == nalloc){
|
||||
nalloc += 1024;
|
||||
buf = realloc(buf, nalloc);
|
||||
if(buf == nil){
|
||||
fprint(2, "read: malloc error: %r\n");
|
||||
exits("malloc");
|
||||
}
|
||||
}
|
||||
buf[m++] = c;
|
||||
if(c == '\n')
|
||||
break;
|
||||
}
|
||||
if(m > 0)
|
||||
write(1, buf, m);
|
||||
free(buf);
|
||||
return m;
|
||||
}
|
||||
|
||||
void
|
||||
lines(int fd, char *file)
|
||||
{
|
||||
do{
|
||||
if(line(fd, file) == 0)
|
||||
break;
|
||||
}while(multi || --nlines>0);
|
||||
}
|
||||
|
||||
void
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i, fd;
|
||||
char *s;
|
||||
|
||||
ARGBEGIN{
|
||||
case 'm':
|
||||
multi = 1;
|
||||
break;
|
||||
case 'n':
|
||||
s = ARGF();
|
||||
if(s){
|
||||
nlines = atoi(s);
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
fprint(2, "usage: read [-m] [-n nlines] [files...]\n");
|
||||
exits("usage");
|
||||
}ARGEND
|
||||
|
||||
if(argc == 0)
|
||||
lines(0, "<stdin>");
|
||||
else
|
||||
for(i=0; i<argc; i++){
|
||||
fd = open(argv[i], OREAD);
|
||||
if(fd < 0){
|
||||
fprint(2, "read: can't open %s: %r\n", argv[i]);
|
||||
exits("open");
|
||||
}
|
||||
lines(fd, argv[i]);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
exits(status);
|
||||
}
|
Reference in New Issue
Block a user