[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
is this my mistake or someone elses?
I was implementing a read builtin (to make things like cat in es possible) and
ran into a problem with file descriptors. Is it a bug, or is it designed that
way?
To elaborate - first my read primitive:
static int max_len_quantum=256,bufsiz=0;
static unsigned char *buf;
PRIM(readctl) {
if (length(list)!=2)
fail("$&readctl","usage: $&readctl bufsiz quant");
max_len_quantum=getnumber(getstr(list->next->term));
bufsiz=getnumber(getstr(list->term));
if (!bufsiz)
efree(buf);
else
buf=erealloc(buf,bufsiz);
return NULL;
}
static int readchar (int fd) {
if (bufsiz==0) {
unsigned char c;
if (read (fd, &c, 1) == 1) return c;
else return EOF;
}
else {
static int buflen;
static unsigned char *bufp;
if (!buflen) {
buflen=read(fd,buf,bufsiz);
bufp=buf;
}
if (!buflen) return EOF;
else return buflen--,*(bufp++);
}
}
PRIM(read) {
int c,fd,l,zfl=0;
char *line=NULL;
size_t len=0, max_len=0;
List *retval;
if ((l=length(list)) > 1)
fail("$&read","usage: $&read [fd]");
if (l)
fd = getnumber(getstr(list->term));
else fd=0;
do {
c = readchar (fd);
if (!zfl && !c) zfl=1;
if (len == max_len)
line = (char*) erealloc (line, max_len += max_len_quantum);
if (c == '\n' || c == EOF)
line[len] = 0;
else
line[len] = c;
len++;
} while (c != '\n' && c != EOF);
if (c==EOF && len==1) {efree(line); return NULL;}
retval=mklist(mkterm(zfl?gcdup(line):gcndup(line,len-1),NULL),NULL);
efree(line);
return retval;
}
( inserted into prim-io.c, and with the appropriate X(read) at the end.)
This is from an implementation of read for rc that I had from somewhere,
modified to return the string read, instead of setting a variable. (It can do
a heck of a job on the gc, judging by how the size blows up when you turn it
off). It works pretty well, with the exceptions that it doesn't use readline
if you are using it, and it chops any lines that it reads at nulls. (hmmm -
using a read primitive, would it be possible to use that to rewrite %parse
completely in the shell? If so, how slow and ugly would it be?)
The function I'm using:
fn shcat {
#$&gcdisable
fi=<=%newfd
for (x=$*) {
## {while {line=<={$&read $fi}; !~ $#line 0} {echo $line }} <[$fi] $x
%open $fi $x {while {line=<={$&read $fi}; !~ $#line 0} {echo $line }}
}
#$&gcenable
}
The $&gc*able just turn the gc on or off; I was testing to see how much faster
it would run when not gc-ing and shcat-ing a large file. Not much, and the
size blows up and doesn't srhink all the way al the time. (Speaking of which,
is there any harm in turning off the gc from the shell level, aside from it
not releasing memory? It would fail assertions if they were on when I used the
shell level gc controls.)
Now, the actual problem: (transcript)
; echo <={$&read 5} <[5] /etc/magic
; time echo <={$&read 5} <[5] /etc/magic
0r 0.0u 0.0s echo
; time {echo <={$&read 5} <[5] /etc/magic}
# Magic file created Thu Dec 24 12:14:18 1992 by winter!root tty1 Dec 24
08:58
0r 0.0u 0.0s {%open 5 <={%one /etc/magic} {echo <={$&read
5}}}
; time echo <={$&read 5 <[5] /etc/magic}
0r 0.0u 0.0s echo
; time {echo <={$&read 5 <[5] /etc/magic}}
0r 0.0u 0.0s {echo <={%open 5 <={%one /etc/magic} {$&read
5}}}
; time {echo <={$&read <[5] /etc/magic}}
asd
asd
2r 0.0u 0.0s {echo <={%open 5 <={%one /etc/magic} {$&read}}}
; time {echo <={$&read 3 <[5] /etc/magic}}
# Magic file created Thu Dec 24 12:14:18 1992 by winter!root tty1 Dec 24
08:58
0r 0.0u 0.0s {echo <={%open 5 <={%one /etc/magic} {$&read
3}}}
;
My read primitive reads from a given file descriptor, or 0 by default. So if
I call it as {$&read 5}, it should read from fd 5. '<[5] /etc/magic' should
open /etc/magic for input and dup2 it to fd 5 (right?). an strace shows that
this is not the case. However, it does perform the dup2 when it's forced into
a subshell (such as by time, as above). When run in the same shell context,
it only opens the file (usually on fd 3, so the last line works when it
shouldn't).
Should file descriptors be assigned when builtin commands are run, or it it
intentional that they are not?
Diversion