diff --git a/Makefile.am b/Makefile.am index 9133112..1e27cc2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -237,7 +237,6 @@ FULL_TESTS = \ TESTS = $(UNIT_TESTS) $(FULL_TESTS) XFAIL_TESTS = \ - tests/20-pipe-sed.sh \ tests/70-hash.sh \ tests/70-hash-hash.sh \ tests/70-percent.sh \ diff --git a/gash/built-ins/echo.scm b/gash/built-ins/echo.scm index ffdb5fe..2a5d6da 100644 --- a/gash/built-ins/echo.scm +++ b/gash/built-ins/echo.scm @@ -1,5 +1,6 @@ ;;; Gash -- Guile As SHell -;;; Copyright © 2018 Timothy Sample +;;; Copyright © 2018, 2019 Timothy Sample +;;; Copyright © 2019 Jan (janneke) Nieuwenhuizen ;;; ;;; This file is part of Gash. ;;; @@ -17,6 +18,9 @@ ;;; along with Gash. If not, see . (define-module (gash built-ins echo) + #:use-module (ice-9 match) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) #:export (echo)) ;;; Commentary: @@ -25,10 +29,50 @@ ;;; ;;; Code: +(define (escape->control string) + (list->string + (let loop ((lst (string->list string))) + (if (null? lst) '() + (let ((char (car lst))) + (if (or (not (eq? char #\\)) + (null? (cdr lst))) (cons char (loop (cdr lst))) + (let* ((lst (cdr lst)) + (char (car lst))) + (case char + ((#\\) (cons #\\ (loop (cdr lst)))) + ((#\a) (cons #\alarm (loop (cdr lst)))) + ((#\b) (cons #\backspace (loop (cdr lst)))) + ((#\c) '()) + ((#\e) (cons #\escape (loop (cdr lst)))) + ((#\f) (cons #\page (loop (cdr lst)))) + ((#\n) (cons #\newline (loop (cdr lst)))) + ((#\r) (cons #\return (loop (cdr lst)))) + ((#\t) (cons #\tab (loop (cdr lst)))) + ((#\v) (cons #\vtab (loop (cdr lst)))) + ((#\0) (error "echo: TODO: \\0NNN")) + ((#\x) (error "echo: TODO: \\xNNN")))))))))) + +(define (option? str) + (and (> (string-length str) 1) + (char=? (string-ref str 0) #\-) + (string-every (cut member <> '(#\E #\e #\n)) (substring str 1)))) + (define (echo . args) - (let* ((n? (and (pair? args) (string=? (car args) "-n"))) - (args (if n? (cdr args) args))) - (display (string-join args " ")) - (unless n? + (let* ((options (append-map (compose cdr string->list) + (take-while option? args))) + (args (drop-while option? args)) + (newline? (not (member #\n options))) + (escapes? (fold (lambda (x acc) + (match x + (#\e #t) + (#\E #f) + (_ acc))) + #f + options)) + (string (string-join args))) + (display (if escapes? + (escape->control string) + string)) + (when newline? (newline)) 0))