diff options
-rw-r--r-- | subtext.awk | 81 | ||||
-rwxr-xr-x | subtext.sh | 13 |
2 files changed, 73 insertions, 21 deletions
diff --git a/subtext.awk b/subtext.awk index 09ec882..07dfb76 100644 --- a/subtext.awk +++ b/subtext.awk | |||
@@ -9,7 +9,8 @@ | |||
9 | BEGIN { | 9 | BEGIN { |
10 | ## Tuneables | 10 | ## Tuneables |
11 | dryrun = dryrun ? dryrun : 0 | 11 | dryrun = dryrun ? dryrun : 0 |
12 | sopath = sopath ? sopath : ".:" ENVIRON["HOME"] "/.subtext" | 12 | sopath = sopath ? sopath : "." |
13 | sofile = sofile ? sofile : "" | ||
13 | shxend = shxend ? shxend : "%%end" | 14 | shxend = shxend ? shxend : "%%end" |
14 | ## Shellfix: escape ` and $ in input | 15 | ## Shellfix: escape ` and $ in input |
15 | # Ask sed to do these b/c awk has no capture groups ;_; | 16 | # Ask sed to do these b/c awk has no capture groups ;_; |
@@ -25,34 +26,60 @@ BEGIN { | |||
25 | $0 = $0 " " nl | 26 | $0 = $0 " " nl |
26 | } | 27 | } |
27 | 28 | ||
28 | /^#so/ { # source a file | 29 | ### AWK layer |
30 | |||
31 | /^%so/ { # source a file | ||
29 | pushpar() | 32 | pushpar() |
30 | source($2) | 33 | source($2) |
31 | next | 34 | next |
32 | } | 35 | } |
33 | 36 | ||
37 | /^%/ { next } # comments | ||
38 | |||
39 | ### Shell layer | ||
40 | |||
34 | /^#/ { # head lines | 41 | /^#/ { # head lines |
35 | sub(/^#+[ ]*/,"") | 42 | sub(/^#+[ ]*/,"") |
36 | head = head (head?"\n":"") $0 | 43 | head = head (head?"\n":"") $0 |
37 | next | 44 | next |
38 | } | 45 | } |
39 | 46 | ||
47 | ### Text layer | ||
48 | |||
49 | end[endn] && $0 == end[endn] { | ||
50 | par = par "\n" end[endn--] "\n)" | ||
51 | next | ||
52 | } | ||
53 | |||
40 | /^\.\./ { # block | 54 | /^\.\./ { # block |
41 | body = body (body?"\n":"") \ | 55 | if (match($0, /[ ]*<<[ ]*/)) |
42 | "$$(unquote + << .." \ | 56 | end[++endn] = substr($0, RSTART+RLENGTH) |
43 | (length>2 ? " | " substr($1,3) " " shquote(2) : "") \ | 57 | else |
44 | slurp("..") \ | 58 | end[++endn] = ".." |
45 | "..\n)" | 59 | $0 = substr($0, 3, RSTART?RSTART-3:length) |
60 | par = par (par?"\n":"") \ | ||
61 | "$$(" ($1 ? $1 " " shquote(2) : "") " << " end[endn] | ||
62 | # par = par (par?"\n":"") \ | ||
63 | # "$$(unquote + << .." \ | ||
64 | # (length>2 ? " | " substr($1,3) " " shquote(2) : "") \ | ||
65 | # slurp("..") \ | ||
66 | # "..\n)" | ||
46 | next | 67 | next |
47 | } | 68 | } |
48 | 69 | ||
70 | /^\.$/ { next } # continuation line | ||
71 | |||
49 | /^\./ { # line | 72 | /^\./ { # line |
50 | body = body (body?"\n":"") \ | 73 | par = par (body?"\n":"") \ |
51 | "$$(" substr($1, 2) " " shquote(2) ")" | 74 | "$$(" substr($1, 2) " " shquote(2) ")" |
52 | next | 75 | next |
53 | } | 76 | } |
54 | 77 | ||
55 | /^$/ { # line break | 78 | /^\\/ { # special line escape |
79 | $0 = substr($0, 2) | ||
80 | } | ||
81 | |||
82 | /^$/ { # blank line | ||
56 | if (!pushpar()) next | 83 | if (!pushpar()) next |
57 | } | 84 | } |
58 | 85 | ||
@@ -70,25 +97,45 @@ END { | |||
70 | printf "shexpand()(eval \"$(echo 'cat<<%s';cat;echo '%s')\")\n", \ | 97 | printf "shexpand()(eval \"$(echo 'cat<<%s';cat;echo '%s')\")\n", \ |
71 | shxend, shxend | 98 | shxend, shxend |
72 | printf "shellfix()(%s)\n", shellfix | 99 | printf "shellfix()(%s)\n", shellfix |
100 | print "echo()(printf '%s\\n' \"$@\")" | ||
101 | print "handle_input()("\ | ||
102 | "test -n \"$1\" && printf '%s' \"$*\";"\ | ||
103 | "if read -r first_line;"\ | ||
104 | "then echo \"$first_line\";cat;return 0;"\ | ||
105 | "else echo;return 1;fi)" | ||
73 | printf "ST_SOPATH=%s\n", sopath | 106 | printf "ST_SOPATH=%s\n", sopath |
107 | if (sofile) source(sofile) | ||
74 | print "### head" | 108 | print "### head" |
75 | print head | 109 | print head |
76 | print "### body" | 110 | print "### body" |
77 | print "body(){ unquote : << \\_ | shexpand" | 111 | print "body(){ unquote : << \\_ | shexpand" |
78 | pushpar() | 112 | pushpar() |
79 | print body | (shellfix " -e 's/^/:/'") | 113 | shfq = shellfix " -e 's/^/:/'" |
80 | close(shellfix " -e 's/^/:/'") | 114 | print body | shfq |
115 | close(shfq) | ||
81 | print "_" | 116 | print "_" |
82 | print "}" | 117 | print "}" |
83 | if (!dryrun) print "body" | 118 | if (!dryrun) print "body" |
84 | } | 119 | } |
85 | 120 | ||
86 | function shquote(begin, end, out) { | 121 | function shquote(begin, end, quoted, out) { |
87 | if (!begin) begin = 1 | 122 | if (!begin) begin = 1 |
88 | if (!end) end = NF | 123 | if (!end) end = NF |
89 | for (i=begin; i<=NF; i++) { | 124 | for (i=begin; i<=NF; i++) { |
90 | gsub(/"/, "\\\"", $i) | 125 | if ($i ~ /^\$/) { |
91 | out = out (out?" ":"") "\"" $i "\"" | 126 | quoted = 1 |
127 | out = out (out?" ":"") "\"" $i | ||
128 | continue | ||
129 | } | ||
130 | if (($i ~ /\)$/) && quoted) { | ||
131 | quoted = 0 | ||
132 | out = out (out?" ":"") $i "\"" | ||
133 | continue | ||
134 | } | ||
135 | if (!quoted) { | ||
136 | gsub(/"/, "\\\"", $i) | ||
137 | out = out (out?" ":"") "\"" $i "\"" | ||
138 | } else out = out (out?" ":"") $i | ||
92 | } | 139 | } |
93 | return out | 140 | return out |
94 | } | 141 | } |
@@ -104,8 +151,9 @@ function slurp(to, out, nl) { | |||
104 | 151 | ||
105 | function pushpar() { | 152 | function pushpar() { |
106 | if (!par) return 0 | 153 | if (!par) return 0 |
107 | if (!match(par, /^[ ]*</)) | 154 | if (!match(par, /^[ \t\n]*[<$]/)) { |
108 | par = "<p>" par "</p>" | 155 | par = "$$(p<<../p\n" par "\n../p\n)" |
156 | } | ||
109 | body = body (body?"\n":"") par | 157 | body = body (body?"\n":"") par |
110 | par = "" | 158 | par = "" |
111 | return 1 | 159 | return 1 |
@@ -120,6 +168,7 @@ function source(name, found, sp) { | |||
120 | found = 1 | 168 | found = 1 |
121 | head = head (head?"\n":"") ln | 169 | head = head (head?"\n":"") ln |
122 | } | 170 | } |
171 | close(fn) | ||
123 | if (found) break | 172 | if (found) break |
124 | } | 173 | } |
125 | if (!found) { | 174 | if (!found) { |
diff --git a/subtext.sh b/subtext.sh index d845955..a60f0d6 100755 --- a/subtext.sh +++ b/subtext.sh | |||
@@ -1,7 +1,7 @@ | |||
1 | #!/bin/sh | 1 | #!/bin/sh |
2 | 2 | ||
3 | stawk() { | 3 | stawk() { |
4 | awk -f subtext.awk "$@" # SUBTEXT AWK SCRIPT HERE | 4 | awk -f subtext.awk "$@" |
5 | } | 5 | } |
6 | 6 | ||
7 | usage() { | 7 | usage() { |
@@ -23,14 +23,17 @@ configure() { | |||
23 | : "${ST_MACROFILE:=}" | 23 | : "${ST_MACROFILE:=}" |
24 | : "${ST_SOPATH:=.:$HOME/.subtext}" | 24 | : "${ST_SOPATH:=.:$HOME/.subtext}" |
25 | : "${ST_PIPE_SH:=true}" | 25 | : "${ST_PIPE_SH:=true}" |
26 | : "${ST_TRACE=+x}" | ||
26 | ## Process options | 27 | ## Process options |
27 | while getopts :hm:I:n OPT | 28 | while getopts :hm:I:no:x OPT |
28 | do | 29 | do |
29 | case "$OPT" in | 30 | case "$OPT" in |
30 | (h) usage ;; | 31 | (h) usage ;; |
31 | (m) ST_MACROFILE="$OPTARG" ;; | 32 | (m) ST_MACROFILE="$OPTARG.st.sh" ;; |
32 | (I) ST_SOPATH="$ST_SOPATH:$OPTARG" ;; | 33 | (I) ST_SOPATH="$ST_SOPATH:$OPTARG" ;; |
33 | (n) ST_PIPE_SH=false ;; | 34 | (n) ST_PIPE_SH=false ;; |
35 | (o) exec > "$OPTARG" ;; | ||
36 | (x) ST_TRACE=-x ;; | ||
34 | (:) printf >&2 'Unknown option -%s\n' "$OPTARG"; | 37 | (:) printf >&2 'Unknown option -%s\n' "$OPTARG"; |
35 | usage 1 ;; | 38 | usage 1 ;; |
36 | (*) usage 1 ;; | 39 | (*) usage 1 ;; |
@@ -41,9 +44,9 @@ configure() { | |||
41 | main() { | 44 | main() { |
42 | configure "$@" | 45 | configure "$@" |
43 | shift $((OPTIND-1)) | 46 | shift $((OPTIND-1)) |
44 | stawk -vsopath="$ST_SOPATH" "$@" | | 47 | stawk -vsopath="$ST_SOPATH" -vsofile="$ST_MACROFILE" "$@" | |
45 | if "$ST_PIPE_SH" | 48 | if "$ST_PIPE_SH" |
46 | then sh | 49 | then sh "$ST_TRACE" |
47 | else cat | 50 | else cat |
48 | fi | 51 | fi |
49 | } | 52 | } |