diff --git a/scsh/fdports1.c b/scsh/fdports1.c index 10e2e09..5c62f14 100644 --- a/scsh/fdports1.c +++ b/scsh/fdports1.c @@ -55,8 +55,8 @@ s48_value read_delim(const char *delims, char *buf, int fd, int start, int end, int *nread) { - char *cptr = buf+start-1, /* Location of last char deposited. */ - *bufend = buf+end-1; /* Last writeable position. */ + char *cptr = buf+start, /* Location of last char deposited. */ + *bufend = buf+end -1; /* Last writeable position. */ int retval; @@ -67,29 +67,35 @@ s48_value read_delim(const char *delims, char *buf, retval = read( fd, &c, 1 ); if( retval == 0 ) { /* Terminal case: EOF. */ - *nread = 1 + cptr - buf - start; + *nread = cptr - buf - start; return S48_EOF; } else if( retval == -1 ) { /* Terminal case: error. */ - *nread = 1 + cptr - buf - start; + *nread = cptr - buf - start; return s48_enter_fixnum(errno); } else if( delims[c] ) { /* Terminal case: delimiter char. */ - s48_value ch = s48_enter_char(c); - *nread = 1 + cptr - buf - start; - return ch; + *nread = cptr - buf - start; + return s48_enter_char(c); } - else if( cptr >= bufend ) { /* Terminal case: buffer overflow. */ - *nread = end-start; - return S48_FALSE; - } - - else *++cptr = c; + else if( cptr == bufend ) { /* Terminal case: buffer overflow. */ + *cptr = c; + *nread = end-start; + return S48_FALSE; + } + else if ( cptr > bufend ){ + fputs("cptr > bufend.\n", stderr); + abort(); + _exit(-1); + } + else { + *cptr++ = c; } } +} s48_value skip_chars(const char *skipchars, int fd, int *nread) @@ -115,7 +121,7 @@ s48_value skip_chars(const char *skipchars, int fd, int *nread) else if( !skipchars[c] ) { /* Terminal case: non-skip char. */ *nread = nr; - return S48_FALSE; + return s48_enter_char(c); } nr++; } diff --git a/scsh/rdelim.scm b/scsh/rdelim.scm index 5b39f82..01a72c2 100644 --- a/scsh/rdelim.scm +++ b/scsh/rdelim.scm @@ -30,12 +30,11 @@ (define (read-delimited delims . args) (let-optionals args ((port (current-input-port)) (delim-action 'trim)) - (let ((substr (lambda (s end) ; Smart substring. - (if (= end (string-length s)) s - (substring s 0 end)))) - (delims (->char-set delims)) - (gobble? (not (eq? delim-action 'peek)))) - + (let ((substr (lambda (s end) ; Smart substring. + (if (= end (string-length s)) s + (substring s 0 end)))) + (delims (->char-set delims)) + (gobble? (not (eq? delim-action 'peek)))) ;; BUFLEN is total amount of buffer space allocated to date. (let lp ((strs '()) (buflen 80) (buf (make-string 80))) (receive (terminator num-read) @@ -154,6 +153,35 @@ ;;; the input stream. Otherwise, it is left in place for a following input ;;; operation. + +(define (port-buffer-read-delimited delims buf gobble? port start end) + (let ((the-port-limit (port-limit port))) + (let lp ((i start) (lp-port-index (port-index port))) + (cond ((port-pending-eof? port) + (set-port-index! port lp-port-index) + (values (eof-object) i)) + ((>= i end) + (set-port-index! port lp-port-index) + (values #f (- i start))) + ((< lp-port-index the-port-limit) + (let ((the-read-char + (ascii->char (byte-vector-ref + (port-buffer port) lp-port-index)))) + (if (char-set-contains? delims the-read-char) + (begin + (if gobble? + (set-port-index! port (+ lp-port-index 1)) + (set-port-index! port lp-port-index)) + (values the-read-char (- i start))) + (begin + (string-set! buf i the-read-char) + (lp (+ i 1) (+ lp-port-index 1)))))) + (else (set-port-index! port 0) + (set-port-limit! port 0) + (values 'port-buffer-exhausted i)))))) + + + (define (%read-delimited! delims buf gobble? . args) (let-optionals args ((port (current-input-port)) (start 0) @@ -167,18 +195,26 @@ (let* ((delims (->char-set delims)) (sdelims (char-set:s delims))) - - (if (and (fdport? port) (not gobble?)) - + + (receive (terminator num-read) + (port-buffer-read-delimited delims buf gobble? port start end) + (if (not (eq? terminator 'port-buffer-exhausted)) + (values terminator num-read) + (begin (set! start (+ start num-read)) + (if (fdport? port) ;; Direct C support for Unix file ports -- zippy quick. - (let lp ((start start) (total 0)) + (let lp ((start start) (total num-read)) (let ((fd (fdport-data:fd (fdport-data port)))) (receive (terminator num-read) - (%read-delimited-fd!/errno sdelims buf + (%read-delimited-fd!/errno sdelims buf fd start end) (let ((total (+ num-read total))) - (cond ((not (integer? terminator)) (values terminator total)) - ((= terminator errno/intr) (lp (+ start num-read) total)) + (cond ((char? terminator) + (if (not gobble?) (push-back port terminator)) + (values terminator total)) + ((not (integer? terminator)) (values terminator total)) + ((= terminator errno/intr) + (lp (+ start num-read) total)) (else (errno-error terminator %read-delimited! num-read total delims buf gobble? port start end))))))) @@ -186,6 +222,7 @@ ;; This is the code for other kinds of ports. ;; Mighty slow -- we read each char twice (peek first, then read). (let lp ((i start)) + (warn "use of read-delim lp") (let ((c (peek-char port))) (cond ((or (eof-object? c) ; Found terminating char or eof (char-set-contains? delims c)) @@ -197,7 +234,13 @@ (values #f (- i start))) (else (string-set! buf i (read-char port)) - (lp (+ i 1)))))))))) + (lp (+ i 1))))))))))))) + +; overwrites port-index :-( +(define (push-back port char) + (byte-vector-set! (port-buffer port) (port-index port) (char->ascii char)) + (set-port-limit! port (+ (port-limit port) 1))) + (foreign-init-name "rdelim") @@ -219,11 +262,11 @@ (define-foreign %skip-char-set-fd/errno (skip_chars (string skip-set) (fixnum fd)) - desc ; int => errno; #f => win. + desc ; int => errno; char => win, pushback; #f => win w/eof. fixnum) ; number of chars skipped. -;;; JMG: I added scset here without knowing, what I do !! + (define (skip-char-set skip-chars . maybe-port) (let* ((port (:optional maybe-port (current-input-port))) (cset (->char-set skip-chars)) @@ -234,13 +277,21 @@ ;; Direct C support for Unix file ports -- zippy quick. ((fdport? port) - (let lp ((total 0)) + (receive (succ num-read) (buffer-skip-char-set cset port) + (if (not succ) + num-read + (let lp ((total num-read)) (receive (err num-read) (%skip-char-set-fd/errno scset (fdport-data:fd (fdport-data port))) (let ((total (+ total num-read))) - (cond ((not err) total) + (cond ((not err) + (set-port-pending-eof?! port #t) + total) + ((char? err) + (push-back port err) + total) ((= errno/intr err) (lp total)) - (errno-error err skip-char-set cset port total)))))) + (errno-error err skip-char-set cset port total)))))))) ;; This is the code for other kinds of ports. ;; Mighty slow -- we read each char twice (peek first, then read). @@ -252,7 +303,24 @@ (else i)))))))) - +(define (buffer-skip-char-set cset port) + (let ((the-port-limit (port-limit port))) + (let lp ((lp-port-index (port-index port)) (i 0)) + (cond ((port-pending-eof? port) + (set-port-index! port lp-port-index) + (values #f i)) + ((< lp-port-index the-port-limit) + (let ((the-read-char + (ascii->char (byte-vector-ref + (port-buffer port) lp-port-index)))) + (cond ((char-set-contains? cset the-read-char) + (lp (+ lp-port-index 1) (+ i 1))) + (else + (set-port-index! port lp-port-index) + (values #f i))))) + (else (set-port-index! port 0) + (set-port-limit! port 0) + (values 'port-buffer-exhausted i)))))) ;;; (read-line [port delim-action]) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;