Rename preamble to newfangle.sty
[newfangle.git] / newfangle
blob15cb12793bd529e87a0b789d8c6eaf2bfd2814f0
1 #! /usr/bin/awk -f
2 # newfangle - fully featured notangle replacement in awk
3 #
4 # Copyright (C) Sam Liddicott 2009
5 #
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 # NOTE: Arnold Robbins public domain getopt for awk is also used:
20 # getopt.awk --- do C library getopt(3) function in awk
22 # Arnold Robbins, arnold@skeeve.com, Public Domain
24 # Initial version: March, 1991
25 # Revised: May, 1993
26 function getopt(argc, argv, options, thisopt, i)
28 if (length(options) == 0) # no options given
29 return -1
30 if (argv[Optind] == "--") { # all done
31 Optind++
32 _opti = 0
33 return -1
34 } else if (argv[Optind] !~ /^-[^: \t\n\f\r\v\b]/) {
35 _opti = 0
36 return -1
38 if (_opti == 0)
39 _opti = 2
40 thisopt = substr(argv[Optind], _opti, 1)
41 Optopt = thisopt
42 i = index(options, thisopt)
43 if (i == 0) {
44 if (Opterr)
45 printf("%c -- invalid option\n",
46 thisopt) > "/dev/stderr"
47 if (_opti >= length(argv[Optind])) {
48 Optind++
49 _opti = 0
50 } else
51 _opti++
52 return "?"
54 if (substr(options, i + 1, 1) == ":") {
55 # get option argument
56 if (length(substr(argv[Optind], _opti + 1)) > 0)
57 Optarg = substr(argv[Optind], _opti + 1)
58 else
59 Optarg = argv[++Optind]
60 _opti = 0
61 } else
62 Optarg = ""
63 if (_opti == 0 || _opti >= length(argv[Optind])) {
64 Optind++
65 _opti = 0
66 } else
67 _opti++
68 return thisopt
71 function error(message)
73 print message > "/dev/stderr";
74 exit 1;
76 function new_chunk(chunk_name, params,
77 # local vars
78 p )
80 active_chunk = chunk_name;
81 if (! (chunk_name in chunk_names)) {
82 if (debug) print "New chunk " chunk_name;
83 chunk_names[chunk_name];
84 for (p in params) {
85 chunks[chunk_name, p] = params[p];
88 prime_chunk(chunk_name);
91 function prime_chunk(chunk_name)
93 chunks[chunk_name, "part", ++chunks[chunk_name, "part"] ] = \
94 chunk_name SUBSEP "chunklet" SUBSEP "" ++chunks[chunk_name, "chunklet"];
95 chunks[chunk_name, "part", chunks[chunk_name, "part"], "FILENAME"] = FILENAME;
96 chunks[chunk_name, "part", chunks[chunk_name, "part"], "LINENO"] = FNR + 1;
99 function chunk_line(chunk_name, line){
100 chunks[chunk_name, "chunklet", chunks[chunk_name, "chunklet"],
101 ++chunks[chunk_name, "chunklet", chunks[chunk_name, "chunklet"], "line"] ] = line;
104 function chunk_include(chunk_name, chunk_ref, indent, tail)
106 chunks[chunk_name, "part", ++chunks[chunk_name, "part"] ] = chunk_ref;
107 chunks[chunk_name, "part", chunks[chunk_name, "part"], "type" ] = part_type_chunk;
108 chunks[chunk_name, "part", chunks[chunk_name, "part"], "indent" ] = indent;
109 chunks[chunk_name, "part", chunks[chunk_name, "part"], "tail" ] = tail;
110 prime_chunk(chunk_name);
112 function write_chunk_names( c, prefix, suffix)
114 if (notangle_mode) {
115 prefix="<<";
116 suffix=">>";
118 for (c in chunk_names) {
119 print prefix c suffix;
122 function write_chunks( a)
124 for (a in chunk_names) {
125 write_chunk(chunk_names[a]);
128 function write_chunk(chunk_name, indent, tail,
129 # optional vars
130 chunk_path,
131 # local vars
132 part, max_part, line, max_line, chunklet, only_part, chunk_args)
134 if (match(chunk_name, "^(.*){(.*)}$", chunk_name_parts)) {
135 chunk_name = chunk_name_parts[1];
136 split(chunk_name_parts[2], chunk_args, " *, *");
138 if (match(chunk_name, "^(.*)\\[([0-9]*)\\]$", chunk_name_parts)) {
139 chunk_name = chunk_name_parts[1];
140 only_part = chunk_name_parts[2];
142 split(chunks[chunk_name, "params"], chunk_params, " *; *");
143 if (! (chunk_name in chunk_names)) {
144 error(sprintf(_"The root module <<%s>> was not defined.\nUsed by: %s",\
145 chunk_name, chunk_path));
148 max_part = chunks[chunk_name, "part"];
149 for(part = 1; part <= max_part; part++) {
150 if (! only_part || part == only_part) {
151 chunklet = chunks[chunk_name, "part", part];
152 if (chunks[chunk_name, "part", part, "type"] == part_type_chunk) {
153 write_chunk(chunklet, indent chunks[chunk_name, "part", part, "indent"],
154 chunks[chunk_name, "part", part, "tail"],
155 chunk_path "\n " chunk_name);
156 } else if (chunklet SUBSEP "line" in chunks) {
157 if (linenos && (chunk_name SUBSEP "part" SUBSEP part SUBSEP "FILENAME" in chunks)) {
158 if (! lineno_suppressed) {
159 a_filename = chunks[chunk_name, "part", part, "FILENAME"];
160 a_lineno = chunks[chunk_name, "part", part, "LINENO"];
161 if (a_filename != filename || a_lineno != lineno || lineno_needed) {
162 filename = a_filename;
163 lineno = a_lineno;
164 print "#line " lineno " \"" filename "\""
166 lineno_needed=0;
167 } else {
168 lineno_needed=1;
172 max_line = chunks[chunklet, "line"];
173 for(line = 1; line <= max_line; line++) {
174 lastline = chunks[chunklet, line];
176 /* check params */
177 # if (length(chunk_args)) {
178 lastline = expand_chunk_args(lastline, chunk_params, chunk_args);
181 lastline = indent lastline tail;
182 print lastline;
183 if (linenos) {
184 lineno_suppressed = substr(lastline, length(lastline)) == "\\";
186 lineno++;
188 } else {
189 # empty last chunklet
194 function expand_chunk_args(text, params, args,
195 p, text_array, next_text, v, t, l)
197 if (split(text, text_array, "\\${")) {
198 for(p in params) {
199 v[params[p]]=args[p];
201 text=text_array[1];
202 for(t in text_array) if (t>1) {
203 # check the text up to } for a parameter and replace with arg
204 if (match(text_array[t], "^([a-zA-Z_][a-zA-Z0-9_]*)}", l) &&
205 l[1] in v)
207 text = text v[l[1]] substr(text_array[t], length(l[1])+2);
208 } else {
209 text = text "${" text_array[t];
213 return text;
215 BEGIN {
216 part_type_chunk=1;
217 debug=0;
218 linenos=0;
219 notangle_mode=0;
220 SUBSEP=",";
221 root="*";
223 Optind = 1 # skip ARGV[0]
224 while(getopt(ARGC, ARGV, "R:Ldhr")!=-1) {
225 if (Optopt == "R") root = Optarg;
226 else if (Optopt == "r") root="";
227 else if (Optopt == "L") linenos = 1;
228 else if (Optopt == "d") debug = 1;
229 else if (Optopt == "h") help();
230 else if (Optopt == "?") help();
232 for (i=1; i<Optind; i++) { ARGV[i]=""; }
234 /^\\Chunk{/ {
235 if (match($0, "^\\\\Chunk{ *([^ ,}]*),?(.*)}", line)) {
236 next_chunk_name=line[1];
237 get_chunk_args(line[2], next_chunk_args);
239 next;
241 /^\\begin{lstlisting}/ {
242 if (match($0, "}.*[[,] *name= *{? *([^], }]*)", line)) {
243 new_chunk(line[1]);
244 } else {
245 new_chunk(next_chunk_name, next_chunk_args);
247 chunking=1;
248 next;
250 /^\\begin{CodeScrap}|^\\begin{Chunk}/ {
251 chunking=1;
252 next;
254 /^\\item *\[{/ && chunking {
255 if (match($0, "^\\\\item *\\[{(.*[^ ]) *}\\]", line)) {
256 new_chunk(line[1]);
257 next;
260 /^[<]<.*[>]>=/ {
261 if (match($0, "^[<]<(.*)[>]>= *$", line)) {
262 chunking=1;
263 notangle_mode=1;
264 new_chunk(line[1]);
265 next;
268 /^\\[e]nd{lstlisting}/ {
269 chunking=0;
270 active_chunk="";
271 next;
273 /^\\end{CodeScrap}|^\\end{Chunk}|^@/ {
274 chunking=0;
275 active_chunk="";
277 /^@/ {
278 chunking=0;
279 active_chunk="";
281 ! chunking { next; }
282 /^.*[=]<\\chunkref{/ {
283 if (match($0, "^(.*)[=]<\\\\chunkref{(.*)}>(.*)", line)) {
284 chunk_include(active_chunk, line[2], line[1], line[3]);
285 next;
288 /^.*\\e[m][p][h]{/ {
289 if (match($0, "^(.*)\\\\e[m][p][h]{([^}]*)}(.*)", line)) {
290 chunk_include(active_chunk, line[2], line[1], line[3]);
291 next;
294 /^[#\/ ]*[<]<.*[>]>/ && (length(active_chunk)) {
295 if (match($0, "^(.*)[<]<(.*)[>]>(.*)", line)) {
296 chunk_include(active_chunk, line[2], line[1], line[3]);
297 next;
300 length(active_chunk) {
301 chunk_line(active_chunk, $0);
303 END {
304 if (debug) {
305 print "------ chunk names "
306 write_chunk_names();
307 print "====== chunks"
308 write_chunks();
309 print "++++++ debug"
310 for (a in chunks) {
311 print a "=" chunks[a];
314 if (length(root)) write_chunk(root);
315 else write_chunk_names();
317 function get_chunk_args(text, values,
318 # optional parameters
319 path,
320 # local vars
321 a, name)
323 while(length(text)) {
324 if (match(text, "^ *}(.*)", a)) {
325 return a[1];
327 if (! match(text, " *([^,=]*[^,= ]) *(([,=]) *(([^,}]*) *,* *(.*))|)$", a)) {
328 return text;
330 name=a[1];
331 if (a[3] == "=") {
332 if (substr(a[4],1,1) == "{") {
333 text = get_chunk_args(substr(a[4],2), values, path name SUBSEP);
334 } else {
335 values[path name]=a[5];
336 text = a[6];
338 } else {
339 values[path name]="";
340 text = a[2];
343 return text;