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
30 function getopt
(argc, argv, options
, thisopt
, i
)
32 if (length(options
) ==
0) # no options given
34 if (argv[Optind
] ==
"--") { # all done
38 } else if (argv[Optind
] !~
/^
-[^
: \t\n\f\r\v\b]/) {
44 thisopt =
substr(argv[Optind
], _opti
, 1)
46 i =
index(options
, thisopt
)
49 printf("%c -- invalid option\n",
50 thisopt
) > "/dev/stderr"
51 if (_opti
>=
length(argv[Optind
])) {
58 if (substr(options
, i
+ 1, 1) ==
":") {
60 if (length(substr(argv[Optind
], _opti
+ 1)) > 0)
61 Optarg =
substr(argv[Optind
], _opti
+ 1)
63 Optarg =
argv[++Optind
]
67 if (_opti ==
0 || _opti
>=
length(argv[Optind
])) {
75 function error
(message
)
77 print "ERROR: " FILENAME ":" FNR " " message
> "/dev/stderr";
80 function warning
(message
)
82 print "WARNING: " FILENAME ":" FNR " " message
> "/dev/stderr";
85 function new_mode_tracker
(context
, language
, mode
) {
87 context
[0, "language"] = language
;
88 context
[0, "mode"] = mode
;
90 function push_mode_tracker
(context
, language
, mode
,
94 if (!
("" in context
)) {
96 new_mode_tracker
(context
, language
, mode
);
99 if (context
[top
, "language"] == language
&& mode==
"") mode = context
[top
, "mode"];
101 context
[top
, "language"] = language
;
102 context
[top
, "mode"] = mode
;
106 function finalize_mode_tracker
(context
,
110 if ( ("" in context
) && context
[""] != 0) return 0;
113 function mode_tracker
(context
, text
, values
,
114 # optional parameters
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
)) {
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);
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
;
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
;
167 text =
substr(text
, 1 + length(part
) + length(a
[1]));
169 else if (match(a
[1], "^" delimiters
"$")) {
171 context
[cindex
, "values", ++context
[cindex
, "values"]] = item
;
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
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
;
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
;
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]));
206 context
[cindex
, "values", ++context
[cindex
, "values"]] = item text
;
212 context
["item"] = item
;
214 if (length(item
)) context
[cindex
, "values", ++context
[cindex
, "values"]] = item
;
217 function transform_escape
(s
, r
, text
,
223 for(c=
1; c
<= max
&& (c in s
); c
++) {
224 gsub(s
[c
], r
[c
], text
);
228 function mode_escaper
(context
, s
, r
, src
,
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
++) {
236 s
[src
] = escapes
[context
[c
, "language"], context
[c
, "mode"], c
, "s"];
237 r
[src
] = escapes
[context
[c
, "language"], context
[c
, "mode"], c
, "r"];
243 function parse_chunk_args
(language
, text
, values
, mode
,
248 new_mode_tracker
(context
, language
, mode
);
249 rest = mode_tracker
(context
, text
, values
);
251 for(c=
1; c
<= context
[0, "values"]; c
++) {
252 values
[c
] = context
[0, "values", c
];
256 function new_chunk
(chunk_name
, params
,
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
];
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");
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)
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) {
326 lineno_needed = linenos;
331 function write_chunk(chunk_name) {
333 return write_chunk_r(chunk_name, context);
335 function write_chunk_r(chunk_name, context, indent, tail,
337 chunk_path, chunk_args,
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];
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) {
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);
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,
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;
391 print "#line " lineno " \"" filename "\"\n"
395 text = chunks
[chunklet
, frag
];
398 text = expand_chunk_args
(text
, chunk_params
, chunk_args
);
402 if (part == max_part
&& frag == max_frag
&& length(chunk_path
)) {
408 } else if (length(text
) || length(tail
)) {
409 if (newline
) text = indent text
;
414 mode_tracker
(context
, text
);
415 print transform_escape
(s
, r
, text
, src
);
417 lineno_suppressed =
substr(lastline
, length(lastline
)) ==
"\\";
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
, "\\${")) {
434 v
[params
[p
]]=args
[p
];
437 for(t=
2; t in text_array
; t
++) {
438 if (match(text_array
[t
], "^([a-zA-Z_][a-zA-Z0-9_]*)}", l
) &&
441 text = text v
[l
[1]] substr(text_array
[t
], length(l
[1])+2);
443 text = text
"${" text_array
[t
];
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#";
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
]=
""; }
573 if (match($
0, "^\\\\Chunk{ *([^ ,}]*),?(.*)}", line
)) {
574 next_chunk_name = line
[1];
575 get_chunk_args
(line
[2], next_chunk_args
);
579 /^
\\begin{lstlisting
}|^
\\begin{Chunk
}/ {
580 if (match($
0, "}.*[[,] *name= *{? *([^], }]*)", line
)) {
583 new_chunk
(next_chunk_name
, next_chunk_args
);
589 if (match($
0, "^[<]<(.*)[>]>= *$", line
)) {
596 /^
\\[e
]nd
{lstlisting
}|^
\\[e
]nd
{Chunk
}/ {
606 length(active_chunk
) {
613 "([=]<\\\\chunkref{([^}>]*)}(\\(.*\\)|)>|<<([a-zA-Z_][-a-zA-Z0-9_]*)>>)",
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) ==
"=") {
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
);
629 error
("Unknown chunk fragment: " line
[1]);
632 chunk_line
(active_chunk
, chunk
);
633 chunk_line
(active_chunk
, "\n");
637 print "------ chunk names "
638 output_chunk_names
();
639 print "====== chunks"
643 print a
"=" chunks
[a
];
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
656 split("", next_chunk_args
);
657 while(length(text
)) {
658 if (match(text
, "^ *}(.*)", a
)) {
661 if (!
match(text
, " *([^,=]*[^,= ]) *(([,=]) *(([^,}]*) *,* *(.*))|)$", a
)) {
666 if (substr(a
[4],1,1) ==
"{") {
667 text = get_chunk_args
(substr(a
[4],2), values
, path name SUBSEP
);
669 values
[path name
]=a
[5];
673 values
[path name
]=
"";