Remove (almost) all references to Geesh.
gash/environment.scm: Remove file.
geesh/*: Move these files into the 'gash' folder and replace all
instances of the word 'geesh'.
scripts/geesh.in: Remove file.
HACKING, INSTALL, Makefile.am, configure.ac, guix.scm,
tests/bootstrap/bash-without-bash.scm, tests/spec/Makefile.am,
tests/spec/check-spec, tests/spec/oil.scm, tests/unit/*,
tools/coverage.in: Replace all instances of the word 'geesh'.
Co-authored-by: Jan Nieuwenhuizen <janneke@gnu.org>
2019-02-15 00:55:07 +00:00
|
|
|
;;; Gash -- Guile As SHell
|
2019-08-20 17:45:59 +01:00
|
|
|
;;; Copyright © 2018, 2019 Timothy Sample <samplet@ngyro.com>
|
2018-07-12 03:05:15 +01:00
|
|
|
;;;
|
Remove (almost) all references to Geesh.
gash/environment.scm: Remove file.
geesh/*: Move these files into the 'gash' folder and replace all
instances of the word 'geesh'.
scripts/geesh.in: Remove file.
HACKING, INSTALL, Makefile.am, configure.ac, guix.scm,
tests/bootstrap/bash-without-bash.scm, tests/spec/Makefile.am,
tests/spec/check-spec, tests/spec/oil.scm, tests/unit/*,
tools/coverage.in: Replace all instances of the word 'geesh'.
Co-authored-by: Jan Nieuwenhuizen <janneke@gnu.org>
2019-02-15 00:55:07 +00:00
|
|
|
;;; This file is part of Gash.
|
2018-07-12 03:05:15 +01:00
|
|
|
;;;
|
Remove (almost) all references to Geesh.
gash/environment.scm: Remove file.
geesh/*: Move these files into the 'gash' folder and replace all
instances of the word 'geesh'.
scripts/geesh.in: Remove file.
HACKING, INSTALL, Makefile.am, configure.ac, guix.scm,
tests/bootstrap/bash-without-bash.scm, tests/spec/Makefile.am,
tests/spec/check-spec, tests/spec/oil.scm, tests/unit/*,
tools/coverage.in: Replace all instances of the word 'geesh'.
Co-authored-by: Jan Nieuwenhuizen <janneke@gnu.org>
2019-02-15 00:55:07 +00:00
|
|
|
;;; Gash is free software: you can redistribute it and/or modify
|
2018-07-12 03:05:15 +01:00
|
|
|
;;; it under the terms of the GNU General Public License as published by
|
|
|
|
;;; the Free Software Foundation, either version 3 of the License, or
|
|
|
|
;;; (at your option) any later version.
|
|
|
|
;;;
|
Remove (almost) all references to Geesh.
gash/environment.scm: Remove file.
geesh/*: Move these files into the 'gash' folder and replace all
instances of the word 'geesh'.
scripts/geesh.in: Remove file.
HACKING, INSTALL, Makefile.am, configure.ac, guix.scm,
tests/bootstrap/bash-without-bash.scm, tests/spec/Makefile.am,
tests/spec/check-spec, tests/spec/oil.scm, tests/unit/*,
tools/coverage.in: Replace all instances of the word 'geesh'.
Co-authored-by: Jan Nieuwenhuizen <janneke@gnu.org>
2019-02-15 00:55:07 +00:00
|
|
|
;;; Gash is distributed in the hope that it will be useful,
|
2018-07-12 03:05:15 +01:00
|
|
|
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
;;; GNU General Public License for more details.
|
|
|
|
;;;
|
|
|
|
;;; You should have received a copy of the GNU General Public License
|
Remove (almost) all references to Geesh.
gash/environment.scm: Remove file.
geesh/*: Move these files into the 'gash' folder and replace all
instances of the word 'geesh'.
scripts/geesh.in: Remove file.
HACKING, INSTALL, Makefile.am, configure.ac, guix.scm,
tests/bootstrap/bash-without-bash.scm, tests/spec/Makefile.am,
tests/spec/check-spec, tests/spec/oil.scm, tests/unit/*,
tools/coverage.in: Replace all instances of the word 'geesh'.
Co-authored-by: Jan Nieuwenhuizen <janneke@gnu.org>
2019-02-15 00:55:07 +00:00
|
|
|
;;; along with Gash. If not, see <http://www.gnu.org/licenses/>.
|
2018-07-12 03:05:15 +01:00
|
|
|
|
Remove (almost) all references to Geesh.
gash/environment.scm: Remove file.
geesh/*: Move these files into the 'gash' folder and replace all
instances of the word 'geesh'.
scripts/geesh.in: Remove file.
HACKING, INSTALL, Makefile.am, configure.ac, guix.scm,
tests/bootstrap/bash-without-bash.scm, tests/spec/Makefile.am,
tests/spec/check-spec, tests/spec/oil.scm, tests/unit/*,
tools/coverage.in: Replace all instances of the word 'geesh'.
Co-authored-by: Jan Nieuwenhuizen <janneke@gnu.org>
2019-02-15 00:55:07 +00:00
|
|
|
(define-module (gash word)
|
|
|
|
#:use-module (gash environment)
|
|
|
|
#:use-module (gash pattern)
|
2018-11-20 20:02:09 +00:00
|
|
|
#:use-module (ice-9 ftw)
|
2018-07-12 03:05:15 +01:00
|
|
|
#:use-module (ice-9 match)
|
|
|
|
#:use-module (srfi srfi-1)
|
|
|
|
#:use-module (srfi srfi-26)
|
2021-04-19 16:16:17 +01:00
|
|
|
#:export (parameter-ref
|
|
|
|
expand-qword))
|
2018-07-12 03:05:15 +01:00
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
;;;
|
|
|
|
;;; This module contains functions for manipulating shell words. This
|
|
|
|
;;; includes tilde expansion, parameter expansions, field splitting,
|
|
|
|
;;; globbing, etc.
|
|
|
|
;;;
|
|
|
|
;;; In the code below, the term "qword" is used to refer to words that
|
|
|
|
;;; only contain quotations (i.e., no substitutions).
|
|
|
|
;;;
|
|
|
|
;;; Code:
|
|
|
|
|
2022-12-22 17:52:14 +00:00
|
|
|
(cond-expand
|
|
|
|
(mes
|
|
|
|
;; We need to sort the results of 'scandir' when globbing, so we
|
|
|
|
;; monkey patch Mes' 'scandir' to do so.
|
|
|
|
(let ((core:scandir scandir))
|
|
|
|
(set! scandir
|
|
|
|
(lambda (name select?)
|
|
|
|
(sort (core:scandir name select?) string<)))))
|
|
|
|
(else))
|
|
|
|
|
2018-07-12 03:05:15 +01:00
|
|
|
(define (normalize-word word)
|
|
|
|
"Normalize @var{word} (which may be a word or a qword) so that it is
|
|
|
|
guaranteed to be a list."
|
|
|
|
(match word
|
|
|
|
((? string?) (list word))
|
|
|
|
(((? symbol?) _) (list word))
|
|
|
|
(_ word)))
|
|
|
|
|
|
|
|
(define (infix x xs)
|
|
|
|
"Place @var{x} between each element of the list @var{xs}."
|
|
|
|
(if (null? xs)
|
|
|
|
xs
|
|
|
|
(let loop ((xs (cdr xs)) (acc (list (car xs))))
|
|
|
|
(if (null? xs)
|
|
|
|
(reverse acc)
|
|
|
|
(loop (cdr xs) (cons* (car xs) x acc))))))
|
|
|
|
|
|
|
|
(define (list-split xs sym)
|
|
|
|
"Split the list @var{xs} into sublists delimited by the symbol
|
|
|
|
@var{sym}."
|
|
|
|
(let loop ((xs xs) (small-acc '()) (big-acc '()))
|
|
|
|
(cond
|
|
|
|
((null? xs)
|
|
|
|
(reverse (cons (reverse small-acc) big-acc)))
|
|
|
|
((eq? (car xs) sym)
|
|
|
|
(loop (cdr xs) '() (cons (reverse small-acc) big-acc)))
|
|
|
|
(else
|
|
|
|
(loop (cdr xs) (cons (car xs) small-acc) big-acc)))))
|
|
|
|
|
2018-11-11 02:12:45 +00:00
|
|
|
(define (string-tokenize* s token-set)
|
|
|
|
"Split the string @var{s} into a list of substrings, where each
|
|
|
|
substring is a maximal non-empty contiguous sequence of characters
|
|
|
|
from the character set @var{token-set} or its compliment."
|
|
|
|
|
|
|
|
(define token-set-complement
|
|
|
|
(let ((token-set* (char-set-complement token-set)))
|
|
|
|
(lambda (cs)
|
|
|
|
(if (eq? cs token-set) token-set* token-set))))
|
|
|
|
|
|
|
|
(let loop ((index 0) (start 0) (cs token-set) (acc '()))
|
|
|
|
(cond
|
|
|
|
((>= index (string-length s))
|
|
|
|
(reverse! (if (> index start)
|
|
|
|
(cons (substring s start index) acc)
|
|
|
|
acc)))
|
|
|
|
((char-set-contains? cs (string-ref s index))
|
|
|
|
(loop (1+ index) start cs acc))
|
|
|
|
(else
|
|
|
|
(loop index index
|
|
|
|
(token-set-complement cs)
|
|
|
|
(if (> index start)
|
|
|
|
(cons (substring s start index) acc)
|
|
|
|
acc))))))
|
|
|
|
|
2018-07-12 03:05:15 +01:00
|
|
|
(define (split-fields qword ifs)
|
2018-11-09 21:35:06 +00:00
|
|
|
"Split @var{qword} into a list of qwords delimited by any character
|
|
|
|
in the string @var{ifs}."
|
2018-07-12 03:05:15 +01:00
|
|
|
|
2018-11-11 02:12:45 +00:00
|
|
|
(define char-set:ifs
|
|
|
|
(string->char-set ifs))
|
|
|
|
|
|
|
|
(define char-set:ifs/nw
|
2020-02-05 04:10:51 +00:00
|
|
|
(string->char-set (string-delete char-set:whitespace ifs)))
|
2018-11-09 21:35:06 +00:00
|
|
|
|
2018-11-09 03:23:17 +00:00
|
|
|
(define (wedge-apart-quote qword)
|
|
|
|
(let loop ((qword (normalize-word qword)) (acc '()))
|
|
|
|
(match qword
|
|
|
|
(() (reverse! acc))
|
|
|
|
((('<sh-quote> qword*) . t)
|
|
|
|
(loop t (append-reverse (wedge-apart-quote qword*) acc)))
|
|
|
|
((('<sh-at> vals) . t)
|
|
|
|
(loop t (append-reverse (infix 'wedge (map (cut list '<sh-quote> <>)
|
|
|
|
vals))
|
|
|
|
acc)))
|
|
|
|
(((? string? h) . t)
|
2019-10-10 18:32:40 +01:00
|
|
|
(loop t (cons `(<sh-quote> ,h) acc)))
|
|
|
|
(((qwords ...) . t)
|
|
|
|
(loop t (append-reverse (wedge-apart-quote qwords) acc))))))
|
2018-11-09 03:23:17 +00:00
|
|
|
|
2018-11-10 22:35:41 +00:00
|
|
|
(define (wedge-apart qword)
|
|
|
|
(match qword
|
2018-11-09 03:23:17 +00:00
|
|
|
(('<sh-quote> quote) (wedge-apart-quote quote))
|
|
|
|
(('<sh-at> vals) (apply append (infix '(wedge) (map wedge-apart vals))))
|
2018-11-10 22:35:41 +00:00
|
|
|
((? string? str)
|
2018-11-11 02:12:45 +00:00
|
|
|
(let ((tokens (string-tokenize* str char-set:ifs)))
|
|
|
|
(append-map (lambda (token)
|
|
|
|
(if (string-any char-set:ifs token)
|
|
|
|
;; Every occurrence of a non-whitespace
|
|
|
|
;; separator must delimit a field. This
|
|
|
|
;; means that we have to add a blank field
|
|
|
|
;; for every non-whitespace separator in
|
|
|
|
;; 'token' beyond the first.
|
|
|
|
(let ((count (string-count token char-set:ifs/nw)))
|
|
|
|
(cons 'wedge
|
|
|
|
(append-map (const '("" wedge))
|
|
|
|
(iota (max 0 (- count 1))))))
|
|
|
|
(list token)))
|
|
|
|
;; When a word starts with a non-whitespace
|
|
|
|
;; separator, it still delimits two fields, the
|
|
|
|
;; one on the left being empty.
|
|
|
|
(match tokens
|
|
|
|
(((? (cut string-any char-set:ifs/nw <>)) . rest)
|
|
|
|
(cons "" tokens))
|
|
|
|
(_ tokens)))))
|
2018-11-10 22:35:41 +00:00
|
|
|
(_ (append-map wedge-apart qword))))
|
2018-07-12 03:05:15 +01:00
|
|
|
|
2018-11-10 22:35:41 +00:00
|
|
|
(let ((wedged (wedge-apart qword)))
|
2018-07-18 07:33:08 +01:00
|
|
|
(filter pair? (list-split wedged 'wedge))))
|
2018-07-12 03:05:15 +01:00
|
|
|
|
2018-11-09 03:23:17 +00:00
|
|
|
(define (argument-separator ifs)
|
|
|
|
"Find the argument separator string by taking the first character of
|
|
|
|
the string @var{ifs}. If @var{ifs} is @code{#f} the separator will be
|
|
|
|
a space (@code{\" \"}), and if @var{ifs} is null (@code{\"\"}) the
|
|
|
|
separator will be null as well."
|
|
|
|
(let ((ifs (or ifs " ")))
|
|
|
|
(if (string-null? ifs)
|
|
|
|
""
|
|
|
|
(string (string-ref ifs 0)))))
|
|
|
|
|
|
|
|
(define (remove-quotes qword ifs)
|
|
|
|
"Remove quote forms from @var{qword} and concatenate the result into
|
|
|
|
a single field (string). When converting an argument list to a
|
|
|
|
string, the separator is derived from @var{ifs} using
|
|
|
|
@code{argument-separator}."
|
2018-07-12 03:05:15 +01:00
|
|
|
(let loop ((qword (normalize-word qword)) (acc '()))
|
|
|
|
(match qword
|
|
|
|
(() (string-concatenate-reverse acc))
|
2018-11-09 03:23:17 +00:00
|
|
|
((('<sh-quote> qword*) . t)
|
|
|
|
(loop t (cons (remove-quotes qword* ifs) acc)))
|
|
|
|
((('<sh-at> vals) . t)
|
|
|
|
(let ((sep (argument-separator ifs)))
|
|
|
|
(loop t (cons (string-join vals sep) acc))))
|
|
|
|
(((? string? h) . t)
|
2019-10-10 18:32:40 +01:00
|
|
|
(loop t (cons h acc)))
|
|
|
|
(((qwords ...) . t)
|
|
|
|
(loop t (cons (remove-quotes qwords ifs) acc))))))
|
2018-07-12 03:05:15 +01:00
|
|
|
|
2019-12-02 03:14:19 +00:00
|
|
|
(define (qword->pattern-string qword ifs)
|
2018-11-20 20:02:09 +00:00
|
|
|
(let loop ((qword (normalize-word qword)) (acc '()))
|
|
|
|
(match qword
|
2019-12-02 03:14:19 +00:00
|
|
|
(() (string-concatenate-reverse acc))
|
2018-11-20 20:02:09 +00:00
|
|
|
((('<sh-quote> qword*) . t)
|
|
|
|
(loop t (cons (pattern-quote (remove-quotes qword* ifs)) acc)))
|
|
|
|
(((? string? h) . t)
|
|
|
|
(loop t (cons h acc))))))
|
|
|
|
|
2019-12-02 03:14:19 +00:00
|
|
|
(define (qword->pattern qword ifs)
|
|
|
|
(parse-pattern (qword->pattern-string qword ifs)))
|
|
|
|
|
|
|
|
(define (find-files base patterns)
|
|
|
|
"Find all the files starting from @var{base} where each node of the
|
|
|
|
file's relative path matchs the corresponding pattern in
|
|
|
|
@var{patterns}."
|
|
|
|
(define (make-select pattern)
|
|
|
|
(cut pattern-match? pattern <> #:explicit-initial-period? #t))
|
|
|
|
|
|
|
|
(define (ensure-directory path)
|
|
|
|
(and (scandir (string-append base "/" path))
|
|
|
|
(string-append path "/")))
|
|
|
|
|
|
|
|
(define* (list-directory path pattern)
|
|
|
|
(map (cond
|
|
|
|
((string-null? path) values)
|
|
|
|
((string-every #\/ path) (cut string-append path <>))
|
|
|
|
(else (cut string-append path "/" <>)))
|
|
|
|
(or (scandir (string-append base "/" path) (make-select pattern))
|
|
|
|
'())))
|
|
|
|
|
|
|
|
(let loop ((paths (list "")) (patterns patterns))
|
|
|
|
(match patterns
|
|
|
|
(() paths)
|
|
|
|
(((? pattern-null?) . rest)
|
|
|
|
(loop (filter-map ensure-directory paths) rest))
|
|
|
|
((pattern . rest)
|
|
|
|
(loop (append-map (cut list-directory <> pattern) paths) rest)))))
|
2018-11-20 20:02:09 +00:00
|
|
|
|
2019-12-02 03:14:19 +00:00
|
|
|
(define (expand-pathnames qword pwd ifs)
|
|
|
|
"Interpret @var{qword} as a pattern and find all files matching that
|
|
|
|
pattern. If no files are found, return a singleton list containing a
|
|
|
|
string version of @var{qword}. If the pattern is relative, @var{pwd}
|
|
|
|
will be used as the current directory. If @var{qword} contains
|
|
|
|
preserved fields (e.g., @code{\"$@\"}), @var{ifs} will be used to
|
|
|
|
faltten them."
|
|
|
|
(define absolute?
|
|
|
|
(match-lambda
|
|
|
|
(((? pattern-null?) . _) #t)
|
|
|
|
(_ #f)))
|
|
|
|
|
2019-12-02 05:08:17 +00:00
|
|
|
(if (getopt 'noglob)
|
|
|
|
`(,(remove-quotes qword ifs))
|
|
|
|
(let* ((pattern-string (qword->pattern-string qword ifs))
|
|
|
|
(patterns (map parse-pattern (string-split pattern-string #\/)))
|
|
|
|
(base (if (absolute? patterns) "/" pwd)))
|
|
|
|
(if (every pattern-plain? patterns)
|
|
|
|
`(,(remove-quotes qword ifs))
|
|
|
|
(match (find-files base patterns)
|
|
|
|
(() `(,(remove-quotes qword ifs)))
|
|
|
|
(matches matches))))))
|
2018-11-20 20:02:09 +00:00
|
|
|
|
Globalize the environment module
Instead of passing around references to the environment, just treat it
as a global. The old way was just the remains of an idea to make the
environment immutable and keep the interpreter from manipulating any
global state. By making everything global and mutable, we will have
less impedance mismatch with POSIX going forward.
The following changelog is only a sketch, since nearly every function
has changed.
* geesh/environment.scm: Replace this module with one that treats the
environment as a global resource.
* tests/environment.scm: Delete file.
* Makefile.am: Remove it from the list of tests.
* geesh/shell.scm, geesh/eval.scm, geesh/repl.scm, geesh/word.scm,
geesh/built-ins/break.scm, geesh/built-ins/continue.scm,
geesh/built-ins/echo.scm, geesh/built-ins/export.scm,
geesh/built-ins/false.scm, geesh/built-ins/read.scm,
geesh/built-ins/readonly.scm, geesh/built-ins/set.scm,
geesh/built-ins/true.scm, geesh/built-ins/unset.scm: Remove 'env'
parameters and use the new environment module.
* .dir-locals.el: Update indentation of functions that no longer take
an 'env' parameter and add with-arguments, with-environ, and
with-variables from the new environment module.
* tests/shell.scm, tests/word.scm: Update environment creation and
manipulation in tests.
2018-11-25 05:47:09 +00:00
|
|
|
(define* (parameter-ref name #:optional dflt)
|
|
|
|
"Get the value of the variable or special parameter @var{name} from
|
2019-08-20 17:22:51 +01:00
|
|
|
the environment. If @var{name} is unset, return @var{dflt} if
|
|
|
|
provided or @code{#f} if not."
|
Add 'status' field to environment
Instead of using an environment variable named '?', we will use a
special environment field called 'status'. This lets us get rid of a
lot of number-string conversions (since an environment variable has to
have a string value).
* geesh/environment.scm (<environment>): Add a 'status' field.
(make-environment): Set it to 0 by default.
* geesh/repl.scm (run-repl): Use new field in place of '?' variable.
* geesh/shell.scm (exec-utility, sh:and, sh:exec-let, sh:for, sh:not,
sh:or, sh:pipeline, sh:subshell, sh:substitute-command): Ditto.
* geesh/word.scm (parameter-ref): New function that handles both
special parameters (e.g., '?') and variables.
(parameter-ref*): Like 'var-ref*', but for 'parameter-ref'.
(word->qword): Replace 'var-ref' and 'var-ref*' with 'parameter-ref'
and 'parameter-ref*' respectively.
2018-11-09 02:29:19 +00:00
|
|
|
(match name
|
Globalize the environment module
Instead of passing around references to the environment, just treat it
as a global. The old way was just the remains of an idea to make the
environment immutable and keep the interpreter from manipulating any
global state. By making everything global and mutable, we will have
less impedance mismatch with POSIX going forward.
The following changelog is only a sketch, since nearly every function
has changed.
* geesh/environment.scm: Replace this module with one that treats the
environment as a global resource.
* tests/environment.scm: Delete file.
* Makefile.am: Remove it from the list of tests.
* geesh/shell.scm, geesh/eval.scm, geesh/repl.scm, geesh/word.scm,
geesh/built-ins/break.scm, geesh/built-ins/continue.scm,
geesh/built-ins/echo.scm, geesh/built-ins/export.scm,
geesh/built-ins/false.scm, geesh/built-ins/read.scm,
geesh/built-ins/readonly.scm, geesh/built-ins/set.scm,
geesh/built-ins/true.scm, geesh/built-ins/unset.scm: Remove 'env'
parameters and use the new environment module.
* .dir-locals.el: Update indentation of functions that no longer take
an 'env' parameter and add with-arguments, with-environ, and
with-variables from the new environment module.
* tests/shell.scm, tests/word.scm: Update environment creation and
manipulation in tests.
2018-11-25 05:47:09 +00:00
|
|
|
("@" `(<sh-at> ,(cdr (program-arguments))))
|
|
|
|
("*" (let* ((ifs (or (getvar "IFS")
|
2018-11-09 03:36:11 +00:00
|
|
|
(string #\space #\tab #\newline)))
|
|
|
|
(sep (argument-separator ifs)))
|
Globalize the environment module
Instead of passing around references to the environment, just treat it
as a global. The old way was just the remains of an idea to make the
environment immutable and keep the interpreter from manipulating any
global state. By making everything global and mutable, we will have
less impedance mismatch with POSIX going forward.
The following changelog is only a sketch, since nearly every function
has changed.
* geesh/environment.scm: Replace this module with one that treats the
environment as a global resource.
* tests/environment.scm: Delete file.
* Makefile.am: Remove it from the list of tests.
* geesh/shell.scm, geesh/eval.scm, geesh/repl.scm, geesh/word.scm,
geesh/built-ins/break.scm, geesh/built-ins/continue.scm,
geesh/built-ins/echo.scm, geesh/built-ins/export.scm,
geesh/built-ins/false.scm, geesh/built-ins/read.scm,
geesh/built-ins/readonly.scm, geesh/built-ins/set.scm,
geesh/built-ins/true.scm, geesh/built-ins/unset.scm: Remove 'env'
parameters and use the new environment module.
* .dir-locals.el: Update indentation of functions that no longer take
an 'env' parameter and add with-arguments, with-environ, and
with-variables from the new environment module.
* tests/shell.scm, tests/word.scm: Update environment creation and
manipulation in tests.
2018-11-25 05:47:09 +00:00
|
|
|
(string-join (cdr (program-arguments)) sep)))
|
2018-12-04 17:53:32 +00:00
|
|
|
("0" (car (program-arguments)))
|
|
|
|
("#" (number->string (length (cdr (program-arguments)))))
|
Globalize the environment module
Instead of passing around references to the environment, just treat it
as a global. The old way was just the remains of an idea to make the
environment immutable and keep the interpreter from manipulating any
global state. By making everything global and mutable, we will have
less impedance mismatch with POSIX going forward.
The following changelog is only a sketch, since nearly every function
has changed.
* geesh/environment.scm: Replace this module with one that treats the
environment as a global resource.
* tests/environment.scm: Delete file.
* Makefile.am: Remove it from the list of tests.
* geesh/shell.scm, geesh/eval.scm, geesh/repl.scm, geesh/word.scm,
geesh/built-ins/break.scm, geesh/built-ins/continue.scm,
geesh/built-ins/echo.scm, geesh/built-ins/export.scm,
geesh/built-ins/false.scm, geesh/built-ins/read.scm,
geesh/built-ins/readonly.scm, geesh/built-ins/set.scm,
geesh/built-ins/true.scm, geesh/built-ins/unset.scm: Remove 'env'
parameters and use the new environment module.
* .dir-locals.el: Update indentation of functions that no longer take
an 'env' parameter and add with-arguments, with-environ, and
with-variables from the new environment module.
* tests/shell.scm, tests/word.scm: Update environment creation and
manipulation in tests.
2018-11-25 05:47:09 +00:00
|
|
|
("?" (number->string (get-status)))
|
2018-12-05 18:58:34 +00:00
|
|
|
("$" (number->string (get-root-pid)))
|
2020-03-17 20:54:01 +00:00
|
|
|
("!" (cond ((get-last-job) => number->string)
|
|
|
|
(else dflt)))
|
2018-12-19 06:19:54 +00:00
|
|
|
(("LINENO" . line) (number->string line))
|
2018-12-04 17:53:32 +00:00
|
|
|
(x (let ((n (string->number x)))
|
|
|
|
(if (and n (integer? n) (> n 0)
|
|
|
|
(<= n (length (cdr (program-arguments)))))
|
|
|
|
(list-ref (program-arguments) n)
|
|
|
|
(getvar name dflt))))))
|
Add 'status' field to environment
Instead of using an environment variable named '?', we will use a
special environment field called 'status'. This lets us get rid of a
lot of number-string conversions (since an environment variable has to
have a string value).
* geesh/environment.scm (<environment>): Add a 'status' field.
(make-environment): Set it to 0 by default.
* geesh/repl.scm (run-repl): Use new field in place of '?' variable.
* geesh/shell.scm (exec-utility, sh:and, sh:exec-let, sh:for, sh:not,
sh:or, sh:pipeline, sh:subshell, sh:substitute-command): Ditto.
* geesh/word.scm (parameter-ref): New function that handles both
special parameters (e.g., '?') and variables.
(parameter-ref*): Like 'var-ref*', but for 'parameter-ref'.
(word->qword): Replace 'var-ref' and 'var-ref*' with 'parameter-ref'
and 'parameter-ref*' respectively.
2018-11-09 02:29:19 +00:00
|
|
|
|
2021-04-17 02:57:40 +01:00
|
|
|
(define* (expand-qword qword #:key (output 'fields) (rhs-tildes? #f))
|
|
|
|
"Expand @var{qword} into a list of fields."
|
|
|
|
(let ((ifs (getvar "IFS" (string #\space #\tab #\newline)))
|
|
|
|
(pwd (getvar "PWD")))
|
2018-11-21 01:44:33 +00:00
|
|
|
(match output
|
|
|
|
('fields (if pwd
|
|
|
|
(append-map (cut expand-pathnames <> pwd ifs)
|
|
|
|
(split-fields qword ifs))
|
|
|
|
(map (cut remove-quotes <> ifs)
|
|
|
|
(split-fields qword ifs))))
|
|
|
|
('string (remove-quotes qword ifs))
|
|
|
|
('pattern (qword->pattern qword ifs)))))
|