ref: 744475a503e3af4597a4a038c3686c25abb48ee0
parent: 1b02c81c18eb4be6d9372c8d668ad2314bae7872
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Sat Nov 5 19:41:43 EDT 2022
read: add -r to read runes instead of bytes (thanks umbraticus)
--- a/sys/man/1/cat
+++ b/sys/man/1/cat
@@ -10,12 +10,15 @@
.B read
[
.B -m
-] [
+|
.B -n
.I nlines
-] [
+|
.B -c
.I nbytes
+|
+.B -r
+.I nrunes
] [
.I file ...
]
@@ -59,20 +62,14 @@
causes it to read no more than
.I nlines
lines.
-.PP
-With the
+The
.B -c
-flag,
-.I read
-copies exactly
-.I nbytes
-of characters instead of lines. It is mutually exclusive with
-.B -n
and
-.B -m
-flag.
+.B -r
+flags specify a number of bytes or runes to read instead of lines.
.PP
-.I Read
+When reading lines,
+.I read
always executes a single
.B write
for each line of input, which can be helpful when
--- a/sys/src/cmd/read.c
+++ b/sys/src/cmd/read.c
@@ -2,8 +2,7 @@
#include <libc.h>
int multi;
-int nlines;
-vlong nchars;
+vlong count;
char *status = nil;
int
@@ -50,7 +49,7 @@
do{
if(line(fd, file) == 0)
break;
- }while(multi || --nlines>0);
+ }while(multi || --count > 0);
}
void
@@ -60,10 +59,10 @@
vlong m;
int n;
- for(m = 0; m < nchars; m += n){
+ for(m = 0; m < count; m += n){
n = sizeof(buf);
- if(n > (nchars - m))
- n = nchars - m;
+ if(n > (count - m))
+ n = count - m;
if((n = read(fd, buf, n)) < 0){
fprint(2, "read: error reading %s: %r\n", file);
exits("read error");
@@ -78,9 +77,45 @@
}
void
+runes(int fd, char *file)
+{
+ char buf[8*1024], *s, *e;
+ Rune r;
+
+ while(count > 0){
+ e = buf + read(fd, buf, count + UTFmax < sizeof buf ? count : sizeof buf - UTFmax);
+ if(e < buf){
+ fprint(2, "read: error reading %s: %r\n", file);
+ exits("read error");
+ }
+ if(e == buf)
+ break;
+ for(s = buf; s < e && fullrune(s, e - s); s += chartorune(&r, s))
+ count--;
+ if(s < e){
+ while(!fullrune(s, e - s))
+ switch(read(fd, e, 1)){
+ case -1:
+ fprint(2, "read: error reading %s: %r\n", file);
+ exits("read error");
+ case 0:
+ fprint(2, "warning: partial rune at end of %s: %r\n", file);
+ write(1, buf, e - buf);
+ return;
+ case 1:
+ e++;
+ break;
+ }
+ count--;
+ }
+ write(1, buf, e - buf);
+ }
+}
+
+void
usage(void)
{
- fprint(2, "usage: read [-m] [-n nlines] [-c nbytes] [files...]\n");
+ fprint(2, "usage: read [ -m | -n nlines | -c nbytes | -r nrunes ] [ file ... ]\n");
exits("usage");
}
@@ -93,11 +128,15 @@
proc = lines;
ARGBEGIN{
case 'c':
- nchars = atoll(EARGF(usage()));
+ count = atoll(EARGF(usage()));
proc = chars;
break;
+ case 'r':
+ count = atoll(EARGF(usage()));
+ proc = runes;
+ break;
case 'n':
- nlines = atoi(EARGF(usage()));
+ count = atoi(EARGF(usage()));
break;
case 'm':
multi = 1;