[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