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/>.
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
27 function getopt
(argc, argv, options
, thisopt
, i
)
29 if (length(options
) ==
0) # no options given
31 if (argv[Optind
] ==
"--") { # all done
35 } else if (argv[Optind
] !~
/^
-[^
: \t\n\f\r\v\b]/) {
41 thisopt =
substr(argv[Optind
], _opti
, 1)
43 i =
index(options
, thisopt
)
46 printf("%c -- invalid option\n",
47 thisopt
) > "/dev/stderr"
48 if (_opti
>=
length(argv[Optind
])) {
55 if (substr(options
, i
+ 1, 1) ==
":") {
57 if (length(substr(argv[Optind
], _opti
+ 1)) > 0)
58 Optarg =
substr(argv[Optind
], _opti
+ 1)
60 Optarg =
argv[++Optind
]
64 if (_opti ==
0 || _opti
>=
length(argv[Optind
])) {
72 function error
(message
)
74 print message
> "/dev/stderr";
77 function new_mode
(language
, mode
) {
78 mode
["language"] = language
;
81 function new_chunk
(chunk_name
, params
,
85 # HACK WHILE WE CHANGE TO ( ) for PARAM CHUNKS
86 gsub("\\(\\)$", "", chunk_name
);
87 active_chunk = chunk_name
;
88 if (!
(chunk_name in chunk_names
)) {
89 if (debug
) print "New chunk " chunk_name
;
90 chunk_names
[chunk_name
];
92 chunks
[chunk_name
, p
] = params
[p
];
95 prime_chunk
(chunk_name
);
98 function prime_chunk
(chunk_name
)
100 chunks
[chunk_name
, "part", ++chunks
[chunk_name
, "part"] ] = \
101 chunk_name SUBSEP
"chunklet" SUBSEP
"" ++chunks
[chunk_name
, "chunklet"];
102 chunks
[chunk_name
, "part", chunks
[chunk_name
, "part"], "FILENAME"] =
FILENAME;
103 chunks
[chunk_name
, "part", chunks
[chunk_name
, "part"], "LINENO"] =
FNR + 1;
106 function chunk_line
(chunk_name
, line
){
107 chunks
[chunk_name
, "chunklet", chunks
[chunk_name
, "chunklet"],
108 ++chunks
[chunk_name
, "chunklet", chunks
[chunk_name
, "chunklet"], "line"] ] = line
;
111 function chunk_include
(chunk_name
, chunk_ref
, indent
, tail
)
113 chunks
[chunk_name
, "part", ++chunks
[chunk_name
, "part"] ] = chunk_ref
;
114 chunks
[chunk_name
, "part", chunks
[chunk_name
, "part"], "type" ] = part_type_chunk
;
115 chunks
[chunk_name
, "part", chunks
[chunk_name
, "part"], "indent" ] = indent_string
(indent
);
116 chunks
[chunk_name
, "part", chunks
[chunk_name
, "part"], "tail" ] = tail
;
117 prime_chunk
(chunk_name
);
120 function indent_string
(indent
) {
121 return sprintf("%" indent "s
", "");
123 function output_chunk_names( c, prefix, suffix)
129 for (c in chunk_names) {
130 print prefix c suffix "\n";
133 function output_chunks( a)
135 for (a in chunk_names) {
136 output_chunk(chunk_names[a]);
140 function output_chunk(chunk) {
142 lineno_needed = linenos;
147 function write_chunk(chunk_name, indent, tail,
149 chunk_path, chunk_args,
151 part, max_part, part_line, frag, max_frag, text,
152 chunklet, only_part, call_chunk_args, mode)
154 if (match(chunk_name, "^
(.
*)\\[([0-9]*)\\]$
", chunk_name_parts)) {
155 chunk_name = chunk_name_parts[1];
156 only_part = chunk_name_parts[2];
159 new_mode(chunks[chunk_name, "language
"], mode);
160 split(chunks[chunk_name, "params
"], chunk_params, " *; *");
161 if (! (chunk_name in chunk_names)) {
162 error(sprintf(_"The root module
<<%s
>> was not defined.
\nUsed by
: %s
",\
163 chunk_name, chunk_path));
166 max_part = chunks[chunk_name, "part
"];
167 for(part = 1; part <= max_part; part++) {
168 if (! only_part || part == only_part) {
169 if (linenos && (chunk_name SUBSEP "part
" SUBSEP part SUBSEP "FILENAME" in chunks)) {
170 a_filename = chunks[chunk_name, "part
", part, "FILENAME"];
171 a_lineno = chunks[chunk_name, "part
", part, "LINENO
"];
172 if (a_filename != filename || a_lineno != lineno) {
177 chunklet = chunks[chunk_name, "part
", part];
178 if (chunks[chunk_name, "part
", part, "type
"] == part_type_chunk) {
179 if (match(chunklet, "^
([^
\\[]*)\\((.
*)\\)$
", chunklet_parts)) {
180 chunklet = chunklet_parts[1];
181 get_chunk_args(chunklet_parts[2], chunk_args);
182 # TO BE parse_chunk_args SOON
183 for (c in call_chunk_args) {
184 call_chunk_args[c] = expand_chunk_args(call_chunk_args[c], chunk_params, chunk_args);
187 split("", call_chunk_args);
189 write_chunk(chunklet,
190 chunks[chunk_name, "part
", part, "indent
"] indent,
191 chunks[chunk_name, "part
", part, "tail
"],
192 chunk_path "\n " chunk_name,
194 } else if (chunklet SUBSEP "line
" in chunks) {
195 max_frag = chunks[chunklet, "line
"];
196 for(frag = 1; frag <= max_frag; frag++) {
197 if (newline && lineno_needed && ! lineno_suppressed) {
198 filename = a_filename;
200 print "#line " lineno " \"" filename "\"\n"
204 text = chunks
[chunklet
, frag
];
207 text = expand_chunk_args
(text
, chunk_params
, chunk_args
);
211 if (part == max_part
&& frag == max_frag
&& length(chunk_path
)) {
218 if (newline
) text = indent text
;
223 # track_mode(mode, text);
226 lineno_suppressed =
substr(lastline
, length(lastline
)) ==
"\\";
230 # empty last chunklet
235 function expand_chunk_args
(text
, params
, args
,
236 p
, text_array
, next_text
, v
, t
, l
)
238 if (split(text
, text_array
, "\\${")) {
240 v
[params
[p
]]=args
[p
];
243 for(t in text_array
) if (t
>1) {
244 if (match(text_array
[t
], "^([a-zA-Z_][a-zA-Z0-9_]*)}", l
) &&
247 text = text v
[l
[1]] substr(text_array
[t
], length(l
[1])+2);
249 text = text
"${" text_array
[t
];
263 Optind =
1 # skip ARGV[0]
264 while(getopt
(ARGC, ARGV, "R:Ldhr")!=-1) {
265 if (Optopt ==
"R") root = Optarg
;
266 else if (Optopt ==
"r") root=
"";
267 else if (Optopt ==
"L") linenos =
1;
268 else if (Optopt ==
"d") debug =
1;
269 else if (Optopt ==
"h") help
();
270 else if (Optopt ==
"?") help
();
272 for (i=
1; i
<Optind
; i
++) { ARGV[i
]=
""; }
275 if (match($
0, "^\\\\Chunk{ *([^ ,}]*),?(.*)}", line
)) {
276 next_chunk_name = line
[1];
277 get_chunk_args
(line
[2], next_chunk_args
);
281 /^
\\begin{lstlisting
}|^
\\begin{Chunk
}/ {
282 if (match($
0, "}.*[[,] *name= *{? *([^], }]*)", line
)) {
285 new_chunk
(next_chunk_name
, next_chunk_args
);
291 if (match($
0, "^[<]<(.*)[>]>= *$", line
)) {
298 /^
\\[e
]nd
{lstlisting
}|^
\\[e
]nd
{Chunk
}/ {
308 length(active_chunk
) {
312 "([=]<\\\\chunkref{([^}>]*)}(\\(.*\\)|)>|<<([a-zA-Z_][-a-zA-Z0-9_]*)>>)",
315 chunklet =
substr(chunk
, 1, RSTART - 1);
316 indent
+=
length(chunklet
);
317 chunk_line
(active_chunk
, chunklet
);
318 chunk =
substr(chunk
, RSTART + RLENGTH);
319 if (substr(line
[1], 1, 1) ==
"=") {
321 chunk_include
(active_chunk
, line
[2] line
[3], indent
);
322 } else if (substr(line
[1], 1, 1) ==
"<") {
323 chunk_include
(active_chunk
, line
[4], indent
);
325 error
("Unknown chunk fragment: " line
[1]);
328 chunk_line
(active_chunk
, chunk
);
329 chunk_line
(active_chunk
, "\n");
333 print "------ chunk names "
334 output_chunk_names
();
335 print "====== chunks"
339 print a
"=" chunks
[a
];
343 if (length(root
)) output_chunk
(root
);
344 else output_chunk_names
();
346 function get_chunk_args
(text
, values
,
347 # optional parameters
348 path
, # hierarchical precursors
352 while(length(text
)) {
353 if (match(text
, "^ *}(.*)", a
)) {
356 if (!
match(text
, " *([^,=]*[^,= ]) *(([,=]) *(([^,}]*) *,* *(.*))|)$", a
)) {
361 if (substr(a
[4],1,1) ==
"{") {
362 text = get_chunk_args
(substr(a
[4],2), values
, path name SUBSEP
);
364 values
[path name
]=a
[5];
368 values
[path name
]=
"";