Fix link error
[newfangle.git] / newfangle
blobf4ada54fa9c99e0ecf42cad8fbccf17e3f1b9e02
1 #! /usr/bin/awk -f
2 # newfangle - fully featured notangle replacement in awk
4 # Copyright (C) Sam Liddicott 2009
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/>.
21 # NOTE: Arnold Robbins public domain getopt for awk is also used:
22 # getopt.awk --- do C library getopt(3) function in awk
24 # Arnold Robbins, arnold@skeeve.com, Public Domain
26 # Initial version: March, 1991
27 # Revised: May, 1993
30 function getopt(argc, argv, options, thisopt, i)
32 if (length(options) == 0) # no options given
33 return -1
34 if (argv[Optind] == "--") { # all done
35 Optind++
36 _opti = 0
37 return -1
38 } else if (argv[Optind] !~ /^-[^: \t\n\f\r\v\b]/) {
39 _opti = 0
40 return -1
42 if (_opti == 0)
43 _opti = 2
44 thisopt = substr(argv[Optind], _opti, 1)
45 Optopt = thisopt
46 i = index(options, thisopt)
47 if (i == 0) {
48 if (Opterr)
49 printf("%c -- invalid option\n",
50 thisopt) > "/dev/stderr"
51 if (_opti >= length(argv[Optind])) {
52 Optind++
53 _opti = 0
54 } else
55 _opti++
56 return "?"
58 if (substr(options, i + 1, 1) == ":") {
59 # get option argument
60 if (length(substr(argv[Optind], _opti + 1)) > 0)
61 Optarg = substr(argv[Optind], _opti + 1)
62 else
63 Optarg = argv[++Optind]
64 _opti = 0
65 } else
66 Optarg = ""
67 if (_opti == 0 || _opti >= length(argv[Optind])) {
68 Optind++
69 _opti = 0
70 } else
71 _opti++
72 return thisopt
75 function error(message)
77 print "ERROR: " FILENAME ":" FNR " " message > "/dev/stderr";
78 exit 1;
80 function warning(message)
82 print "WARNING: " FILENAME ":" FNR " " message > "/dev/stderr";
83 warnings++;
85 function new_mode_tracker(context, language, mode) {
86 context[""] = 0;
87 context[0, "language"] = language;
88 context[0, "mode"] = mode;
90 function push_mode_tracker(context, language, mode,
91 # local vars
92 top)
94 if (! ("" in context)) {
95 split("", context);
96 new_mode_tracker(context, language, mode);
97 } else {
98 top = context[""];
99 if (context[top, "language"] == language && mode=="") mode = context[top, "mode"];
100 top++;
101 context[top, "language"] = language;
102 context[top, "mode"] = mode;
103 context[""] = top;
106 function dump_mode_tracker(context,
107 c, d)
109 for(c=0; c <= context[""]; c++) {
110 printf(" %2d %s:%s\n", c, context[c, "language"], context[c, "mode"]) > "/dev/stderr";
111 for(d=1; ( (c, "values", d) in context); d++) {
112 printf(" %2d %s\n", d, context[c, "values", d]) > "/dev/stderr";
116 function finalize_mode_tracker(context)
118 if ( ("" in context) && context[""] != 0) return 0;
119 return 1;
121 function mode_tracker(context, text, values,
122 # optional parameters
123 # local vars
124 mode, submodes, language,
125 cindex, c, a, part, item, name, result, new_values, new_mode,
126 delimiters, terminators)
128 cindex = context[""] + 0;
129 mode = context[cindex, "mode"];
130 language = context[cindex, "language" ];
131 submodes=modes[language, mode, "submodes"];
133 if ((language, mode, "delimiters") in modes) {
134 delimiters = modes[language, mode, "delimiters"];
135 if (length(submodes)>0) submodes = submodes "|";
136 submodes=submodes delimiters;
137 } else delimiters="";
138 if ((language, mode, "terminators") in modes) {
139 terminators = modes[language, mode, "terminators"];
140 if (length(submodes)>0) submodes = submodes "|";
141 submodes=submodes terminators;
142 } else terminators="";
143 if (! length(submodes)) return text;
144 while((cindex >= 0) && length(text)) {
145 if (match(text, "(" submodes ")", a)) {
146 if (RLENGTH<1) {
147 error(sprintf("Internal error, matched zero length submode, should be impossible - likely regex computation error\n" \
148 "Language=%s\nmode=%s\nmatch=%s\n", language, mode, submodes));
150 part = substr(text, 1, RSTART -1);
151 item = item part;
152 if (match(a[1], "^" terminators "$")) {
153 #printf("%2d EXIT MODE [%s] by [%s] [%s]\n", cindex, mode, a[1], text) > "/dev/stderr"
154 context[cindex, "values", ++context[cindex, "values"]] = item;
155 delete context[cindex];
156 context[""] = --cindex;
157 if (cindex>=0) {
158 mode = context[cindex, "mode"];
159 language = context[cindex, "language"];
160 submodes=modes[language, mode, "submodes"];
162 if ((language, mode, "delimiters") in modes) {
163 delimiters = modes[language, mode, "delimiters"];
164 if (length(submodes)>0) submodes = submodes "|";
165 submodes=submodes delimiters;
166 } else delimiters="";
167 if ((language, mode, "terminators") in modes) {
168 terminators = modes[language, mode, "terminators"];
169 if (length(submodes)>0) submodes = submodes "|";
170 submodes=submodes terminators;
171 } else terminators="";
172 if (! length(submodes)) return text;
174 item = item a[1];
175 text = substr(text, 1 + length(part) + length(a[1]));
177 else if (match(a[1], "^" delimiters "$")) {
178 if (cindex==0) {
179 context[cindex, "values", ++context[cindex, "values"]] = item;
180 item = "";
181 } else {
182 item = item a[1];
184 text = substr(text, 1 + length(part) + length(a[1]));
186 else if ((language, a[1], "terminators") in modes) {
187 #check if new_mode is defined
188 item = item a[1];
189 #printf("%2d ENTER MODE [%s] in [%s]\n", cindex, a[1], text) > "/dev/stderr"
190 text = substr(text, 1 + length(part) + length(a[1]));
191 context[""] = ++cindex;
192 context[cindex, "mode"] = a[1];
193 context[cindex, "language"] = language;
194 mode = a[1];
195 submodes=modes[language, mode, "submodes"];
197 if ((language, mode, "delimiters") in modes) {
198 delimiters = modes[language, mode, "delimiters"];
199 if (length(submodes)>0) submodes = submodes "|";
200 submodes=submodes delimiters;
201 } else delimiters="";
202 if ((language, mode, "terminators") in modes) {
203 terminators = modes[language, mode, "terminators"];
204 if (length(submodes)>0) submodes = submodes "|";
205 submodes=submodes terminators;
206 } else terminators="";
207 if (! length(submodes)) return text;
208 } else {
209 error(sprintf("Submode '%s' set unknown mode in text: %s\nLanguage %s Mode %s\n", a[1], text, language, mode));
210 text = substr(text, 1 + length(part) + length(a[1]));
213 else {
214 context[cindex, "values", ++context[cindex, "values"]] = item text;
215 text = "";
216 item = "";
220 context["item"] = item;
222 if (length(item)) context[cindex, "values", ++context[cindex, "values"]] = item;
223 return text;
225 function transform_escape(s, r, text,
226 # optional
227 max,
228 # local vars
231 for(c=1; c <= max && (c in s); c++) {
232 gsub(s[c], r[c], text);
234 return text;
236 function mode_escaper(context, s, r, src,
237 c, cp, cpl)
239 for(c = context[""]; c >= 0; c--) {
240 if ( (context[c, "language"], context[c, "mode"]) in escapes) {
241 cpl = escapes[context[c, "language"], context[c, "mode"]];
242 for (cp = 1; cp <= cpl; cp ++) {
243 ++src;
244 s[src] = escapes[context[c, "language"], context[c, "mode"], cp, "s"];
245 r[src] = escapes[context[c, "language"], context[c, "mode"], cp, "r"];
249 return src;
251 function dump_escaper(c, s, r, cc) {
252 for(cc=1; cc<=c; cc++) {
253 printf("%2d s[%s] r[%s]\n", cc, s[cc], r[cc]) > "/dev/stderr"
256 function parse_chunk_args(language, text, values, mode,
257 # local vars
258 c, context, rest)
260 split("", context);
261 new_mode_tracker(context, language, mode);
262 rest = mode_tracker(context, text, values);
263 # extract values
264 for(c=1; c <= context[0, "values"]; c++) {
265 values[c] = context[0, "values", c];
267 return rest;
269 function new_chunk(chunk_name, params,
270 # local vars
271 p, append )
273 # HACK WHILE WE CHANGE TO ( ) for PARAM CHUNKS
274 gsub("\\(\\)$", "", chunk_name);
275 if (! (chunk_name in chunk_names)) {
276 if (debug) print "New chunk " chunk_name;
277 chunk_names[chunk_name];
278 for (p in params) {
279 chunks[chunk_name, p] = params[p];
281 if ("append" in params) {
282 append=params["append"];
283 if (! (append in chunk_names)) {
284 warning("Chunk " chunk_name " is appended to chunk " append " which is not defined yet");
285 new_chunk(append);
287 chunk_include(append, chunk_name);
288 chunk_line(append, ORS);
291 active_chunk = chunk_name;
292 prime_chunk(chunk_name);
295 function prime_chunk(chunk_name)
297 chunks[chunk_name, "part", ++chunks[chunk_name, "part"] ] = \
298 chunk_name SUBSEP "chunklet" SUBSEP "" ++chunks[chunk_name, "chunklet"];
299 chunks[chunk_name, "part", chunks[chunk_name, "part"], "FILENAME"] = FILENAME;
300 chunks[chunk_name, "part", chunks[chunk_name, "part"], "LINENO"] = FNR + 1;
303 function chunk_line(chunk_name, line){
304 chunks[chunk_name, "chunklet", chunks[chunk_name, "chunklet"],
305 ++chunks[chunk_name, "chunklet", chunks[chunk_name, "chunklet"], "line"] ] = line;
308 function chunk_include(chunk_name, chunk_ref, indent, tail)
310 chunks[chunk_name, "part", ++chunks[chunk_name, "part"] ] = chunk_ref;
311 chunks[chunk_name, "part", chunks[chunk_name, "part"], "type" ] = part_type_chunk;
312 chunks[chunk_name, "part", chunks[chunk_name, "part"], "indent" ] = indent_string(indent);
313 chunks[chunk_name, "part", chunks[chunk_name, "part"], "tail" ] = tail;
314 prime_chunk(chunk_name);
317 function indent_string(indent) {
318 return sprintf("%" indent "s", "");
320 function output_chunk_names( c, prefix, suffix)
322 if (notangle_mode) {
323 prefix="<<";
324 suffix=">>";
326 for (c in chunk_names) {
327 print prefix c suffix "\n";
330 function output_chunks( a)
332 for (a in chunk_names) {
333 output_chunk(chunk_names[a]);
337 function output_chunk(chunk) {
338 newline = 1;
339 lineno_needed = linenos;
341 write_chunk(chunk);
344 function write_chunk(chunk_name) {
345 split("", context);
346 return write_chunk_r(chunk_name, context);
348 function write_chunk_r(chunk_name, context, indent, tail,
349 # optional vars
350 chunk_path, chunk_args,
351 s, r, src, new_src,
352 # local vars
353 chunk_params, part, max_part, part_line, frag, max_frag, text,
354 chunklet, only_part, call_chunk_args, new_context)
356 if (match(chunk_name, "^(.*)\\[([0-9]*)\\]$", chunk_name_parts)) {
357 chunk_name = chunk_name_parts[1];
358 only_part = chunk_name_parts[2];
360 split("", context);
361 new_mode_tracker(context, chunks[chunk_name, "language"], "");
362 split(chunks[chunk_name, "params"], chunk_params, " *; *");
363 if (! (chunk_name in chunk_names)) {
364 error(sprintf(_"The root module <<%s>> was not defined.\nUsed by: %s",\
365 chunk_name, chunk_path));
368 max_part = chunks[chunk_name, "part"];
369 for(part = 1; part <= max_part; part++) {
370 if (! only_part || part == only_part) {
371 if (linenos && (chunk_name SUBSEP "part" SUBSEP part SUBSEP "FILENAME" in chunks)) {
372 a_filename = chunks[chunk_name, "part", part, "FILENAME"];
373 a_lineno = chunks[chunk_name, "part", part, "LINENO"];
374 if (a_filename != filename || a_lineno != lineno) {
375 lineno_needed++;
379 chunklet = chunks[chunk_name, "part", part];
380 if (chunks[chunk_name, "part", part, "type"] == part_type_chunk) {
381 if (match(chunklet, "^([^\\[\\(]*)\\((.*)\\)$", chunklet_parts)) {
382 chunklet = chunklet_parts[1];
383 parse_chunk_args("c-like", chunklet_parts[2], call_chunk_args, "(");
384 for (c in call_chunk_args) {
385 call_chunk_args[c] = expand_chunk_args(call_chunk_args[c], chunk_params, chunk_args);
387 } else {
388 split("", call_chunk_args);
390 # update the transforms arrays
391 new_src = mode_escaper(context, s, r, src);
392 split("", new_context);
393 write_chunk_r(chunklet, new_context,
394 chunks[chunk_name, "part", part, "indent"] indent,
395 chunks[chunk_name, "part", part, "tail"],
396 chunk_path "\n " chunk_name,
397 call_chunk_args,
398 s, r, new_src);
399 } else if (chunklet SUBSEP "line" in chunks) {
400 max_frag = chunks[chunklet, "line"];
401 for(frag = 1; frag <= max_frag; frag++) {
402 if (newline && lineno_needed && ! lineno_suppressed) {
403 filename = a_filename;
404 lineno = a_lineno;
405 print "#line " lineno " \"" filename "\"\n"
406 lineno_needed = 0;
409 text = chunks[chunklet, frag];
411 /* check params */
412 text = expand_chunk_args(text, chunk_params, chunk_args);
414 if (text == "\n") {
415 lineno++;
416 if (part == max_part && frag == max_frag && length(chunk_path)) {
417 text = "";
418 break;
419 } else {
420 newline = 1;
422 } else if (length(text) || length(tail)) {
423 if (newline) text = indent text;
424 newline = 0;
427 text = text tail;
428 mode_tracker(context, text);
429 print transform_escape(s, r, text, src);
430 if (linenos) {
431 lineno_suppressed = substr(lastline, length(lastline)) == "\\";
434 } else {
435 # empty last chunklet
439 if (! finalize_mode_tracker(context)) {
440 dump_mode_tracker(context);
441 error(sprintf(_"Module %s did not close context properly.\nUsed by: %s\n", chunk_name, chunk_path));
444 function expand_chunk_args(text, params, args,
445 p, text_array, next_text, v, t, l)
447 if (split(text, text_array, "\\${")) {
448 for(p in params) {
449 v[params[p]]=args[p];
451 text=text_array[1];
452 for(t=2; t in text_array; t++) {
453 if (match(text_array[t], "^([a-zA-Z_][a-zA-Z0-9_]*)}", l) &&
454 l[1] in v)
456 text = text v[l[1]] substr(text_array[t], length(l[1])+2);
457 } else {
458 text = text "${" text_array[t];
463 return text;
465 BEGIN {
466 part_type_chunk=1;
467 SUBSEP=",";
468 modes["c-like", "", "submodes" ]="\\\\|\"|'|{|\\(|\\[";
469 modes["c-like", "", "delimiters"]=" *, *";
470 modes["c-like", "\\", "terminators"]=".";
471 modes["c-like", "\"", "submodes" ]="\\\\";
472 modes["c-like", "\"", "terminators"]="\"";
473 escapes["c-like", "\"", ++escapes["c-like", "\""], "s"]="\\\\";
474 escapes["c-like", "\"", escapes["c-like", "\""], "r"]="\\\\";
475 escapes["c-like", "\"", ++escapes["c-like", "\""], "s"]="\"";
476 escapes["c-like", "\"", escapes["c-like", "\""], "r"]="\\" "\"";
477 escapes["c-like", "\"", ++escapes["c-like", "\""], "s"]="\n";
478 escapes["c-like", "\"", escapes["c-like", "\""], "r"]="\\n";
479 modes["c-like", "'", "submodes" ]="\\\\";
480 modes["c-like", "'", "terminators"]="'";
481 escapes["c-like", "'", ++escapes["c-like", "'"], "s"]="\\\\";
482 escapes["c-like", "'", escapes["c-like", "'"], "r"]="\\\\";
483 escapes["c-like", "'", ++escapes["c-like", "'"], "s"]="'";
484 escapes["c-like", "'", escapes["c-like", "'"], "r"]="\\" "'";
485 escapes["c-like", "'", ++escapes["c-like", "'"], "s"]="\n";
486 escapes["c-like", "'", escapes["c-like", "'"], "r"]="\\n";
487 modes["c-like", "{", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
488 modes["c-like", "{", "delimiters"]=" *, *";
489 modes["c-like", "{", "terminators"]="}";
490 modes["c-like", "[", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
491 modes["c-like", "[", "delimiters"]=" *, *";
492 modes["c-like", "[", "terminators"]="\\]";
493 modes["c-like", "(", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
494 modes["c-like", "(", "delimiters"]=" *, *";
495 modes["c-like", "(", "terminators"]="\\)";
497 modes["c", "", "submodes" ]="\\\\|\"|'|{|\\(|\\[";
498 modes["c", "", "delimiters"]=" *, *";
499 modes["c", "\\", "terminators"]=".";
500 modes["c", "\"", "submodes" ]="\\\\";
501 modes["c", "\"", "terminators"]="\"";
502 escapes["c", "\"", ++escapes["c", "\""], "s"]="\\\\";
503 escapes["c", "\"", escapes["c", "\""], "r"]="\\\\";
504 escapes["c", "\"", ++escapes["c", "\""], "s"]="\"";
505 escapes["c", "\"", escapes["c", "\""], "r"]="\\" "\"";
506 escapes["c", "\"", ++escapes["c", "\""], "s"]="\n";
507 escapes["c", "\"", escapes["c", "\""], "r"]="\\n";
508 modes["c", "'", "submodes" ]="\\\\";
509 modes["c", "'", "terminators"]="'";
510 escapes["c", "'", ++escapes["c", "'"], "s"]="\\\\";
511 escapes["c", "'", escapes["c", "'"], "r"]="\\\\";
512 escapes["c", "'", ++escapes["c", "'"], "s"]="'";
513 escapes["c", "'", escapes["c", "'"], "r"]="\\" "'";
514 escapes["c", "'", ++escapes["c", "'"], "s"]="\n";
515 escapes["c", "'", escapes["c", "'"], "r"]="\\n";
516 modes["c", "{", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
517 modes["c", "{", "delimiters"]=" *, *";
518 modes["c", "{", "terminators"]="}";
519 modes["c", "[", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
520 modes["c", "[", "delimiters"]=" *, *";
521 modes["c", "[", "terminators"]="\\]";
522 modes["c", "(", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
523 modes["c", "(", "delimiters"]=" *, *";
524 modes["c", "(", "terminators"]="\\)";
525 modes["c", "", "submodes"] = modes["c", "", "submodes"] "|" "/\\*";
526 modes["c", "/*", "terminators"]="\\*/";
527 modes["c", "", "submodes"] = modes["c", "", "submodes"] "|" "//";
528 modes["c", "//", "terminators"]="\n";
529 escapes["c", "//", ++escapes["c", "//"], "s"]="\n";
530 escapes["c", "//", escapes["c", "//"], "r"]="\n//";
531 modes["c", "", "submodes"] = modes["c", "", "submodes"] "|" "#";
532 modes["c", "#", "submodes" ]="\\\\";
533 modes["c", "#", "terminators"]="\n";
534 escapes["c", "#", ++escapes["c", "#"], "s"]="\n";
535 escapes["c", "#", escapes["c", "#"], "r"]="\\\\\n";
537 modes["awk", "", "submodes" ]="\\\\|\"|'|{|\\(|\\[";
538 modes["awk", "", "delimiters"]=" *, *";
539 modes["awk", "\\", "terminators"]=".";
540 modes["awk", "\"", "submodes" ]="\\\\";
541 modes["awk", "\"", "terminators"]="\"";
542 escapes["awk", "\"", ++escapes["awk", "\""], "s"]="\\\\";
543 escapes["awk", "\"", escapes["awk", "\""], "r"]="\\\\";
544 escapes["awk", "\"", ++escapes["awk", "\""], "s"]="\"";
545 escapes["awk", "\"", escapes["awk", "\""], "r"]="\\" "\"";
546 escapes["awk", "\"", ++escapes["awk", "\""], "s"]="\n";
547 escapes["awk", "\"", escapes["awk", "\""], "r"]="\\n";
548 modes["awk", "'", "submodes" ]="\\\\";
549 modes["awk", "'", "terminators"]="'";
550 escapes["awk", "'", ++escapes["awk", "'"], "s"]="\\\\";
551 escapes["awk", "'", escapes["awk", "'"], "r"]="\\\\";
552 escapes["awk", "'", ++escapes["awk", "'"], "s"]="'";
553 escapes["awk", "'", escapes["awk", "'"], "r"]="\\" "'";
554 escapes["awk", "'", ++escapes["awk", "'"], "s"]="\n";
555 escapes["awk", "'", escapes["awk", "'"], "r"]="\\n";
556 modes["awk", "{", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
557 modes["awk", "{", "delimiters"]=" *, *";
558 modes["awk", "{", "terminators"]="}";
559 modes["awk", "[", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
560 modes["awk", "[", "delimiters"]=" *, *";
561 modes["awk", "[", "terminators"]="\\]";
562 modes["awk", "(", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
563 modes["awk", "(", "delimiters"]=" *, *";
564 modes["awk", "(", "terminators"]="\\)";
565 modes["awk", "", "submodes"] = modes["awk", "", "submodes"] "|" "#";
566 modes["awk", "#", "terminators"]="\n";
567 escapes["awk", "#", ++escapes["awk", "#"], "s"]="\n";
568 escapes["awk", "#", escapes["awk", "#"], "r"]="\n#";
569 modes["awk", "", "submodes"] = modes["awk", "", "submodes"] "|" "/\\^";
570 modes["awk", "/^", "terminators"]="/";
571 modes["perl", "", "submodes" ]="\\\\|\"|'|{|\\(|\\[";
572 modes["perl", "", "delimiters"]=" *, *";
573 modes["perl", "\\", "terminators"]=".";
574 modes["perl", "\"", "submodes" ]="\\\\";
575 modes["perl", "\"", "terminators"]="\"";
576 escapes["perl", "\"", ++escapes["perl", "\""], "s"]="\\\\";
577 escapes["perl", "\"", escapes["perl", "\""], "r"]="\\\\";
578 escapes["perl", "\"", ++escapes["perl", "\""], "s"]="\"";
579 escapes["perl", "\"", escapes["perl", "\""], "r"]="\\" "\"";
580 escapes["perl", "\"", ++escapes["perl", "\""], "s"]="\n";
581 escapes["perl", "\"", escapes["perl", "\""], "r"]="\\n";
582 modes["perl", "'", "submodes" ]="\\\\";
583 modes["perl", "'", "terminators"]="'";
584 escapes["perl", "'", ++escapes["perl", "'"], "s"]="\\\\";
585 escapes["perl", "'", escapes["perl", "'"], "r"]="\\\\";
586 escapes["perl", "'", ++escapes["perl", "'"], "s"]="'";
587 escapes["perl", "'", escapes["perl", "'"], "r"]="\\" "'";
588 escapes["perl", "'", ++escapes["perl", "'"], "s"]="\n";
589 escapes["perl", "'", escapes["perl", "'"], "r"]="\\n";
590 modes["perl", "{", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
591 modes["perl", "{", "delimiters"]=" *, *";
592 modes["perl", "{", "terminators"]="}";
593 modes["perl", "[", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
594 modes["perl", "[", "delimiters"]=" *, *";
595 modes["perl", "[", "terminators"]="\\]";
596 modes["perl", "(", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
597 modes["perl", "(", "delimiters"]=" *, *";
598 modes["perl", "(", "terminators"]="\\)";
599 modes["perl", "", "submodes"] = modes["perl", "", "submodes"] "|" "/\\*";
600 modes["perl", "/*", "terminators"]="\\*/";
601 modes["perl", "", "submodes"] = modes["perl", "", "submodes"] "|" "#";
602 modes["perl", "#", "terminators"]="\n";
603 escapes["perl", "#", ++escapes["perl", "#"], "s"]="\n";
604 escapes["perl", "#", escapes["perl", "#"], "r"]="\n#";
605 modes["sh", "", "submodes" ]="\\\\|\"|'|{|\\(|\\[";
606 modes["sh", "", "delimiters"]=" *, *";
607 modes["sh", "\\", "terminators"]=".";
608 modes["sh", "\"", "submodes" ]="\\\\";
609 modes["sh", "\"", "terminators"]="\"";
610 escapes["sh", "\"", ++escapes["sh", "\""], "s"]="\\\\";
611 escapes["sh", "\"", escapes["sh", "\""], "r"]="\\\\";
612 escapes["sh", "\"", ++escapes["sh", "\""], "s"]="\"";
613 escapes["sh", "\"", escapes["sh", "\""], "r"]="\\" "\"";
614 escapes["sh", "\"", ++escapes["sh", "\""], "s"]="\n";
615 escapes["sh", "\"", escapes["sh", "\""], "r"]="\\n";
616 modes["sh", "'", "submodes" ]="\\\\";
617 modes["sh", "'", "terminators"]="'";
618 escapes["sh", "'", ++escapes["sh", "'"], "s"]="\\\\";
619 escapes["sh", "'", escapes["sh", "'"], "r"]="\\\\";
620 escapes["sh", "'", ++escapes["sh", "'"], "s"]="'";
621 escapes["sh", "'", escapes["sh", "'"], "r"]="\\" "'";
622 escapes["sh", "'", ++escapes["sh", "'"], "s"]="\n";
623 escapes["sh", "'", escapes["sh", "'"], "r"]="\\n";
624 modes["sh", "{", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
625 modes["sh", "{", "delimiters"]=" *, *";
626 modes["sh", "{", "terminators"]="}";
627 modes["sh", "[", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
628 modes["sh", "[", "delimiters"]=" *, *";
629 modes["sh", "[", "terminators"]="\\]";
630 modes["sh", "(", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
631 modes["sh", "(", "delimiters"]=" *, *";
632 modes["sh", "(", "terminators"]="\\)";
633 #<\chunkref{mode:common-string}("sh", "\textbackslash{}"")>
634 #<\chunkref{mode:common-string}("sh", "'")>
635 modes["sh", "", "submodes"] = modes["sh", "", "submodes"] "|" "#";
636 modes["sh", "#", "terminators"]="\n";
637 escapes["sh", "#", ++escapes["sh", "#"], "s"]="\n";
638 escapes["sh", "#", escapes["sh", "#"], "r"]="\n#";
639 escapes["sh", "\"", ++escapes["sh", "\""], "s"]="\\$";
640 escapes["sh", "\"", escapes["sh", "\""], "r"]="\\$";
641 debug=0;
642 linenos=0;
643 notangle_mode=0;
644 root="*";
645 tabs = "";
647 Optind = 1 # skip ARGV[0]
648 while(getopt(ARGC, ARGV, "R:LdT:hr")!=-1) {
649 if (Optopt == "R") root = Optarg;
650 else if (Optopt == "r") root="";
651 else if (Optopt == "L") linenos = 1;
652 else if (Optopt == "d") debug = 1;
653 else if (Optopt == "T") tabs = indent_string(Optarg+0);
654 else if (Optopt == "h") help();
655 else if (Optopt == "?") help();
657 for (i=1; i<Optind; i++) { ARGV[i]=""; }
659 /^\\Chunk{/ {
660 if (match($0, "^\\\\Chunk{ *([^ ,}]*),?(.*)}", line)) {
661 next_chunk_name = line[1];
662 get_chunk_args(line[2], next_chunk_args);
664 next;
666 /^\\begin{lstlisting}|^\\begin{Chunk}/ {
667 if (match($0, "}.*[[,] *name= *{? *([^], }]*)", line)) {
668 new_chunk(line[1]);
669 } else {
670 new_chunk(next_chunk_name, next_chunk_args);
672 chunking=1;
673 next;
675 /^[<]<.*[>]>=/ {
676 if (match($0, "^[<]<(.*)[>]>= *$", line)) {
677 chunking=1;
678 notangle_mode=1;
679 new_chunk(line[1]);
680 next;
683 /^\\[e]nd{lstlisting}|^\\[e]nd{Chunk}/ {
684 chunking=0;
685 active_chunk="";
686 next;
688 /^@ *$/ {
689 chunking=0;
690 active_chunk="";
692 ! chunking { next; }
693 length(active_chunk) {
694 if (length(tabs)) {
695 gsub("\t", tabs);
697 chunk = $0;
698 indent = 0;
699 while(match(chunk,
700 "([=]<\\\\chunkref{([^}>]*)}(\\(.*\\)|)>|<<([a-zA-Z_][-a-zA-Z0-9_]*)>>)",
701 line)\
703 chunklet = substr(chunk, 1, RSTART - 1);
704 indent += length(chunklet);
705 chunk_line(active_chunk, chunklet);
706 chunk = substr(chunk, RSTART + RLENGTH);
707 if (substr(line[1], 1, 1) == "=") {
708 # chunk name up to }
709 # FILTHY HACK
710 gsub("\\\\#", "#", line[3]);
711 gsub("\\\\textbackslash{}", "\\", line[3]);
712 gsub("\\\\\\^", "^", line[3]);
713 chunk_include(active_chunk, line[2] line[3], indent);
714 } else if (substr(line[1], 1, 1) == "<") {
715 chunk_include(active_chunk, line[4], indent);
716 } else {
717 error("Unknown chunk fragment: " line[1]);
720 chunk_line(active_chunk, chunk);
721 chunk_line(active_chunk, "\n");
723 END {
724 if (debug) {
725 print "------ chunk names "
726 output_chunk_names();
727 print "====== chunks"
728 output_chunks();
729 print "++++++ debug"
730 for (a in chunks) {
731 print a "=" chunks[a];
734 ORS="";
735 if (length(root)) output_chunk(root);
736 else output_chunk_names();
738 function get_chunk_args(text, values,
739 # optional parameters
740 path, # hierarchical precursors
741 # local vars
742 a, name)
744 split("", next_chunk_args);
745 while(length(text)) {
746 if (match(text, "^ *}(.*)", a)) {
747 return a[1];
749 if (! match(text, " *([^,=]*[^,= ]) *(([,=]) *(([^,}]*) *,* *(.*))|)$", a)) {
750 return text;
752 name=a[1];
753 if (a[3] == "=") {
754 if (substr(a[4],1,1) == "{") {
755 text = get_chunk_args(substr(a[4],2), values, path name SUBSEP);
756 } else {
757 values[path name]=a[5];
758 text = a[6];
760 } else {
761 values[path name]="";
762 text = a[2];
765 return text;