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
26 function getopt
(argc, argv, options
, thisopt
, i
)
28 if (length(options
) ==
0) # no options given
30 if (argv[Optind
] ==
"--") { # all done
34 } else if (argv[Optind
] !~
/^
-[^
: \t\n\f\r\v\b]/) {
40 thisopt =
substr(argv[Optind
], _opti
, 1)
42 i =
index(options
, thisopt
)
45 printf("%c -- invalid option\n",
46 thisopt
) > "/dev/stderr"
47 if (_opti
>=
length(argv[Optind
])) {
54 if (substr(options
, i
+ 1, 1) ==
":") {
56 if (length(substr(argv[Optind
], _opti
+ 1)) > 0)
57 Optarg =
substr(argv[Optind
], _opti
+ 1)
59 Optarg =
argv[++Optind
]
63 if (_opti ==
0 || _opti
>=
length(argv[Optind
])) {
71 function error
(message
)
73 print message
> "/dev/stderr";
76 function new_chunk
(chunk_name
, params
,
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
];
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
)
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
,
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
;
164 print "#line " lineno
" \"" filename "\""
172 max_line = chunks
[chunklet
, "line"];
173 for(line =
1; line
<= max_line
; line
++) {
174 lastline = chunks
[chunklet
, line
];
177 # if (length(chunk_args)) {
178 lastline = expand_chunk_args
(lastline
, chunk_params
, chunk_args
);
181 lastline = indent lastline tail
;
184 lineno_suppressed =
substr(lastline
, length(lastline
)) ==
"\\";
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
, "\\${")) {
199 v
[params
[p
]]=args
[p
];
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
) &&
207 text = text v
[l
[1]] substr(text_array
[t
], length(l
[1])+2);
209 text = text
"${" text_array
[t
];
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
]=
""; }
235 if (match($
0, "^\\\\Chunk{ *([^ ,}]*),?(.*)}", line
)) {
236 next_chunk_name=line
[1];
237 get_chunk_args
(line
[2], next_chunk_args
);
241 /^
\\begin{lstlisting
}/ {
242 if (match($
0, "}.*[[,] *name= *{? *([^], }]*)", line
)) {
245 new_chunk
(next_chunk_name
, next_chunk_args
);
250 /^
\\begin{CodeScrap
}|^
\\begin{Chunk
}/ {
254 /^
\\item
*\
[{/ && chunking
{
255 if (match($
0, "^\\\\item *\\[{(.*[^ ]) *}\\]", line
)) {
261 if (match($
0, "^[<]<(.*)[>]>= *$", line
)) {
268 /^
\\[e
]nd
{lstlisting
}/ {
273 /^
\\end{CodeScrap
}|^
\\end{Chunk
}|^@
/ {
282 /^.
*[=
]<\\chunkref
{/ {
283 if (match($
0, "^(.*)[=]<\\\\chunkref{(.*)}>(.*)", line
)) {
284 chunk_include
(active_chunk
, line
[2], line
[1], line
[3]);
289 if (match($
0, "^(.*)\\\\e[m][p][h]{([^}]*)}(.*)", line
)) {
290 chunk_include
(active_chunk
, line
[2], line
[1], line
[3]);
294 /^
[#\/ ]*[<]<.*[>]>/ && (length(active_chunk)) {
295 if (match($
0, "^(.*)[<]<(.*)[>]>(.*)", line
)) {
296 chunk_include
(active_chunk
, line
[2], line
[1], line
[3]);
300 length(active_chunk
) {
301 chunk_line
(active_chunk
, $
0);
305 print "------ chunk names "
307 print "====== 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
323 while(length(text
)) {
324 if (match(text
, "^ *}(.*)", a
)) {
327 if (!
match(text
, " *([^,=]*[^,= ]) *(([,=]) *(([^,}]*) *,* *(.*))|)$", a
)) {
332 if (substr(a
[4],1,1) ==
"{") {
333 text = get_chunk_args
(substr(a
[4],2), values
, path name SUBSEP
);
335 values
[path name
]=a
[5];
339 values
[path name
]=
"";