Fix newfangle.module, fix generation of non-defined languages
[newfangle.git] / newfangle
blob91f867ea0568a9ab69b780a6156dbe94628a332c
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 finalize_mode_tracker(context,
107 # local vars
108 top)
110 if ( ("" in context) && context[""] != 0) return 0;
111 return 1;
113 function mode_tracker(context, text, values,
114 # optional parameters
115 # local vars
116 mode, submodes, language,
117 cindex, c, a, part, item, name, result, new_values, new_mode,
118 delimiters, terminators)
120 cindex = context[""] + 0;
121 mode = context[cindex, "mode"];
122 language = context[cindex, "language" ];
123 submodes=modes[language, mode, "submodes"];
125 if ((language, mode, "delimiters") in modes) {
126 delimiters = modes[language, mode, "delimiters"];
127 if (length(submodes)>0) submodes = submodes "|";
128 submodes=submodes delimiters;
129 } else delimiters="";
130 if ((language, mode, "terminators") in modes) {
131 terminators = modes[language, mode, "terminators"];
132 if (length(submodes)>0) submodes = submodes "|";
133 submodes=submodes terminators;
134 } else terminators="";
135 if (! length(submodes)) return text;
136 while((cindex >= 0) && length(text)) {
137 if (match(text, "(" submodes ")", a)) {
138 if (RLENGTH<1) {
139 error(sprintf("Internal error, matched zero length submode, should be impossible - likely regex computation error\n" \
140 "Language=%s\nmode=%s\nmatch=%s\n", language, mode, submodes));
142 part = substr(text, 1, RSTART -1);
143 item = item part;
144 if (match(a[1], "^" terminators "$")) {
145 #printf("%2d EXIT MODE [%s] by [%s] [%s]\n", cindex, mode, a[1], text) > "/dev/stderr"
146 context[cindex, "values", ++context[cindex, "values"]] = item;
147 delete context[cindex];
148 context[""] = --cindex;
149 if (cindex>=0) {
150 mode = context[cindex, "mode"];
151 language = context[cindex, "language"];
152 submodes=modes[language, mode, "submodes"];
154 if ((language, mode, "delimiters") in modes) {
155 delimiters = modes[language, mode, "delimiters"];
156 if (length(submodes)>0) submodes = submodes "|";
157 submodes=submodes delimiters;
158 } else delimiters="";
159 if ((language, mode, "terminators") in modes) {
160 terminators = modes[language, mode, "terminators"];
161 if (length(submodes)>0) submodes = submodes "|";
162 submodes=submodes terminators;
163 } else terminators="";
164 if (! length(submodes)) return text;
166 item = item a[1];
167 text = substr(text, 1 + length(part) + length(a[1]));
169 else if (match(a[1], "^" delimiters "$")) {
170 if (cindex==0) {
171 context[cindex, "values", ++context[cindex, "values"]] = item;
172 item = "";
173 } else {
174 item = item a[1];
176 text = substr(text, 1 + length(part) + length(a[1]));
178 else if ((language, a[1], "terminators") in modes) {
179 #check if new_mode is defined
180 item = item a[1];
181 #printf("%2d ENTER MODE [%s] in [%s]\n", cindex, a[1], text) > "/dev/stderr"
182 text = substr(text, 1 + length(part) + length(a[1]));
183 context[""] = ++cindex;
184 context[cindex, "mode"] = a[1];
185 context[cindex, "language"] = language;
186 mode = a[1];
187 submodes=modes[language, mode, "submodes"];
189 if ((language, mode, "delimiters") in modes) {
190 delimiters = modes[language, mode, "delimiters"];
191 if (length(submodes)>0) submodes = submodes "|";
192 submodes=submodes delimiters;
193 } else delimiters="";
194 if ((language, mode, "terminators") in modes) {
195 terminators = modes[language, mode, "terminators"];
196 if (length(submodes)>0) submodes = submodes "|";
197 submodes=submodes terminators;
198 } else terminators="";
199 if (! length(submodes)) return text;
200 } else {
201 error(sprintf("Submode '%s' set unknown mode in text: %s\nLanguage %s Mode %s\n", a[1], text, language, mode));
202 text = substr(text, 1 + length(part) + length(a[1]));
205 else {
206 context[cindex, "values", ++context[cindex, "values"]] = item text;
207 text = "";
208 item = "";
212 context["item"] = item;
214 if (length(item)) context[cindex, "values", ++context[cindex, "values"]] = item;
215 return text;
217 function transform_escape(s, r, text,
218 # optional
219 max,
220 # local vars
223 for(c=1; c <= max && (c in s); c++) {
224 gsub(s[c], r[c], text);
226 return text;
228 function mode_escaper(context, s, r, src,
229 c, cp, cpl)
231 for(c = context[""]; c >= 0; c--) {
232 if ( (context[c, "language"], context[c, "mode"]) in escapes) {
233 cpl = escapes[context[c, "language"], context[c, "mode"]];
234 for (cp = 1; cp <= cpl; cp ++) {
235 ++src;
236 s[src] = escapes[context[c, "language"], context[c, "mode"], c, "s"];
237 r[src] = escapes[context[c, "language"], context[c, "mode"], c, "r"];
241 return src;
243 function parse_chunk_args(language, text, values, mode,
244 # local vars
245 c, context, rest)
247 split("", context);
248 new_mode_tracker(context, language, mode);
249 rest = mode_tracker(context, text, values);
250 # extract values
251 for(c=1; c <= context[0, "values"]; c++) {
252 values[c] = context[0, "values", c];
254 return rest;
256 function new_chunk(chunk_name, params,
257 # local vars
258 p, append )
260 # HACK WHILE WE CHANGE TO ( ) for PARAM CHUNKS
261 gsub("\\(\\)$", "", chunk_name);
262 if (! (chunk_name in chunk_names)) {
263 if (debug) print "New chunk " chunk_name;
264 chunk_names[chunk_name];
265 for (p in params) {
266 chunks[chunk_name, p] = params[p];
268 if ("append" in params) {
269 append=params["append"];
270 if (! (append in chunk_names)) {
271 warning("Chunk " chunk_name " is appended to chunk " append " which is not defined yet");
272 new_chunk(append);
274 chunk_include(append, chunk_name);
275 chunk_line(append, ORS);
278 active_chunk = chunk_name;
279 prime_chunk(chunk_name);
282 function prime_chunk(chunk_name)
284 chunks[chunk_name, "part", ++chunks[chunk_name, "part"] ] = \
285 chunk_name SUBSEP "chunklet" SUBSEP "" ++chunks[chunk_name, "chunklet"];
286 chunks[chunk_name, "part", chunks[chunk_name, "part"], "FILENAME"] = FILENAME;
287 chunks[chunk_name, "part", chunks[chunk_name, "part"], "LINENO"] = FNR + 1;
290 function chunk_line(chunk_name, line){
291 chunks[chunk_name, "chunklet", chunks[chunk_name, "chunklet"],
292 ++chunks[chunk_name, "chunklet", chunks[chunk_name, "chunklet"], "line"] ] = line;
295 function chunk_include(chunk_name, chunk_ref, indent, tail)
297 chunks[chunk_name, "part", ++chunks[chunk_name, "part"] ] = chunk_ref;
298 chunks[chunk_name, "part", chunks[chunk_name, "part"], "type" ] = part_type_chunk;
299 chunks[chunk_name, "part", chunks[chunk_name, "part"], "indent" ] = indent_string(indent);
300 chunks[chunk_name, "part", chunks[chunk_name, "part"], "tail" ] = tail;
301 prime_chunk(chunk_name);
304 function indent_string(indent) {
305 return sprintf("%" indent "s", "");
307 function output_chunk_names( c, prefix, suffix)
309 if (notangle_mode) {
310 prefix="<<";
311 suffix=">>";
313 for (c in chunk_names) {
314 print prefix c suffix "\n";
317 function output_chunks( a)
319 for (a in chunk_names) {
320 output_chunk(chunk_names[a]);
324 function output_chunk(chunk) {
325 newline = 1;
326 lineno_needed = linenos;
328 write_chunk(chunk);
331 function write_chunk(chunk_name) {
332 split("", context);
333 return write_chunk_r(chunk_name, context);
335 function write_chunk_r(chunk_name, context, indent, tail,
336 # optional vars
337 chunk_path, chunk_args,
338 s, r, src, new_src,
339 # local vars
340 chunk_params, part, max_part, part_line, frag, max_frag, text,
341 chunklet, only_part, call_chunk_args)
343 if (match(chunk_name, "^(.*)\\[([0-9]*)\\]$", chunk_name_parts)) {
344 chunk_name = chunk_name_parts[1];
345 only_part = chunk_name_parts[2];
347 split("", context);
348 new_mode_tracker(context, chunks[chunk_name, "language"], "");
349 split(chunks[chunk_name, "params"], chunk_params, " *; *");
350 if (! (chunk_name in chunk_names)) {
351 error(sprintf(_"The root module <<%s>> was not defined.\nUsed by: %s",\
352 chunk_name, chunk_path));
355 max_part = chunks[chunk_name, "part"];
356 for(part = 1; part <= max_part; part++) {
357 if (! only_part || part == only_part) {
358 if (linenos && (chunk_name SUBSEP "part" SUBSEP part SUBSEP "FILENAME" in chunks)) {
359 a_filename = chunks[chunk_name, "part", part, "FILENAME"];
360 a_lineno = chunks[chunk_name, "part", part, "LINENO"];
361 if (a_filename != filename || a_lineno != lineno) {
362 lineno_needed++;
366 chunklet = chunks[chunk_name, "part", part];
367 if (chunks[chunk_name, "part", part, "type"] == part_type_chunk) {
368 if (match(chunklet, "^([^\\[\\(]*)\\((.*)\\)$", chunklet_parts)) {
369 chunklet = chunklet_parts[1];
370 parse_chunk_args("", chunklet_parts[2], call_chunk_args, "(");
371 for (c in call_chunk_args) {
372 call_chunk_args[c] = expand_chunk_args(call_chunk_args[c], chunk_params, chunk_args);
374 } else {
375 split("", call_chunk_args);
377 # update the transforms arrays
378 new_src = mode_escaper(context, s, r, src);
379 write_chunk_r(chunklet, context,
380 chunks[chunk_name, "part", part, "indent"] indent,
381 chunks[chunk_name, "part", part, "tail"],
382 chunk_path "\n " chunk_name,
383 call_chunk_args,
384 s, r, new_src);
385 } else if (chunklet SUBSEP "line" in chunks) {
386 max_frag = chunks[chunklet, "line"];
387 for(frag = 1; frag <= max_frag; frag++) {
388 if (newline && lineno_needed && ! lineno_suppressed) {
389 filename = a_filename;
390 lineno = a_lineno;
391 print "#line " lineno " \"" filename "\"\n"
392 lineno_needed = 0;
395 text = chunks[chunklet, frag];
397 /* check params */
398 text = expand_chunk_args(text, chunk_params, chunk_args);
400 if (text == "\n") {
401 lineno++;
402 if (part == max_part && frag == max_frag && length(chunk_path)) {
403 text = "";
404 break;
405 } else {
406 newline = 1;
408 } else if (length(text) || length(tail)) {
409 if (newline) text = indent text;
410 newline = 0;
413 text = text tail;
414 mode_tracker(context, text);
415 print transform_escape(s, r, text, src);
416 if (linenos) {
417 lineno_suppressed = substr(lastline, length(lastline)) == "\\";
420 } else {
421 # empty last chunklet
425 if (! finalize_mode_tracker(context)) {
426 error(sprintf(_"Module %s did not close context properly.\nUsed by: %s\n", chunk_name, chunk_path));
429 function expand_chunk_args(text, params, args,
430 p, text_array, next_text, v, t, l)
432 if (split(text, text_array, "\\${")) {
433 for(p in params) {
434 v[params[p]]=args[p];
436 text=text_array[1];
437 for(t=2; t in text_array; t++) {
438 if (match(text_array[t], "^([a-zA-Z_][a-zA-Z0-9_]*)}", l) &&
439 l[1] in v)
441 text = text v[l[1]] substr(text_array[t], length(l[1])+2);
442 } else {
443 text = text "${" text_array[t];
448 return text;
450 BEGIN {
451 part_type_chunk=1;
452 SUBSEP=",";
453 modes["", "", "submodes" ]="\\\\|\"|'|{|\\(|\\[";
454 modes["", "", "delimiters"]=" *, *";
455 modes["", "\\", "terminators"]=".";
456 modes["", "\"", "submodes" ]="\\\\";
457 modes["", "\"", "terminators"]="\"";
458 escapes["", "\"", ++escapes["", "\""], "s"]="\\";
459 escapes["", "\"", escapes["", "\""], "r"]="\\\\";
460 escapes["", "\"", ++escapes["", "\""], "s"]="\"";
461 escapes["", "\"", escapes["", "\""], "r"]="\\" "\"";
462 escapes["", "\"", ++escapes["", "\""], "s"]="\n";
463 escapes["", "\"", escapes["", "\""], "r"]="\\n";
464 modes["", "'", "submodes" ]="\\\\";
465 modes["", "'", "terminators"]="'";
466 escapes["", "'", ++escapes["", "'"], "s"]="\\";
467 escapes["", "'", escapes["", "'"], "r"]="\\\\";
468 escapes["", "'", ++escapes["", "'"], "s"]="'";
469 escapes["", "'", escapes["", "'"], "r"]="\\" "'";
470 escapes["", "'", ++escapes["", "'"], "s"]="\n";
471 escapes["", "'", escapes["", "'"], "r"]="\\n";
472 modes["", "{", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
473 modes["", "{", "delimiters"]=" *, *";
474 modes["", "{", "terminators"]="}";
475 modes["", "[", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
476 modes["", "[", "delimiters"]=" *, *";
477 modes["", "[", "terminators"]="\\]";
478 modes["", "(", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
479 modes["", "(", "delimiters"]=" *, *";
480 modes["", "(", "terminators"]="\\)";
482 modes["c", "", "submodes" ]="\\\\|\"|'|{|\\(|\\[";
483 modes["c", "", "delimiters"]=" *, *";
484 modes["c", "\\", "terminators"]=".";
485 modes["c", "\"", "submodes" ]="\\\\";
486 modes["c", "\"", "terminators"]="\"";
487 escapes["c", "\"", ++escapes["c", "\""], "s"]="\\";
488 escapes["c", "\"", escapes["c", "\""], "r"]="\\\\";
489 escapes["c", "\"", ++escapes["c", "\""], "s"]="\"";
490 escapes["c", "\"", escapes["c", "\""], "r"]="\\" "\"";
491 escapes["c", "\"", ++escapes["c", "\""], "s"]="\n";
492 escapes["c", "\"", escapes["c", "\""], "r"]="\\n";
493 modes["c", "'", "submodes" ]="\\\\";
494 modes["c", "'", "terminators"]="'";
495 escapes["c", "'", ++escapes["c", "'"], "s"]="\\";
496 escapes["c", "'", escapes["c", "'"], "r"]="\\\\";
497 escapes["c", "'", ++escapes["c", "'"], "s"]="'";
498 escapes["c", "'", escapes["c", "'"], "r"]="\\" "'";
499 escapes["c", "'", ++escapes["c", "'"], "s"]="\n";
500 escapes["c", "'", escapes["c", "'"], "r"]="\\n";
501 modes["c", "{", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
502 modes["c", "{", "delimiters"]=" *, *";
503 modes["c", "{", "terminators"]="}";
504 modes["c", "[", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
505 modes["c", "[", "delimiters"]=" *, *";
506 modes["c", "[", "terminators"]="\\]";
507 modes["c", "(", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
508 modes["c", "(", "delimiters"]=" *, *";
509 modes["c", "(", "terminators"]="\\)";
510 modes["c", "", "submodes"] = modes["c", "", "submodes"] "|" "/\\*";
511 modes["c", "/*", "terminators"]="\\*/";
512 modes["c", "", "submodes"] = modes["c", "", "submodes"] "|" "//";
513 modes["c", "//", "terminators"]="\n";
514 escapes["c", "//", ++escapes["c", "//"], "s"]="\n";
515 escapes["c", "//", escapes["c", "//"], "r"]="\n//";
516 modes["c", "", "submodes"] = modes["c", "", "submodes"] "|" "#";
517 modes["c", "#", "submodes" ]="\\\\";
518 modes["c", "#", "terminators"]="\n";
519 escapes["c", "#", ++escapes["c", "#"], "s"]="\n";
520 escapes["c", "#", escapes["c", "#"], "r"]="\\\\\n";
522 modes["awk", "", "submodes" ]="\\\\|\"|'|{|\\(|\\[";
523 modes["awk", "", "delimiters"]=" *, *";
524 modes["awk", "\\", "terminators"]=".";
525 modes["awk", "\"", "submodes" ]="\\\\";
526 modes["awk", "\"", "terminators"]="\"";
527 escapes["awk", "\"", ++escapes["awk", "\""], "s"]="\\";
528 escapes["awk", "\"", escapes["awk", "\""], "r"]="\\\\";
529 escapes["awk", "\"", ++escapes["awk", "\""], "s"]="\"";
530 escapes["awk", "\"", escapes["awk", "\""], "r"]="\\" "\"";
531 escapes["awk", "\"", ++escapes["awk", "\""], "s"]="\n";
532 escapes["awk", "\"", escapes["awk", "\""], "r"]="\\n";
533 modes["awk", "'", "submodes" ]="\\\\";
534 modes["awk", "'", "terminators"]="'";
535 escapes["awk", "'", ++escapes["awk", "'"], "s"]="\\";
536 escapes["awk", "'", escapes["awk", "'"], "r"]="\\\\";
537 escapes["awk", "'", ++escapes["awk", "'"], "s"]="'";
538 escapes["awk", "'", escapes["awk", "'"], "r"]="\\" "'";
539 escapes["awk", "'", ++escapes["awk", "'"], "s"]="\n";
540 escapes["awk", "'", escapes["awk", "'"], "r"]="\\n";
541 modes["awk", "{", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
542 modes["awk", "{", "delimiters"]=" *, *";
543 modes["awk", "{", "terminators"]="}";
544 modes["awk", "[", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
545 modes["awk", "[", "delimiters"]=" *, *";
546 modes["awk", "[", "terminators"]="\\]";
547 modes["awk", "(", "submodes" ]="\\\\|\"|{|\\(|\\[|'|/\\*";
548 modes["awk", "(", "delimiters"]=" *, *";
549 modes["awk", "(", "terminators"]="\\)";
550 modes["awk", "", "submodes"] = modes["awk", "", "submodes"] "|" "#";
551 modes["awk", "#", "terminators"]="\n";
552 escapes["awk", "#", ++escapes["awk", "#"], "s"]="\n";
553 escapes["awk", "#", escapes["awk", "#"], "r"]="\n#";
554 debug=0;
555 linenos=0;
556 notangle_mode=0;
557 root="*";
558 tabs = "";
560 Optind = 1 # skip ARGV[0]
561 while(getopt(ARGC, ARGV, "R:LdT:hr")!=-1) {
562 if (Optopt == "R") root = Optarg;
563 else if (Optopt == "r") root="";
564 else if (Optopt == "L") linenos = 1;
565 else if (Optopt == "d") debug = 1;
566 else if (Optopt == "T") tabs = indent_string(Optarg+0);
567 else if (Optopt == "h") help();
568 else if (Optopt == "?") help();
570 for (i=1; i<Optind; i++) { ARGV[i]=""; }
572 /^\\Chunk{/ {
573 if (match($0, "^\\\\Chunk{ *([^ ,}]*),?(.*)}", line)) {
574 next_chunk_name = line[1];
575 get_chunk_args(line[2], next_chunk_args);
577 next;
579 /^\\begin{lstlisting}|^\\begin{Chunk}/ {
580 if (match($0, "}.*[[,] *name= *{? *([^], }]*)", line)) {
581 new_chunk(line[1]);
582 } else {
583 new_chunk(next_chunk_name, next_chunk_args);
585 chunking=1;
586 next;
588 /^[<]<.*[>]>=/ {
589 if (match($0, "^[<]<(.*)[>]>= *$", line)) {
590 chunking=1;
591 notangle_mode=1;
592 new_chunk(line[1]);
593 next;
596 /^\\[e]nd{lstlisting}|^\\[e]nd{Chunk}/ {
597 chunking=0;
598 active_chunk="";
599 next;
601 /^@ *$/ {
602 chunking=0;
603 active_chunk="";
605 ! chunking { next; }
606 length(active_chunk) {
607 if (length(tabs)) {
608 gsub("\t", tabs);
610 chunk = $0;
611 indent = 0;
612 while(match(chunk,
613 "([=]<\\\\chunkref{([^}>]*)}(\\(.*\\)|)>|<<([a-zA-Z_][-a-zA-Z0-9_]*)>>)",
614 line)\
616 chunklet = substr(chunk, 1, RSTART - 1);
617 indent += length(chunklet);
618 chunk_line(active_chunk, chunklet);
619 chunk = substr(chunk, RSTART + RLENGTH);
620 if (substr(line[1], 1, 1) == "=") {
621 # chunk name up to }
622 # FILTHY HACK
623 gsub("\\\\#", "#", line[3]);
624 gsub("\\\\textbackslash{}", "\\", line[3]);
625 chunk_include(active_chunk, line[2] line[3], indent);
626 } else if (substr(line[1], 1, 1) == "<") {
627 chunk_include(active_chunk, line[4], indent);
628 } else {
629 error("Unknown chunk fragment: " line[1]);
632 chunk_line(active_chunk, chunk);
633 chunk_line(active_chunk, "\n");
635 END {
636 if (debug) {
637 print "------ chunk names "
638 output_chunk_names();
639 print "====== chunks"
640 output_chunks();
641 print "++++++ debug"
642 for (a in chunks) {
643 print a "=" chunks[a];
646 ORS="";
647 if (length(root)) output_chunk(root);
648 else output_chunk_names();
650 function get_chunk_args(text, values,
651 # optional parameters
652 path, # hierarchical precursors
653 # local vars
654 a, name)
656 split("", next_chunk_args);
657 while(length(text)) {
658 if (match(text, "^ *}(.*)", a)) {
659 return a[1];
661 if (! match(text, " *([^,=]*[^,= ]) *(([,=]) *(([^,}]*) *,* *(.*))|)$", a)) {
662 return text;
664 name=a[1];
665 if (a[3] == "=") {
666 if (substr(a[4],1,1) == "{") {
667 text = get_chunk_args(substr(a[4],2), values, path name SUBSEP);
668 } else {
669 values[path name]=a[5];
670 text = a[6];
672 } else {
673 values[path name]="";
674 text = a[2];
677 return text;