From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from oldp.astro.wisc.edu ([128.104.39.15]) by hawkwind.utcs.toronto.edu with SMTP id <2223>; Mon, 17 May 1993 22:13:46 -0400 Received: by oldp.astro.wisc.edu (5.65/DEC-Ultrix/4.3) id AA18944; Mon, 17 May 1993 21:13:31 -0500 Message-Id: <9305180213.AA18944@oldp.astro.wisc.edu> To: rc@hawkwind.utcs.toronto.edu Subject: Re: read Date: Mon, 17 May 1993 22:13:30 -0400 From: Alan Watson X-Mts: smtp Gosh, this stuff is tricky, isn't it? Here are both external and built-in implementations of read, following v7 semantics on EOF (i.e., set the variable to '' and return 1), and a corrected trip.read. None of the other reads in the list or the examples get this right (including my previous offerings). Of course, all of this will be made redundant by bqstatus. I take it by the silence that no one objects to a built-in read by default ("yeah, right"). Alan. ; cat addon/read.c /* b_reads -- read a single line, terminated by \n or EOF, from the standard input, and assign the line without the terminator to av[1]. */ static int readchar (int fd) { unsigned char c; if (read (fd, &c, 1) == 1) return c; else return EOF; } void b_read (char **av) { char *name; int c; char *line; SIZE_T len; SIZE_T max_len; SIZE_T max_len_quantum; /* check usage is "read name" */ if (av[1] == NULL) rc_error ("missing variable name"); if (av[2] != NULL) rc_error ("too many arguments to read"); name = av[1]; /* read a single line from stdin */ line = NULL; len = 0; max_len = 0; max_len_quantum = 256; do { c = readchar (0); if (len == max_len) line = 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); /* assign whatever we read to the variable */ assign (word (name, NULL), word (line, NULL), FALSE); efree (line); /* return TRUE if we terminated with a \n, otherwise FALSE */ set (c == '\n'); return; } ; cat read.fn fn read { switch ( $#* ) { case 0 echo >[1=2] missing variable return 1 case 1 case * echo >[1=2] too many arguments to read return 1 } lines = () { ifs = $nl { lines = `{ line ; echo $status } } if ( ~ $#lines 1 ) { $1 = '' return $lines } else { $1 = $lines(1) return $lines(2) } } } ; cat trip.read # trip.read -- check a read implementation performs like a true v7 sh read fn check { echo $1 $2 ./rc -c $2 if ( ! ~ $status $1 ) { echo failed: $2 } } check 0 true check 1 false nl = ' ' ifs = $nl file = /etc/passwd first = `{ cat $file } first = $first(1) echo 'start of trip.read' # check read X and read '*' return 0 check 0 'exec <$file ; read X' check 0 'exec <$file ; read ''*''' # check read, read 1, read '=', and read '' return 1 check 1 'exec <$file ; read' check 1 'exec <$file ; read 1' check 1 'exec <$file ; read ''=''' check 1 'exec <$file ; read ''''' # check read X correctly reads first line check 0 'exec <$file; read X ; ~ $X $first' check 0 'echo -n $first | { read X ; ~ $X $first }' # check read '*' correctly reads first line, preserves $0 check 0 'exec <$file ; old0 = $0 ; read ''*'' ; ~ $0 $old0 && ~ $1 $first && ~ $#* 1' # check read returns 1 on EOF and I/O error check 1 'exec