From f05a4dee04ff588f3b3b27a35ba8c75ef1afdba0 Mon Sep 17 00:00:00 2001 From: DONG Yuxuan Date: Wed, 19 Jul 2023 19:32:16 +0800 Subject: [PATCH] Shsub 2.0.0 --- .gitignore | 7 +- LICENSE | 44 +++-- Makefile | 61 ++----- README.md | 118 ++++++------ cases/argv/echo.out | 1 + cases/argv/echo.tpl | 1 + cases/argv/run | 5 + cases/compile/echo.out | 1 + cases/compile/echo.tpl | 1 + cases/compile/run | 6 + cases/letter/letter.out | 10 + cases/letter/letter.tpl | 17 ++ cases/letter/run | 3 + cases/letter/utils.sh | 16 ++ cases/letter/vars.tpl | 1 + cases/lexhack/lexhack.out | 4 + cases/lexhack/lexhack.tpl | 6 + cases/lexhack/run | 3 + cases/pipein/letter.out | 10 + cases/pipein/letter.tpl | 17 ++ cases/pipein/run | 3 + cases/pipein/utils.sh | 16 ++ cases/pipein/vars.tpl | 1 + cli.sh | 75 -------- shsub.1 | 70 ------- shsub.1.tpl | 58 ++++++ shsub.c | 371 ++++++++++++++++++++++++++++++++++++++ tc.c | 229 ----------------------- test | 13 ++ test/1/in | 0 test/1/out | 0 test/1/run | 4 - test/10/in | 3 - test/10/out | 10 - test/10/run | 4 - test/11/in | 3 - test/11/out | 10 - test/11/run | 4 - test/12/in | 5 - test/12/out | 1 - test/12/run | 4 - test/13/in | 9 - test/13/out | 1 - test/13/run | 4 - test/14/in | 10 - test/14/out | 1 - test/14/run | 4 - test/15/in | 10 - test/15/out | 1 - test/15/run | 4 - test/16/in | 10 - test/16/out | 1 - test/16/run | 5 - test/17/in | 6 - test/17/out | 5 - test/17/run | 9 - test/18/in | 6 - test/18/out | 5 - test/18/run | 9 - test/19/in | 6 - test/19/out | 5 - test/19/run | 8 - test/2/in | 2 - test/2/out | 2 - test/2/run | 4 - test/3/in | 5 - test/3/out | 2 - test/3/run | 4 - test/4/in | 3 - test/4/out | 4 - test/4/run | 4 - test/5/err | 1 - test/5/in | 2 - test/5/run | 4 - test/6/err | 1 - test/6/in | 4 - test/6/run | 4 - test/7/in | 0 test/7/out | 0 test/7/run | 4 - test/8/in | 1 - test/8/out | 1 - test/8/run | 4 - test/9/in | 3 - test/9/out | 5 - test/9/run | 4 - version | 1 - 87 files changed, 669 insertions(+), 735 deletions(-) create mode 100644 cases/argv/echo.out create mode 100644 cases/argv/echo.tpl create mode 100755 cases/argv/run create mode 100644 cases/compile/echo.out create mode 100644 cases/compile/echo.tpl create mode 100755 cases/compile/run create mode 100644 cases/letter/letter.out create mode 100644 cases/letter/letter.tpl create mode 100755 cases/letter/run create mode 100644 cases/letter/utils.sh create mode 100644 cases/letter/vars.tpl create mode 100644 cases/lexhack/lexhack.out create mode 100644 cases/lexhack/lexhack.tpl create mode 100755 cases/lexhack/run create mode 100644 cases/pipein/letter.out create mode 100644 cases/pipein/letter.tpl create mode 100755 cases/pipein/run create mode 100644 cases/pipein/utils.sh create mode 100644 cases/pipein/vars.tpl delete mode 100644 cli.sh delete mode 100644 shsub.1 create mode 100644 shsub.1.tpl create mode 100644 shsub.c delete mode 100644 tc.c create mode 100755 test delete mode 100644 test/1/in delete mode 100644 test/1/out delete mode 100755 test/1/run delete mode 100644 test/10/in delete mode 100644 test/10/out delete mode 100755 test/10/run delete mode 100644 test/11/in delete mode 100644 test/11/out delete mode 100755 test/11/run delete mode 100644 test/12/in delete mode 100644 test/12/out delete mode 100755 test/12/run delete mode 100644 test/13/in delete mode 100644 test/13/out delete mode 100755 test/13/run delete mode 100644 test/14/in delete mode 100644 test/14/out delete mode 100755 test/14/run delete mode 100644 test/15/in delete mode 100644 test/15/out delete mode 100755 test/15/run delete mode 100644 test/16/in delete mode 100644 test/16/out delete mode 100755 test/16/run delete mode 100755 test/17/in delete mode 100644 test/17/out delete mode 100755 test/17/run delete mode 100755 test/18/in delete mode 100644 test/18/out delete mode 100755 test/18/run delete mode 100755 test/19/in delete mode 100644 test/19/out delete mode 100755 test/19/run delete mode 100644 test/2/in delete mode 100644 test/2/out delete mode 100755 test/2/run delete mode 100644 test/3/in delete mode 100644 test/3/out delete mode 100755 test/3/run delete mode 100644 test/4/in delete mode 100644 test/4/out delete mode 100755 test/4/run delete mode 100644 test/5/err delete mode 100644 test/5/in delete mode 100755 test/5/run delete mode 100644 test/6/err delete mode 100644 test/6/in delete mode 100755 test/6/run delete mode 100644 test/7/in delete mode 100644 test/7/out delete mode 100755 test/7/run delete mode 100644 test/8/in delete mode 100644 test/8/out delete mode 100644 test/8/run delete mode 100644 test/9/in delete mode 100644 test/9/out delete mode 100755 test/9/run delete mode 100644 version diff --git a/.gitignore b/.gitignore index 100b9b3..38f631c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ +/shsub +/shsub.1 .DS_Store +*.tmp *.dSYM *.swp -/cli -/tc -/testenv -/testinst diff --git a/LICENSE b/LICENSE index 4c93f9e..b07eee7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,22 +1,30 @@ -The MIT License (MIT) +Shsub +Porject Homepage: +Copyright (c) 2022 DONG Yuxuan -Copyright(C) DONG Yuxuan +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile index 747b09f..3dae597 100644 --- a/Makefile +++ b/Makefile @@ -1,64 +1,27 @@ .PHONY: all install test clean +name = shsub prefix = /usr/local bindir = $(prefix)/bin -libdir = $(prefix)/lib datarootdir = $(prefix)/share mandir = $(datarootdir)/man INSTALL = install CC = cc -CFLAGS = -std=c89 \ - -D_POSIX_C_SOURCE=200809L \ - -pedantic-errors \ - -Wno-error=all -all: cli tc +all: shsub install: all - $(INSTALL) -d \ - $(bindir) \ - $(libdir)/shsub \ - $(mandir)/man1 - $(INSTALL) cli tc $(libdir)/shsub/ - $(INSTALL) -m644 version LICENSE $(libdir)/shsub/ - $(INSTALL) -m644 shsub.1 $(mandir)/man1/ - @echo append version information to manpage - @( \ - printf "\n%s\n\n" ".SH VERSION"; \ - printf "shsub "; \ - cat version; \ - printf "\n"; \ - cat LICENSE; \ - ) >>$(mandir)/man1/shsub.1 - @echo generate "`echo $(bindir)/shsub`" - @( \ - echo '#!/bin/sh'; \ - echo exec `echo $(libdir)/shsub/cli` '"$$@"'; \ - ) >$(bindir)/shsub - @chmod 755 $(bindir)/shsub + name='$(name)' ./shsub shsub.1.tpl >shsub.1 + mkdir -p $(bindir) $(mandir)/man1 + $(INSTALL) shsub $(bindir)/$(name) + $(INSTALL) -m644 shsub.1 $(mandir)/man1/$(name).1 -test: all - @set -e; \ - rm -rf testenv testinst; \ - make install prefix="`pwd`/testinst"; \ - cp -R test testenv; \ - for t in testenv/*; do \ - echo running test $$t...; \ - ( \ - cd $$t; \ - PATH="../../testinst/bin:$$PATH"; \ - chmod +x run; \ - ./run \ - ); \ - done; \ - echo all tests passed - -cli: cli.sh - cp $< $@ - chmod +x $@ - -tc: tc.c +shsub: shsub.c $(CC) $(CFLAGS) -o $@ $< +test: all + chmod +x test + ./test + clean: - rm -rf cli tc testenv testinst *.dSYM + rm -rf shsub shsub.1 diff --git a/README.md b/README.md index b49d2df..520367c 100644 --- a/README.md +++ b/README.md @@ -1,87 +1,97 @@ -shsub +Shsub ===== -`shsub` is a template engine of the shell language, -implemented in C and Shell. +Shsub is a template engine of the shell language, +implemented in C. -The following file `lsnotes.html.st` is a simple shell template: +The following file `notes.html.tpl` demonstrates a simple template:
    - <% for i in notes/*.md; do -%> - <% title=`grep '^# ' "$i" | head -n1` -%> - <% if [ -n "$title" ]; then -%> -
  • - <%=$title %> -
  • - <% fi -%> - <% done -%> + <%for i in notes/*.md; do-%> + <% title="$(grep '^# ' "$i" | head -n1)"-%> +
  • <%="$title"%>
  • + <%done-%>
-Running `shsub lsnotes.html.st` prints a HTML list reporting titles of -your Markdown notes. +Calling `shsub notes.html.tpl` +prints a HTML list reporting titles of your Markdown notes. -Template Syntax ---------------- +**Key Features** -The `shsub` program compiles the template to a shell script and execute it. +- Fast template compiling; +- Low memory footprint; +- Light-weight, containing only a standalone executable. -- if the first line of the shell template begins with `#!` (*shebang*), -it will be ignored +Template Syntax +--------------- -- `<%`*cmd*`%>` is compiled to *cmd* +- Shell commands are surrounded by `<%` and `%>` and +are compiled to the commands themselves; -- `<%=`*expr*`%>` is compiled to `printf %s "`*expr*`"` +- Shell expressions are surrounded by `<%=` and `%>` and each `<%=expr%>` is compiled to `printf %s expr`; - Leading and trailing spaces, tabs, and newlines of *expr* - are removed. - Double quotes in *expr* are automatically escaped. +- Ordinary text is compiled to the command printing that text; -- `-%>` can be used instead of `%>` to ignore the following newline +- A template can include other templates by `<%+filename%>`; -- `<%%` and `%%>` are escaping tokens representing literal `<%` and `%>` +- If `-%>` is used instead of `%>`, +the following newline character will be ignored; -- ordinary text is compiled to the command that prints the text +- `<%%` and `%%>` are compiled to literal `<%` and `%>`. Installation ------------ -Download the source tarball of the latest version from -the [release list](https://github.com/dongyx/shsub/releases). -Unpack the tarball and -execute the following commands in the source tree: +It would be better to select a version from the +[release page](https://github.com/dongyx/shsub/releases) +than downloading the working code, +unless you understand the status of the working code. +The latest stable release is always recommended. + + $ make + $ sudo make install + +By default, Shsub is installed to `/usr/local`. +You could call `shsub --version` to check the installation. + +Further Documentation +--------------------- - make test - sudo make install +Calling Shsub with `--help` prints a brief of the command-line options. +The complete description is documented in the man page shipped with the installation. -`shsub` is installed to `/usr/local` by default. +The implementation is explained in the [paper](https://www.dyx.name/notes/shsub-impl.html). +If you attempt to contribute to this project, it may help. -Building `shsub` requires: +Migrating from 1.x +------------------ -- `cc`(1): any C compiler which is compatible with `clang` or `gcc` +The breaking changes of Shsub 2.0.0 are: -Usage ------ +- The special treatment for shebang comments are deprecated; +If an executable is required, +compile the template to a shell script using the `-c` option; -`shsub` \[*options*\] \[*file*\] \[*argument* ...\] +- Expressions are no longer automatically quoted and escaped; -If *file* is `-` or omitted, `shsub` reads the template from stdin. +- The `progname` environment variable is no longer set; +If the template needs to use `$0`, +compile it to a shell script using the `-c` option; -options: +To make parallel installations of Shsub 1.x and the later version, +use the `name` installation variable: -- `-s` *sh* specify the shell to execute the compiled script, - `/bin/sh` by default -- `-h` print the brief usage -- `-v` print the version information + sudo make install name=shsub2 -The detailed information is documented in the man page `shsub`(1) -which is included in the installation. -You could read it anytime by typing `man shsub`. +This will install with the name `shsub2` +instead of the default `shsub`. +Both the executable and the man page will use the specified name. -Uninstallation --------------- +Credits +------- -For default installation in `/usr/local`: +Shsub is created by [DONG Yuxuan](https://www.dyx.name) in 2022. - sudo rm /usr/local/bin/shsub - sudo rm -r /usr/local/lib/shsub/ - sudo rm /usr/local/share/man/man1/shsub.1 +The syntax is inspired by +Jakub Jirutka's [ESH](https://github.com/jirutka/esh) +whose syntax is based on ERB (Embedded Ruby). diff --git a/cases/argv/echo.out b/cases/argv/echo.out new file mode 100644 index 0000000..b85905e --- /dev/null +++ b/cases/argv/echo.out @@ -0,0 +1 @@ +1 2 3 diff --git a/cases/argv/echo.tpl b/cases/argv/echo.tpl new file mode 100644 index 0000000..d3a7f2b --- /dev/null +++ b/cases/argv/echo.tpl @@ -0,0 +1 @@ +<%="$*"%> diff --git a/cases/argv/run b/cases/argv/run new file mode 100755 index 0000000..bf686a3 --- /dev/null +++ b/cases/argv/run @@ -0,0 +1,5 @@ +#!/bin/sh + +set -e +shsub echo.tpl 1 2 3 >echo.tmp +diff -u echo.out echo.tmp diff --git a/cases/compile/echo.out b/cases/compile/echo.out new file mode 100644 index 0000000..b85905e --- /dev/null +++ b/cases/compile/echo.out @@ -0,0 +1 @@ +1 2 3 diff --git a/cases/compile/echo.tpl b/cases/compile/echo.tpl new file mode 100644 index 0000000..d3a7f2b --- /dev/null +++ b/cases/compile/echo.tpl @@ -0,0 +1 @@ +<%="$*"%> diff --git a/cases/compile/run b/cases/compile/run new file mode 100755 index 0000000..bd2e66b --- /dev/null +++ b/cases/compile/run @@ -0,0 +1,6 @@ +#!/bin/sh + +set -e +shsub -co echo.sh.tmp -s /bin/sh echo.tpl +./echo.sh.tmp 1 2 3 >echo.tmp +diff -u echo.out echo.tmp diff --git a/cases/letter/letter.out b/cases/letter/letter.out new file mode 100644 index 0000000..cac9567 --- /dev/null +++ b/cases/letter/letter.out @@ -0,0 +1,10 @@ + A Letter from Shsub +Hi, dear user: + Shsub is a template engine of the shell language, implemented in C. + + **Key Features** + + - Fast template compiling; + - Low memory footprint; + - Light-weight, containing only a standalone executable. + - Shsub Developer diff --git a/cases/letter/letter.tpl b/cases/letter/letter.tpl new file mode 100644 index 0000000..2c0adbf --- /dev/null +++ b/cases/letter/letter.tpl @@ -0,0 +1,17 @@ +<%+vars.tpl-%> +<%. "$(pwd)/utils.sh"-%> +<%w=80-%> +<%(-%> +A Letter from Shsub +<%)|center $w-%> +Hi, <%="$name"%>: +<%(-%> +Shsub is a template engine of the shell language, implemented in C. + +**Key Features** + +- Fast template compiling; +- Low memory footprint; +- Light-weight, containing only a standalone executable. +<%) | fold -w$(($w-8)) | awk '{print "\t" $0}'-%> +<%( %>- Shsub Developer<% ) | xargs -0 printf %${w}s%> diff --git a/cases/letter/run b/cases/letter/run new file mode 100755 index 0000000..4266793 --- /dev/null +++ b/cases/letter/run @@ -0,0 +1,3 @@ +#!/bin/sh +shsub letter.tpl >letter.tmp +diff -u letter.out letter.tmp diff --git a/cases/letter/utils.sh b/cases/letter/utils.sh new file mode 100644 index 0000000..ae45105 --- /dev/null +++ b/cases/letter/utils.sh @@ -0,0 +1,16 @@ +center() +{ + local w + local p + local l + + w=$1 + while read l; do + p=$(((w - ${#l})/2)) + while [ $p -gt 0 ]; do + printf ' ' + p=$((p-1)) + done + printf %s\\n "$l" + done +} diff --git a/cases/letter/vars.tpl b/cases/letter/vars.tpl new file mode 100644 index 0000000..0ffb8ac --- /dev/null +++ b/cases/letter/vars.tpl @@ -0,0 +1 @@ +<%name="dear user"-%> diff --git a/cases/lexhack/lexhack.out b/cases/lexhack/lexhack.out new file mode 100644 index 0000000..7deff96 --- /dev/null +++ b/cases/lexhack/lexhack.out @@ -0,0 +1,4 @@ +..............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................<%%%%%%> +........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................ +xy +xy diff --git a/cases/lexhack/lexhack.tpl b/cases/lexhack/lexhack.tpl new file mode 100644 index 0000000..ab6e115 --- /dev/null +++ b/cases/lexhack/lexhack.tpl @@ -0,0 +1,6 @@ +..............................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................<%%%%%%%%> +........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................ +x<%-%> +y +x<%#-%%>-%-%> +y diff --git a/cases/lexhack/run b/cases/lexhack/run new file mode 100755 index 0000000..61ca9b3 --- /dev/null +++ b/cases/lexhack/run @@ -0,0 +1,3 @@ +#!/bin/sh +shsub lexhack.tpl >lexhack.tmp +diff -u lexhack.out lexhack.tmp diff --git a/cases/pipein/letter.out b/cases/pipein/letter.out new file mode 100644 index 0000000..cac9567 --- /dev/null +++ b/cases/pipein/letter.out @@ -0,0 +1,10 @@ + A Letter from Shsub +Hi, dear user: + Shsub is a template engine of the shell language, implemented in C. + + **Key Features** + + - Fast template compiling; + - Low memory footprint; + - Light-weight, containing only a standalone executable. + - Shsub Developer diff --git a/cases/pipein/letter.tpl b/cases/pipein/letter.tpl new file mode 100644 index 0000000..2c0adbf --- /dev/null +++ b/cases/pipein/letter.tpl @@ -0,0 +1,17 @@ +<%+vars.tpl-%> +<%. "$(pwd)/utils.sh"-%> +<%w=80-%> +<%(-%> +A Letter from Shsub +<%)|center $w-%> +Hi, <%="$name"%>: +<%(-%> +Shsub is a template engine of the shell language, implemented in C. + +**Key Features** + +- Fast template compiling; +- Low memory footprint; +- Light-weight, containing only a standalone executable. +<%) | fold -w$(($w-8)) | awk '{print "\t" $0}'-%> +<%( %>- Shsub Developer<% ) | xargs -0 printf %${w}s%> diff --git a/cases/pipein/run b/cases/pipein/run new file mode 100755 index 0000000..596158e --- /dev/null +++ b/cases/pipein/run @@ -0,0 +1,3 @@ +#!/bin/sh +shsub letter.tmp +diff -u letter.out letter.tmp diff --git a/cases/pipein/utils.sh b/cases/pipein/utils.sh new file mode 100644 index 0000000..ae45105 --- /dev/null +++ b/cases/pipein/utils.sh @@ -0,0 +1,16 @@ +center() +{ + local w + local p + local l + + w=$1 + while read l; do + p=$(((w - ${#l})/2)) + while [ $p -gt 0 ]; do + printf ' ' + p=$((p-1)) + done + printf %s\\n "$l" + done +} diff --git a/cases/pipein/vars.tpl b/cases/pipein/vars.tpl new file mode 100644 index 0000000..0ffb8ac --- /dev/null +++ b/cases/pipein/vars.tpl @@ -0,0 +1 @@ +<%name="dear user"-%> diff --git a/cli.sh b/cli.sh deleted file mode 100644 index 4884666..0000000 --- a/cli.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/sh - -# the user interface of shsub -# piping the output of tc to shell - -set -e -dir=`dirname -- "$0"` -version="$dir/version" -license="$dir/LICENSE" -tc="$dir/tc" - -help() { -cat <<\. -usage: shsub [] [] [ ...] - -if is `-' or omitted, read from stdin. - -options - --s specify the shell to execute the compiled script, - `/bin/sh' by default --h print the brief usage --v print the version information -. -} - -# shell escape -shesc() { - printf %s "$1" | sed "s/'/'\\\\''/g; 1 s/^/'/; $ s/$/'/" -} - -preproc() { - awk ' - # replace shebang with a placeholder - # to align line numbers after preprocessing - NR == 1 && /^#!/ { - print "<% -%>" - next - } - { - print - } - ' -} - -sh=/bin/sh -while getopts 's:hv' opt; do - case $opt in - s) sh="$OPTARG";; - h) help - exit;; - v) echo shsub "`cat "$version"`" - cat "$license" - exit;; - ?) help >&2 - exit 1;; - esac -done -shift $(($OPTIND - 1)) - -script="$(mktemp)" -trap '[ -f "$script" ] && rm "$script"' EXIT -trap 'exit 1' TERM INT HUP -if [ $# -gt 0 ]; then - printf '%s\n' progname="`shesc "$1"`" >>"$script" - if [ "$1" = - ]; then - preproc | "$tc" >>"$script" - else - <"$1" preproc | "$tc" >>"$script" - fi - shift -else - preproc | "$tc" >>"$script" -fi -"$sh" "$script" "$@" diff --git a/shsub.1 b/shsub.1 deleted file mode 100644 index cd58d4b..0000000 --- a/shsub.1 +++ /dev/null @@ -1,70 +0,0 @@ -.TH shsub 1 - -.SH NAME - -shsub - compile the shell template to a shell script -and execute it - -.SH SYNOPSIS - -\fBshsub\fR [\fIoptions\fR] [\fIfile\fR\] [\fIargument\fR ...] - -\fBshsub\fR reads the shell template from \fIfile\fR. -If \fIfile\fR is \fB-\fR or omitted, \fBshsub\fR reads from stdin. - -.SH DESCRIPTION - -A shell template is text -with shell commands and expressions embedded in. - -The shell commands are surrounded by \fB<%\fR and \fB%>\fR. -Each \fB<%\fIcmd\fB%>\fR is compiled to \fIcmd\fR. - -The shell expressions are surrounded by \fB<%=\fR and \fB%>\fR. -Each \fB<%=\fIexpr\fB%>\fR is compiled to -\fBprintf %s \[dq]\fIexpr\fB\[dq]\fR. -Leading and trailing spaces, tabs, and newlines of \fIexpr\fR -are removed. -Double quotes in \fIexpr\fR are automatically escaped. - -Ordinary text is compiled to the command printing that text. - -\fB<%%\fR and \fB%%>\fR are escaping tokens representing -literal \fB<%\fR and \fB%>\fR. - -If \fB-%>\fR is used instead of \fB%>\fR, -\fBshsub\fR ignores the following newline. - -If the first line of the shell template begins with -\fB#!\fR (\fIshebang\fR), it will be ignored. -This is for the convenience of making executable shell templates. - -.SH READING INPUT - -Arguments are passed to the compiled script, -but \fB$0\fR could be any value. - -The shell variable \fB$progname\fR is -set to \fB-\fR if the template is read from stdin. -Otherwise it's set to the template name. - -If the template is read from stdin -and the the template itself reads stdin, -the behavior is unspecific. - -.SH OPTIONS - -.TP -\fB\-s\fR \fIshell\fR -Set which shell is used to execute the compiled script. -By default, -\fBshsub\fR uses \fB/bin/sh\fR. -Setting \fB-s cat\fR is a convenient way to examine the compiled script. - -.TP -.B \-h -Print the brief usage. - -.TP -.B \-v -Print the version information. diff --git a/shsub.1.tpl b/shsub.1.tpl new file mode 100644 index 0000000..cf611a8 --- /dev/null +++ b/shsub.1.tpl @@ -0,0 +1,58 @@ +.TH <%="$name"%> 1 + +.SH NAME + +<%="$name"%> - compile the template to a shell script and execute it + +.SH SYNOPSIS + +\fB<%="$name"%>\fR [\fIoptions\fR] [\fIfile\fR\] [\fIarguments\fR] + +\fB<%="$name"%>\fR \fB--help\fR + +\fB<%="$name"%>\fR \fB--version\fR + +.SH DESCRIPTION + +\fB<%="$name"%>\fR reads the template from \fIfile\fR, +or, by default, the standard input. + +A template is text +with embedded shell commands and expressions. +Shell commands are surrounded by \fB<%%\fR and \fB%%>\fR. +Shell expressions are surrounded by \fB<%%=\fR and \fB%%>\fR. +Shell commands are compiled to the commands themselves. +Each \fB<%%=\fIexpr\fB%%>\fR is compiled to \fBprintf %s \fIexpr\fR. +Ordinary text is compiled to the command printing that text. +A template can include other templates by \fB<%%+\fIfilename\fB%%>\fR. + +If \fB-%%>\fR is used instead of \fB%%>\fR +to end a command, expression, or including, +the following newline character will be ignored. +\fB<%%%\fR and \fB%%%>\fR are compiled to literal \fB<%%\fR and \fB%%>\fR. + +\fIArguments\fR are passed to the compiled script while execution. + +.SH OPTIONS + +.TP +\fB\-s\fR \fIpath\fR +Set which shell is used to execute the script +(default: \fB/bin/sh\fR) + +.TP +.B \-c +Compile the template without execution + +.TP +\fB\-o\fR \fIpath\fR +Set the path of the output script if \fB-c\fR is enabled + +.SH AUTHORS + +Shsub is originally created by +DONG Yuxuan in 2022. + +.SH FURTHER DOCUMENTATION + +See the project homepage . diff --git a/shsub.c b/shsub.c new file mode 100644 index 0000000..cfcb266 --- /dev/null +++ b/shsub.c @@ -0,0 +1,371 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define MAXLITR 4096 +#define MAXINCL 64 + +enum token { + INCL, + CMDOPEN, + EXPOPEN, + CLOSE, + ESCOPEN, + ESCCLOSE, + LITERAL, + END +}; + +struct iframe { + FILE *in; + int lookahead, cstack[3], *csp, lineno; + char *tmplname; +} istack[MAXINCL], *isp = istack; + +char *progname, *tmplname, script[] = "/tmp/shsub.XXXXXX"; +enum token lookahead; +int cstack[3], *csp = cstack, lineno = 1; +char literal[MAXLITR]; + +enum token gettoken(FILE *fp); +int cpush(int c); +int cpop(FILE *fp); +void tmpl(FILE *in, FILE *ou); +void text(int esc, FILE *in, FILE *ou); +void match(enum token tok, FILE *fp); +void ipush(FILE *in); +FILE *ipop(void); +void rmscr(void); +void version(void); +void help(void); +void err(char *fmt, ...); +void parserr(char *fmt, ...); +void syserr(void); +void verr(char *fmt, va_list ap); + +int main(int argc, char **argv) +{ + FILE *in, *out; + char *sh = "/bin/sh", *target = NULL; + int fd, op, noexe = 0; + + progname = argv[0]; + if (argc > 1) { + if (!strcmp(argv[1], "--version")) + version(); + if (!strcmp(argv[1], "--help")) + help(); + } + while ((op = getopt(argc, argv, "s:co:")) != -1) + switch (op) { + case 's': sh = optarg; break; + case 'c': noexe = 1; break; + case 'o': target = optarg; break; + case '?': err("Call with `--help` for usage"); + } + argc -= optind; + argv += optind; + in = stdin; + if (argc > 0) { + tmplname = argv[0]; + if (!(in = fopen(tmplname = argv[0], "r"))) + err("%s: %s", tmplname, strerror(errno)); + } + lookahead = gettoken(in); + if (noexe) { + if (target) { + if ((fd = open( + target, + O_CREAT|O_WRONLY|O_TRUNC, + 0755 + )) == -1) + syserr(); + if (!(out = fdopen(fd, "w"))) + syserr(); + } else + out = stdout; + fprintf(out, "#!%s\n", sh); + tmpl(in, out); + if (fclose(out) == EOF) + syserr(); + return 0; + } + if ((fd = mkstemp(script)) == -1 || atexit(rmscr)) + syserr(); + if (!(out = fdopen(fd, "w"))) + syserr(); + fprintf(out, "#!%s\nrm %s\n", sh, script); + tmpl(in, out); + if (fchmod(fd, S_IRWXU) == -1) + syserr(); + if (fclose(out)) + syserr(); + if (argc > 0) + execv(script, argv); + else + execl(script, "-", NULL); + syserr(); + return 0; +} + +enum token gettoken(FILE *fp) +{ + char *p; + int c, h, r, trim = 0; + enum token kw = END; + + p = literal; + while (kw == END) { + while (p - literal < MAXLITR - 1) { + if ((c = cpop(fp)) == EOF || strchr("<%-", c )) + break; + *p++ = c; + } + *p = '\0'; + if (c == EOF) + return p > literal ? LITERAL : END; + if (p == literal + MAXLITR - 1) + return LITERAL; + h = cpop(fp); + r = cpop(fp); + if (c == '<' && h == '%') { + kw = CMDOPEN; + if (r == '=') + kw = EXPOPEN; + else if (r == '+') + kw = INCL; + else if (r == '%') + kw = ESCOPEN; + } else if (c == '%' && h == '>') + kw = CLOSE; + else if (c == '%' && h == '%' && r == '>') + kw = ESCCLOSE; + else if (c == '-' && h == '%' && r == '>') { + trim = 1; + kw = CLOSE; + } else { + cpush(r); + cpush(h); + *p++ = c; + *p = '\0'; + } + } + if (p > literal) { + cpush(r); + cpush(h); + cpush(c); + return LITERAL; + } + if (kw == CMDOPEN || kw == CLOSE && !trim) + cpush(r); + if (trim && (c = cpop(fp)) != '\n') + cpush(c); + return kw; +} + +int cpush(int c) +{ + if (c == '\n') + --lineno; + return *csp++ = c; +} + +int cpop(FILE *fp) +{ + int c; + + if (csp == cstack) + c = fgetc(fp); + else + c = *--csp; + if (c == '\n') { + if (lineno == INT_MAX) + err("Too many lines"); + ++lineno; + } + return c; +} + +void tmpl(FILE *in, FILE *ou) +{ + while (lookahead != END) + switch (lookahead) { + case INCL: + match(INCL, in); + if (lookahead != LITERAL) + parserr("Expect included filename"); + if (!(tmplname = strdup(literal))) + syserr(); + match(LITERAL, in); + match(CLOSE, in); + ipush(in); + if (!(in = fopen(tmplname, "r"))) + err("%s: %s", + tmplname, strerror(errno)); + lineno = 1; + csp = cstack; + lookahead = gettoken(in); + tmpl(in, ou); + fclose(in); + free(tmplname); + in = ipop(); + break; + case CMDOPEN: + match(CMDOPEN, in); + text(0, in, ou); + fputc('\n', ou); + match(CLOSE, in); + break; + case EXPOPEN: + fputs("printf %s ", ou); + match(EXPOPEN, in); + text(0, in, ou); + fputc('\n', ou); + match(CLOSE, in); + break; + case LITERAL: case ESCOPEN: case ESCCLOSE: + fputs("printf %s '", ou); + text(1, in, ou); + fputs("'\n", ou); + break; + default: + parserr("Unexpected token"); + } +} + +void text(int esc, FILE *in, FILE *ou) +{ + char *s; + + for (;;) + switch(lookahead) { + case LITERAL: + if (!esc) + fputs(literal, ou); + else + for (s = literal; *s; ++s) + if (*s == '\'') + fputs("'\\''", ou); + else + fputc(*s, ou); + match(LITERAL, in); + break; + case ESCOPEN: + fputs("<%", ou); + match(ESCOPEN, in); + break; + case ESCCLOSE: + fputs("%>", ou); + match(ESCCLOSE, in); + break; + default: + return; + } +} + +void match(enum token tok, FILE *fp) +{ + if (lookahead != tok) + parserr("Lack of expected token"); + lookahead = gettoken(fp); +} + +void ipush(FILE *in) +{ + if (isp == istack + MAXINCL) + err("Including too deep"); + isp->lookahead = lookahead; + memcpy(isp->cstack, cstack, sizeof cstack); + isp->csp = csp; + isp->in = in; + isp->tmplname = tmplname; + isp->lineno = lineno; + ++isp; +} + +FILE *ipop(void) +{ + --isp; + lookahead = isp->lookahead; + memcpy(cstack, isp->cstack, sizeof cstack); + csp = isp->csp; + tmplname = isp->tmplname; + lineno = isp->lineno; + return isp->in; +} + +void rmscr(void) +{ + unlink(script); +} + +void version(void) +{ + fputs( + "Shsub 2.0.0\n" + "Project Homepage: \n" + "Copyright (c) 2022 DONG Yuxuan \n" + , stdout); + exit(0); +} + +void help(void) +{ + printf( + "USAGE\n" + " %s [OPTIONS] [FILE] [ARGUMENTS]\n" + " %s --help\n" + " %s --version\n" + "OPTIONS\n" + " -s PATH Specify the shell\n" + " (default: /bin/sh)\n" + " -c Compile without execution\n" + " -o PATH Set the path of the output script\n" + " (default: the standard output)\n" + "FURTHER DOCUMENTATION\n" + " See the man page\n" + " See \n" + , progname, progname, progname); + exit(0); +} + +void err(char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "%s: ", progname); + va_start(ap, fmt); + verr(fmt, ap); +} + +void parserr(char *fmt, ...) +{ + va_list ap; + + if (tmplname) + fprintf(stderr,"%s: %s: line %d: ", + progname, tmplname, lineno); + else + fprintf(stderr, "%s: line %d: ", progname, lineno); + va_start(ap, fmt); + verr(fmt, ap); +} + +void syserr(void) +{ + perror(progname); + exit(-1); +} + +void verr(char *fmt, va_list ap) +{ + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + exit(-1); +} diff --git a/tc.c b/tc.c deleted file mode 100644 index 039369e..0000000 --- a/tc.c +++ /dev/null @@ -1,229 +0,0 @@ -/* tc - compile the shell template to a shell script - * - * the shell template is read from stdin - * the shell script is printed to stdout - * - * tc is a component of the shsub project - * - */ - -#include -#include -#include - -#define MAXEXPR 8192 -#define TOKSIZ 8 - -enum error { ESYS = 1, ESYNTAX, ELIM }; -enum token { - OPENCMD, /* <% */ - OPENEXP, /* <%= */ - CLOSE, /* %> */ - TRIMCLS, /* -%> */ - ESCOPEN, /* <%% */ - ESCCLS, /* %%> */ - TXT, /* text */ - END /* EOF */ -}; -enum state { SERR, SINIT, STXT, SCMD, SEXP, STERM }; -enum state sttab[][6] = { -/* in/st ERR INIT TXT CMD EXP TERM */ - -/* OPENCMD */ { SERR, SCMD, SCMD, SERR, SERR, SERR }, -/* OPENEXP */ { SERR, SEXP, SEXP, SERR, SERR, SERR }, -/* CLOSE */ { SERR, SERR, SERR, SINIT, SINIT, SERR }, -/* TRIMCLS */ { SERR, SERR, SERR, SINIT, SINIT, SERR }, -/* ESCOPEN */ { SERR, STXT, STXT, SCMD, SEXP, SERR }, -/* ESCCLS */ { SERR, STXT, STXT, SCMD, SEXP, SERR }, -/* TXT */ { SERR, STXT, STXT, SCMD, SEXP, SERR }, -/* END */ { SERR, STERM, STERM, SERR, SERR, SERR } -}; -void entrtxt(enum state from, enum token in); -void entrcmd(enum state from, enum token in); -void entrexp(enum state from, enum token in); -void entrerr(enum state from, enum token in); -void exittxt(enum state to, enum token in); -void exitcmd(enum state to, enum token in); -void exitexp(enum state to, enum token in); -void (*entrtab[])(enum state, enum token) = { - &entrerr, NULL, &entrtxt, &entrcmd, &entrexp, NULL -}; -void (*exittab[])(enum state, enum token) = { - NULL, NULL, &exittxt, &exitcmd, &exitexp, NULL -}; - -int cstack[TOKSIZ], cssize; -int popc(void); -int pushc(int c); - -int lineno = 1; -char exprbuf[MAXEXPR], *pexpr; -char token[TOKSIZ]; -enum token gettok(void); -int dryread(char *s); - -main() -{ - enum state st, next; - enum token in; - int trim; - - trim = 0; - for (st = SINIT; st != STERM && st != SERR; st = next) { - in = gettok(); - if (token[0] == '\n') { - lineno++; - if (trim) { - trim = 0; - continue; - } - } - if (in == ESCOPEN) - strcpy(token, "<%"); - if (in == ESCCLS) - strcpy(token, "%>"); - next = sttab[in][st]; - if (exittab[st]) - exittab[st](next, in); - if (entrtab[next]) - entrtab[next](st, in); - trim = in == TRIMCLS; - } - return 0; -} - -void entrtxt(enum state from, enum token in) -{ - char *s; - - if (from != STXT) - fputs("printf %s '", stdout); - for (s = token; *s; s++) - if (*s == '\'') - fputs("'\\''", stdout); - else - putchar(*s); -} - -void entrcmd(enum state from, enum token in) -{ - if (from == SCMD) - fputs(token, stdout); -} - -void entrexp(enum state from, enum token in) -{ - char *s; - - if (from != SEXP) { - fputs("printf %s \"", stdout); - pexpr = exprbuf; - *pexpr = '\0'; - } - if (in == OPENEXP) - return; - pexpr = stpncpy(pexpr, token, MAXEXPR - (pexpr - exprbuf)); - if (pexpr >= &exprbuf[MAXEXPR]) { - fprintf( - stderr, - "shsub: expression at line %d " - "exceeds the maximum length %d\n", - lineno, - MAXEXPR - 1 - ); - exit(ELIM); - } -} - -void exitexp(enum state to, enum token in) -{ - static char *spaces = " \t\n"; - char *s; - - if (to == SEXP) - return; - while (pexpr > exprbuf && strchr(spaces, *(pexpr - 1))) - pexpr--; - for (s = &exprbuf[strspn(exprbuf, spaces)]; s < pexpr; s++) - if (*s == '"') - fputs("\\\"", stdout); - else - putchar(*s); - puts("\""); -} - -void entrerr(enum state from, enum token in) -{ - fprintf(stderr, "shsub: unexpected token %s at line %d\n", - token, lineno); - exit(ESYNTAX); -} - -void exittxt(enum state to, enum token in) -{ - if (to != STXT) - puts("'"); -} - -void exitcmd(enum state to, enum token in) -{ - if (to == SCMD) - return; - putchar('\n'); -} - -enum token gettok(void) -{ - static char *kwords[] = { - "<%", "<%=", "%>", "-%>", "<%%", "%%>" - }; - static int nkwords = sizeof kwords / sizeof kwords[0]; - int i, matched, len, maxlen; - - maxlen = 0; - matched = -1; - for (i = 0; i < nkwords; i++) { - len = strlen(kwords[i]); - if (len > maxlen && dryread(kwords[i])) { - matched = i; - maxlen = len; - } - } - while (maxlen--) - popc(); - if (matched >= 0) { - strcpy(token, kwords[matched]); - return matched; - } - token[0] = popc(); - token[1] = '\0'; - return token[0] == EOF ? END : TXT; -} - -int pushc(int c) -{ - return cstack[cssize++] = c; -} - -int popc(void) -{ - return cssize > 0 ? cstack[--cssize] : getchar(); -} - -int dryread(char *s) -{ - char *p, c; - int ret; - - ret = 1; - p = s; - while (*p && (c = popc()) == *p) - p++; - if (*p) { - ret = 0; - pushc(c); - } - while (p != s) - pushc(*--p); - return ret; -} diff --git a/test b/test new file mode 100755 index 0000000..db72684 --- /dev/null +++ b/test @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e +pwd="$(pwd)" +PATH="$pwd:$PATH" +for test in cases/*; do + echo Testing "$test"... + cd "$test" + chmod +x run + ./run + cd "$pwd" +done +echo All tests passed diff --git a/test/1/in b/test/1/in deleted file mode 100644 index e69de29..0000000 diff --git a/test/1/out b/test/1/out deleted file mode 100644 index e69de29..0000000 diff --git a/test/1/run b/test/1/run deleted file mode 100755 index ff612bc..0000000 --- a/test/1/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -shsub progout -diff out progout diff --git a/test/10/in b/test/10/in deleted file mode 100644 index 0b4516f..0000000 --- a/test/10/in +++ /dev/null @@ -1,3 +0,0 @@ -<% for i in a b c d e; do %> -- <%=$i%> -<% done -%> diff --git a/test/10/out b/test/10/out deleted file mode 100644 index 6156e2e..0000000 --- a/test/10/out +++ /dev/null @@ -1,10 +0,0 @@ - -- a - -- b - -- c - -- d - -- e diff --git a/test/10/run b/test/10/run deleted file mode 100755 index ff612bc..0000000 --- a/test/10/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -shsub progout -diff out progout diff --git a/test/11/in b/test/11/in deleted file mode 100644 index 39b6e66..0000000 --- a/test/11/in +++ /dev/null @@ -1,3 +0,0 @@ -<% for i in a b c d e; do %> -- <%= $i %> -<% done -%> diff --git a/test/11/out b/test/11/out deleted file mode 100644 index 6156e2e..0000000 --- a/test/11/out +++ /dev/null @@ -1,10 +0,0 @@ - -- a - -- b - -- c - -- d - -- e diff --git a/test/11/run b/test/11/run deleted file mode 100755 index ff612bc..0000000 --- a/test/11/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -shsub progout -diff out progout diff --git a/test/12/in b/test/12/in deleted file mode 100644 index d60f49e..0000000 --- a/test/12/in +++ /dev/null @@ -1,5 +0,0 @@ -<% foo=hello - bar=world - foobar=END --%> -<%= $foo %>, <%=%><%=$bar%>.<%= %> <%= $foobar %>. diff --git a/test/12/out b/test/12/out deleted file mode 100644 index 433bd15..0000000 --- a/test/12/out +++ /dev/null @@ -1 +0,0 @@ -hello, world. END. diff --git a/test/12/run b/test/12/run deleted file mode 100755 index ff612bc..0000000 --- a/test/12/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -shsub progout -diff out progout diff --git a/test/13/in b/test/13/in deleted file mode 100644 index eacace0..0000000 --- a/test/13/in +++ /dev/null @@ -1,9 +0,0 @@ -<% foo=hello - bar=world - foobar=END --%> -<%= - -$foo %>, <%=%><%=$bar%>.<%= %> <%= $foobar - -%>. diff --git a/test/13/out b/test/13/out deleted file mode 100644 index 433bd15..0000000 --- a/test/13/out +++ /dev/null @@ -1 +0,0 @@ -hello, world. END. diff --git a/test/13/run b/test/13/run deleted file mode 100755 index ff612bc..0000000 --- a/test/13/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -shsub progout -diff out progout diff --git a/test/14/in b/test/14/in deleted file mode 100644 index 491155f..0000000 --- a/test/14/in +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env shsub -<% foo=hello - bar=world - foobar=END --%> -<%= - -$foo %>, <%=%><%=$bar%>.<%= %> <%= $foobar - -%>. diff --git a/test/14/out b/test/14/out deleted file mode 100644 index 433bd15..0000000 --- a/test/14/out +++ /dev/null @@ -1 +0,0 @@ -hello, world. END. diff --git a/test/14/run b/test/14/run deleted file mode 100755 index ff612bc..0000000 --- a/test/14/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -shsub progout -diff out progout diff --git a/test/15/in b/test/15/in deleted file mode 100644 index 491155f..0000000 --- a/test/15/in +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env shsub -<% foo=hello - bar=world - foobar=END --%> -<%= - -$foo %>, <%=%><%=$bar%>.<%= %> <%= $foobar - -%>. diff --git a/test/15/out b/test/15/out deleted file mode 100644 index 433bd15..0000000 --- a/test/15/out +++ /dev/null @@ -1 +0,0 @@ -hello, world. END. diff --git a/test/15/run b/test/15/run deleted file mode 100755 index 08706b0..0000000 --- a/test/15/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -shsub in >progout -diff out progout diff --git a/test/16/in b/test/16/in deleted file mode 100644 index 491155f..0000000 --- a/test/16/in +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env shsub -<% foo=hello - bar=world - foobar=END --%> -<%= - -$foo %>, <%=%><%=$bar%>.<%= %> <%= $foobar - -%>. diff --git a/test/16/out b/test/16/out deleted file mode 100644 index 433bd15..0000000 --- a/test/16/out +++ /dev/null @@ -1 +0,0 @@ -hello, world. END. diff --git a/test/16/run b/test/16/run deleted file mode 100755 index 39f1e6c..0000000 --- a/test/16/run +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -chmod +x in -./in >progout -diff out progout diff --git a/test/17/in b/test/17/in deleted file mode 100755 index 0da6b47..0000000 --- a/test/17/in +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env shsub -We've learnt: - -<% for i in "$@"; do -%> -- <%= $i %> -<% done -%> diff --git a/test/17/out b/test/17/out deleted file mode 100644 index 21e168b..0000000 --- a/test/17/out +++ /dev/null @@ -1,5 +0,0 @@ -We've learnt: - -- let the machine do the work -- let other people do the work -- do the job in stages diff --git a/test/17/run b/test/17/run deleted file mode 100755 index 808cce1..0000000 --- a/test/17/run +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -chmod +x in -./in \ - "let the machine do the work" \ - "let other people do the work" \ - "do the job in stages" \ - >progout -diff out progout diff --git a/test/18/in b/test/18/in deleted file mode 100755 index 2c334c6..0000000 --- a/test/18/in +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env shsub -We've learnt from <%=$progname%>: - -<% for i in "$@"; do -%> -- <%= $i %> -<% done -%> diff --git a/test/18/out b/test/18/out deleted file mode 100644 index 9feb881..0000000 --- a/test/18/out +++ /dev/null @@ -1,5 +0,0 @@ -We've learnt from ./in: - -- let the machine do the work -- let other people do the work -- do the job in stages diff --git a/test/18/run b/test/18/run deleted file mode 100755 index 808cce1..0000000 --- a/test/18/run +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -chmod +x in -./in \ - "let the machine do the work" \ - "let other people do the work" \ - "do the job in stages" \ - >progout -diff out progout diff --git a/test/19/in b/test/19/in deleted file mode 100755 index 2c334c6..0000000 --- a/test/19/in +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env shsub -We've learnt from <%=$progname%>: - -<% for i in "$@"; do -%> -- <%= $i %> -<% done -%> diff --git a/test/19/out b/test/19/out deleted file mode 100644 index 71c7264..0000000 --- a/test/19/out +++ /dev/null @@ -1,5 +0,0 @@ -We've learnt from -: - -- let the machine do the work -- let other people do the work -- do the job in stages diff --git a/test/19/run b/test/19/run deleted file mode 100755 index 31d078c..0000000 --- a/test/19/run +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -progout -diff out progout diff --git a/test/2/in b/test/2/in deleted file mode 100644 index f27a744..0000000 --- a/test/2/in +++ /dev/null @@ -1,2 +0,0 @@ -<% %> -<%=%> diff --git a/test/2/out b/test/2/out deleted file mode 100644 index 139597f..0000000 --- a/test/2/out +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/test/2/run b/test/2/run deleted file mode 100755 index ff612bc..0000000 --- a/test/2/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -shsub progout -diff out progout diff --git a/test/3/in b/test/3/in deleted file mode 100644 index ae64ff3..0000000 --- a/test/3/in +++ /dev/null @@ -1,5 +0,0 @@ -<% name=shsub - desc="substitute embedded shell commands and expressions with \ -their outputs and results" -%><%=$name%> <%=$desc%>. -Best wish. diff --git a/test/3/out b/test/3/out deleted file mode 100644 index 0c8b95e..0000000 --- a/test/3/out +++ /dev/null @@ -1,2 +0,0 @@ -shsub substitute embedded shell commands and expressions with their outputs and results. -Best wish. diff --git a/test/3/run b/test/3/run deleted file mode 100755 index ff612bc..0000000 --- a/test/3/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -shsub progout -diff out progout diff --git a/test/4/in b/test/4/in deleted file mode 100644 index 9fa8481..0000000 --- a/test/4/in +++ /dev/null @@ -1,3 +0,0 @@ -<% notes='note1 <%%note2 note3%%> note4' -%><% for i in $notes; do%><%=- <%%$i%%>%> -<% done-%> diff --git a/test/4/out b/test/4/out deleted file mode 100644 index 489781e..0000000 --- a/test/4/out +++ /dev/null @@ -1,4 +0,0 @@ -- <%note1%> -- <%<%note2%> -- <%note3%>%> -- <%note4%> diff --git a/test/4/run b/test/4/run deleted file mode 100755 index ff612bc..0000000 --- a/test/4/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -shsub progout -diff out progout diff --git a/test/5/err b/test/5/err deleted file mode 100644 index e15ca55..0000000 --- a/test/5/err +++ /dev/null @@ -1 +0,0 @@ -shsub: unexpected token %> at line 2 diff --git a/test/5/in b/test/5/in deleted file mode 100644 index b8b215a..0000000 --- a/test/5/in +++ /dev/null @@ -1,2 +0,0 @@ -<% echo hello world %> -%> this line has an error diff --git a/test/5/run b/test/5/run deleted file mode 100755 index 8d18dc0..0000000 --- a/test/5/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -shsub /dev/null 2>progerr -diff err progerr diff --git a/test/6/err b/test/6/err deleted file mode 100644 index 3410d04..0000000 --- a/test/6/err +++ /dev/null @@ -1 +0,0 @@ -shsub: unexpected token %> at line 1 diff --git a/test/6/in b/test/6/in deleted file mode 100644 index b5a8057..0000000 --- a/test/6/in +++ /dev/null @@ -1,4 +0,0 @@ -%> -<% -<% echo hello world %> -%> this line has an error diff --git a/test/6/run b/test/6/run deleted file mode 100755 index c60216d..0000000 --- a/test/6/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -shsub in >/dev/null 2>progerr -diff err progerr diff --git a/test/7/in b/test/7/in deleted file mode 100644 index e69de29..0000000 diff --git a/test/7/out b/test/7/out deleted file mode 100644 index e69de29..0000000 diff --git a/test/7/run b/test/7/run deleted file mode 100755 index 08706b0..0000000 --- a/test/7/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -shsub in >progout -diff out progout diff --git a/test/8/in b/test/8/in deleted file mode 100644 index 927c3c1..0000000 --- a/test/8/in +++ /dev/null @@ -1 +0,0 @@ -<% read foo bar %><%=$(echo $foo, $bar)%> diff --git a/test/8/out b/test/8/out deleted file mode 100644 index 4b5fa63..0000000 --- a/test/8/out +++ /dev/null @@ -1 +0,0 @@ -hello, world diff --git a/test/8/run b/test/8/run deleted file mode 100644 index fb9da74..0000000 --- a/test/8/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -echo hello world | shsub in >progout -diff out progout diff --git a/test/9/in b/test/9/in deleted file mode 100644 index 33a8eb5..0000000 --- a/test/9/in +++ /dev/null @@ -1,3 +0,0 @@ -<% for i in a b c d e; do -%> -- <%=$i%> -<% done -%> diff --git a/test/9/out b/test/9/out deleted file mode 100644 index 4ead9f9..0000000 --- a/test/9/out +++ /dev/null @@ -1,5 +0,0 @@ -- a -- b -- c -- d -- e diff --git a/test/9/run b/test/9/run deleted file mode 100755 index ff612bc..0000000 --- a/test/9/run +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -shsub progout -diff out progout diff --git a/version b/version deleted file mode 100644 index 9df886c..0000000 --- a/version +++ /dev/null @@ -1 +0,0 @@ -1.4.2