Make 'read' handle logical lines.
* gash/built-ins/read.scm (read-logical-line): New procedure. (main): Use it unless given the '-r' option. * tests/read.org: Add tests.
This commit is contained in:
parent
5fed1b0d87
commit
804b6cbe05
|
@ -17,10 +17,13 @@
|
||||||
;;; along with Gash. If not, see <http://www.gnu.org/licenses/>.
|
;;; along with Gash. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
(define-module (gash built-ins read)
|
(define-module (gash built-ins read)
|
||||||
|
#:use-module (gash compat)
|
||||||
|
#:use-module (gash compat textual-ports)
|
||||||
#:use-module (gash environment)
|
#:use-module (gash environment)
|
||||||
#:use-module (ice-9 match)
|
#:use-module (ice-9 match)
|
||||||
#:use-module (ice-9 rdelim)
|
#:use-module (ice-9 rdelim)
|
||||||
#:use-module (srfi srfi-1))
|
#:use-module (srfi srfi-1)
|
||||||
|
#:use-module (srfi srfi-26))
|
||||||
|
|
||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
;;;
|
;;;
|
||||||
|
@ -28,6 +31,21 @@
|
||||||
;;;
|
;;;
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
|
(define* (read-logical-line #:optional (port (current-input-port)))
|
||||||
|
"Return a ``logical'' line from @var{port} if specified, otherwise
|
||||||
|
from the value returned by @code{(current-input-port)}. A logical
|
||||||
|
line allows ignoring a newline character by prefixing it with a
|
||||||
|
backslash."
|
||||||
|
(let loop ((acc '()))
|
||||||
|
(match (get-char port)
|
||||||
|
((? eof-object? eof) (cons (reverse-list->string acc) eof))
|
||||||
|
(#\newline (cons (reverse-list->string acc) #\newline))
|
||||||
|
(#\\ (match (get-char port)
|
||||||
|
((? eof-object? eof) (cons (reverse-list->string acc) eof))
|
||||||
|
(#\newline (loop acc))
|
||||||
|
(chr (loop (cons chr acc)))))
|
||||||
|
(chr (loop (cons chr acc))))))
|
||||||
|
|
||||||
;; The '(gash word)' module already has a 'split-fields' procedure.
|
;; The '(gash word)' module already has a 'split-fields' procedure.
|
||||||
;; However, we need to be able to specify a maximum number of fields,
|
;; However, we need to be able to specify a maximum number of fields,
|
||||||
;; which it cannot do. We could extend it, but it has to deal with
|
;; which it cannot do. We could extend it, but it has to deal with
|
||||||
|
@ -67,17 +85,24 @@ field, while contiguous sequences of characters from the set
|
||||||
(else '())))
|
(else '())))
|
||||||
|
|
||||||
(define (main . args)
|
(define (main . args)
|
||||||
(match (read-line (current-input-port))
|
(match-let* (((vars . get-line)
|
||||||
((? eof-object?) 1)
|
(match args
|
||||||
(str (let* ((limit (length args))
|
(("-r" vars ...)
|
||||||
(dflt (string #\space #\tab #\newline))
|
(cons vars (cut read-line (current-input-port) 'split)))
|
||||||
(ifs (string->char-set (getvar "IFS" dflt)))
|
((vars ...)
|
||||||
(ifs/w (char-set-intersection ifs char-set:whitespace))
|
(cons vars read-logical-line))))
|
||||||
(ifs/nw (char-set-difference ifs char-set:whitespace))
|
(limit (length vars))
|
||||||
(fields (split-fields str limit ifs/nw ifs/w)))
|
((line . delimiter) (get-line))
|
||||||
(for-each (lambda (var field)
|
(dflt (string #\space #\tab #\newline))
|
||||||
;; XXX: Verify that VAR is a valid variable name.
|
(ifs (string->char-set (getvar "IFS" dflt)))
|
||||||
(setvar! var field))
|
(ifs/w (char-set-intersection ifs char-set:whitespace))
|
||||||
args
|
(ifs/nw (char-set-difference ifs char-set:whitespace))
|
||||||
(append fields (circular-list "")))
|
(fields (split-fields line limit ifs/nw ifs/w)))
|
||||||
0))))
|
(for-each (lambda (var field)
|
||||||
|
;; XXX: Verify that VAR is a valid variable name.
|
||||||
|
(setvar! var field))
|
||||||
|
vars
|
||||||
|
(append fields (circular-list "")))
|
||||||
|
(if (eof-object? delimiter)
|
||||||
|
EXIT_FAILURE
|
||||||
|
EXIT_SUCCESS)))
|
||||||
|
|
|
@ -88,3 +88,31 @@
|
||||||
foo
|
foo
|
||||||
bar baz
|
bar baz
|
||||||
#+end_example
|
#+end_example
|
||||||
|
|
||||||
|
* Allows escaping line breaks
|
||||||
|
:script:
|
||||||
|
#+begin_src sh
|
||||||
|
echo 'foo\
|
||||||
|
bar' | {
|
||||||
|
read x
|
||||||
|
echo $x
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
:stdout:
|
||||||
|
#+begin_example
|
||||||
|
foobar
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
* Understands raw input flag
|
||||||
|
:script:
|
||||||
|
#+begin_src sh
|
||||||
|
echo 'foo\
|
||||||
|
bar' | {
|
||||||
|
read -r x
|
||||||
|
echo $x
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
:stdout:
|
||||||
|
#+begin_example
|
||||||
|
foo\
|
||||||
|
#+end_example
|
||||||
|
|
Loading…
Reference in New Issue