diff options
-rw-r--r-- | subtext.awk | 95 | ||||
-rwxr-xr-x | subtext.sh | 57 | ||||
-rw-r--r-- | test.st | 4 |
3 files changed, 121 insertions, 35 deletions
diff --git a/subtext.awk b/subtext.awk index c3e135b..ee04238 100644 --- a/subtext.awk +++ b/subtext.awk | |||
@@ -2,17 +2,13 @@ | |||
2 | # (C) C Duckworth <acdw@acdw.net> | 2 | # (C) C Duckworth <acdw@acdw.net> |
3 | 3 | ||
4 | BEGIN { | 4 | BEGIN { |
5 | true = 1; false = 0 | ||
5 | ## Tuneables | 6 | ## Tuneables |
6 | postproc = get_value(postproc, "ST_POSTPROC", "shexpand") | 7 | runbody = bool(runbody ? runbody : true) |
7 | bodyfunc = get_value(bodyfunc, "ST_BODYFUNC", "sub_text") | 8 | postproc = postproc ? postproc : "shexpand" |
8 | sopath = get_value(sopath, "ST_SOPATH", ".:"ENVIRON["HOME"]"/.subtext") | 9 | bodyfunc = bodyfunc ? bodyfunc : "body" |
9 | split(sopath, asopath, ":") | 10 | sopath = get_value(sopath, ".:"ENVIRON["HOME"]"/.subtext") |
10 | # postproc = postproc ? postproc : "shexpand" | ||
11 | # bodyfunc = bodyfunc ? bodyfunc : "sub_text" | ||
12 | ## Globals | 11 | ## Globals |
13 | # Booleans | ||
14 | true = 1 | ||
15 | false = 0 | ||
16 | ## Wrap the text in a function | 12 | ## Wrap the text in a function |
17 | pretext = "### begin text\n"bodyfunc"(){\n" | 13 | pretext = "### begin text\n"bodyfunc"(){\n" |
18 | posttext = "}\n### end text" | 14 | posttext = "}\n### end text" |
@@ -47,7 +43,7 @@ BEGIN { | |||
47 | ### End a block | 43 | ### End a block |
48 | 44 | ||
49 | end[endn] && $0 == end[endn] { | 45 | end[endn] && $0 == end[endn] { |
50 | par = par "\n" end[endn--] "\n)" | 46 | pushpar(end[endn--] "\n)", true) |
51 | printpar() | 47 | printpar() |
52 | subdocp = false | 48 | subdocp = false |
53 | next | 49 | next |
@@ -64,27 +60,31 @@ end[endn] && $0 == end[endn] { | |||
64 | ### Special commands | 60 | ### Special commands |
65 | ## These call subtext-internal functions | 61 | ## These call subtext-internal functions |
66 | 62 | ||
67 | /^\.so/ { # Insert $2 verbatim (if in sopath), else error | 63 | /^#so/ { # Insert $2 verbatim (if in sopath), else error |
64 | pushpar($0) | ||
68 | source($2) | 65 | source($2) |
69 | next | 66 | next |
70 | } | 67 | } |
71 | 68 | ||
72 | ### Escape sequences | 69 | /^###$/ { # Delimit document |
73 | |||
74 | /^\.\.\./ { # Delimit document (end is optional) | ||
75 | printpar() | 70 | printpar() |
76 | docp = !docp | 71 | docp = !docp |
77 | if (docp) print pretext "unpreface ':'<<'_'|eval \"$ST_POSTPROC\"" | 72 | if (docp) { |
78 | else end_text() | 73 | print pretext "unpreface ':'<<'_'|eval \"$ST_POSTPROC\"" |
74 | } else { | ||
75 | end_text() | ||
76 | } | ||
79 | next | 77 | next |
80 | } | 78 | } |
81 | 79 | ||
80 | ### Escape sequences | ||
81 | |||
82 | /^\.\./ && docp { # Begin a heredoc | 82 | /^\.\./ && docp { # Begin a heredoc |
83 | # ..[<command>] [<options>] [<<delim] | 83 | # ..[<command>] [<options>] [<<delim] |
84 | ## ends with DELIM or '..' | 84 | ## ends with DELIM or '..' |
85 | subdocp = true | 85 | subdocp = true |
86 | end[++endn] = (match($0,"<<") ? substr($0,RSTART+RLENGTH) : "..") | 86 | end[++endn] = (match($0, "<<") ? substr($0, RSTART + RLENGTH) : "..") |
87 | command = substr($0, 3, RSTART ? RSTART - 2 : length) | 87 | command = substr($0, 3, RSTART ? RSTART - 2 : length($0)) |
88 | $0 = "$$(" (command ? command : "cat") "<<" end[endn] | 88 | $0 = "$$(" (command ? command : "cat") "<<" end[endn] |
89 | } | 89 | } |
90 | 90 | ||
@@ -92,9 +92,11 @@ end[endn] && $0 == end[endn] { | |||
92 | # .<command> [<parameters>] | 92 | # .<command> [<parameters>] |
93 | ## wraps the line in $( ... ), basically (also quotes) | 93 | ## wraps the line in $( ... ), basically (also quotes) |
94 | specialp = 2 | 94 | specialp = 2 |
95 | gsub(/"/,"\\\\&") | 95 | gsub(/"/, "\\\\&", $0) |
96 | ln = "$$(" substr($1, 2) | 96 | ln = "$$(" substr($1, 2) |
97 | for (f=2;f<=NF;f++) ln = ln " \"" $f "\"" | 97 | for (f=2; f<=NF; f++) { |
98 | ln = ln " \"" $f "\"" | ||
99 | } | ||
98 | ln = ln ")" | 100 | ln = ln ")" |
99 | $0 = ln | 101 | $0 = ln |
100 | } | 102 | } |
@@ -106,53 +108,80 @@ end[endn] && $0 == end[endn] { | |||
106 | ### Book-keeping | 108 | ### Book-keeping |
107 | 109 | ||
108 | /^$/ { | 110 | /^$/ { |
109 | if (!par) next | 111 | if (!par) |
112 | next | ||
110 | printpar() | 113 | printpar() |
111 | } | 114 | } |
112 | 115 | ||
113 | { par = par (par?"\n":"") $0 } | 116 | { |
114 | { if (--specialp < 0) specialp = 0 } | 117 | pushpar($0) |
118 | if (--specialp < 0) | ||
119 | specialp = 0 | ||
120 | } | ||
115 | 121 | ||
116 | END { | 122 | END { |
117 | if (dead) exit dead | 123 | if (dead) |
118 | if (par) printpar() | 124 | exit dead |
125 | if (par) | ||
126 | printpar() | ||
119 | while (endn > 0) | 127 | while (endn > 0) |
120 | print "\n" end[endn--] "\n)" | 128 | print "\n" end[endn--] "\n)" |
121 | if (docp) end_text() | 129 | if (docp) |
130 | end_text() | ||
131 | if (runbody) | ||
132 | print bodyfunc | ||
122 | } | 133 | } |
123 | 134 | ||
124 | function end_text() { | 135 | function end_text() { |
125 | print "_\n" posttext | 136 | print "_\n" posttext |
126 | } | 137 | } |
127 | 138 | ||
139 | function pushpar(text, force_newline) { | ||
140 | par = par ((par || force_newline) ? "\n" : "") text | ||
141 | } | ||
142 | |||
128 | function printpar() { | 143 | function printpar() { |
129 | specialp = specialp || (match(par, /^[ ]*</)) | 144 | specialp = specialp || (match(par, /^[ ]*</)) |
130 | if (docp) { | 145 | if (docp) { |
131 | if (!subdocp && !specialp) par = "<p>" par "</p>" | 146 | if (!subdocp && !specialp) |
147 | par = "<p>" par "</p>" | ||
132 | shx = shellfix shxwrap | 148 | shx = shellfix shxwrap |
133 | print par | shx | 149 | print par | shx |
134 | close(shx) | 150 | close(shx) |
135 | } else print par | 151 | } else |
152 | print par | ||
136 | par = "" | 153 | par = "" |
137 | } | 154 | } |
138 | 155 | ||
139 | function get_value(var, env_var, default) { | 156 | function get_value(var, env_var, default) { |
140 | if (var) return var | 157 | if (var) |
141 | else if (ENVIRON[env_var]) return ENVIRON[env_var] | 158 | return var |
142 | else return default | 159 | else |
160 | return default | ||
161 | } | ||
162 | |||
163 | function bool(var, default) { | ||
164 | if (var=="false" || var=="no" || var=="0") | ||
165 | return false | ||
166 | else if (var=="true" || var=="yes" || var=="1") | ||
167 | return true | ||
168 | else | ||
169 | return var || default | ||
143 | } | 170 | } |
144 | 171 | ||
145 | function source(name) { | 172 | function source(name) { |
146 | found = false | 173 | found = false |
147 | sp = "" | 174 | sp = "" |
175 | split(sopath, asopath, ":") | ||
148 | for (dir in asopath) { | 176 | for (dir in asopath) { |
149 | fn = asopath[dir] "/" name | 177 | fn = asopath[dir] "/" name |
150 | sp = asopath[dir] "\n\t" sp | 178 | sp = asopath[dir] "\n\t" sp |
151 | while ((getline ln < fn) > 0) { | 179 | while ((getline ln < fn) > 0) { |
152 | found = true | 180 | found = true |
153 | par = par (par?"\n":"") ln | 181 | pushpar(ln) |
154 | } | 182 | } |
155 | if (found) break | 183 | if (found) |
184 | break | ||
156 | } | 185 | } |
157 | if (!found) | 186 | if (!found) |
158 | die("Couldn't source " name "; looked in:\n\t" sp, 9) | 187 | die("Couldn't source " name "; looked in:\n\t" sp, 9) |
diff --git a/subtext.sh b/subtext.sh new file mode 100755 index 0000000..d845955 --- /dev/null +++ b/subtext.sh | |||
@@ -0,0 +1,57 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | stawk() { | ||
4 | awk -f subtext.awk "$@" # SUBTEXT AWK SCRIPT HERE | ||
5 | } | ||
6 | |||
7 | usage() { | ||
8 | cat>&2 <<EOF | ||
9 | SUBTEXT v.meowmers (C) Case Duckworth | ||
10 | Usage: subtext [OPTIONS] FILE... | ||
11 | subtext < FILE | ||
12 | Options: | ||
13 | -h Show this help and exit. | ||
14 | -n Don't run the resulting script; just print it. | ||
15 | -m FILE Use macrofile FILE. | ||
16 | -I DIRECTORY Add DIRECTORY to the search path. | ||
17 | EOF | ||
18 | exit $1 | ||
19 | } | ||
20 | |||
21 | configure() { | ||
22 | ## Initialize state variables | ||
23 | : "${ST_MACROFILE:=}" | ||
24 | : "${ST_SOPATH:=.:$HOME/.subtext}" | ||
25 | : "${ST_PIPE_SH:=true}" | ||
26 | ## Process options | ||
27 | while getopts :hm:I:n OPT | ||
28 | do | ||
29 | case "$OPT" in | ||
30 | (h) usage ;; | ||
31 | (m) ST_MACROFILE="$OPTARG" ;; | ||
32 | (I) ST_SOPATH="$ST_SOPATH:$OPTARG" ;; | ||
33 | (n) ST_PIPE_SH=false ;; | ||
34 | (:) printf >&2 'Unknown option -%s\n' "$OPTARG"; | ||
35 | usage 1 ;; | ||
36 | (*) usage 1 ;; | ||
37 | esac | ||
38 | done | ||
39 | } | ||
40 | |||
41 | main() { | ||
42 | configure "$@" | ||
43 | shift $((OPTIND-1)) | ||
44 | stawk -vsopath="$ST_SOPATH" "$@" | | ||
45 | if "$ST_PIPE_SH" | ||
46 | then sh | ||
47 | else cat | ||
48 | fi | ||
49 | } | ||
50 | |||
51 | die() { | ||
52 | ec="$1"; shift | ||
53 | printf >&2 '!! %s\n' "$*" | ||
54 | exit "$ec" | ||
55 | } | ||
56 | |||
57 | main "$@" | ||
diff --git a/test.st b/test.st index b11bd87..18319fe 100644 --- a/test.st +++ b/test.st | |||
@@ -1,7 +1,7 @@ | |||
1 | .so etlib.sh | 1 | #so etlib.sh |
2 | alias verse=cat | 2 | alias verse=cat |
3 | title="test file" | 3 | title="test file" |
4 | ... | 4 | ### |
5 | here's a test file | 5 | here's a test file |
6 | .a href="https://example.com" a link or something!! | 6 | .a href="https://example.com" a link or something!! |
7 | 7 | ||