]>
Commit | Line | Data |
---|---|---|
9c0d9ce3 DS |
1 | #!/bin/awk -f |
2 | # scripts/options.awk - library build configuration control | |
3 | # | |
72281370 | 4 | # last changed in libpng version 1.5.7 - December 15, 2011 |
9c0d9ce3 DS |
5 | # |
6 | # Copyright (c) 1998-2011 Glenn Randers-Pehrson | |
7 | # | |
8 | # This code is released under the libpng license. | |
9 | # For conditions of distribution and use, see the disclaimer | |
10 | # and license in png.h | |
11 | ||
12 | # The output of this script is written to the file given by | |
13 | # the variable 'out'. The script is run twice, once with | |
14 | # an intermediate output file, 'options.tmp' then again on | |
15 | # that file to produce the final output: | |
16 | # | |
17 | # awk -f scripts/options.awk out=options.tmp scripts/options.dfa 1>&2 | |
18 | # awk -f scripts/options.awk out=options.dfn options.tmp 1>&2 | |
19 | # | |
20 | # Some options may be specified on the command line: | |
21 | # | |
22 | # deb=1 Causes debugging to be output | |
23 | # logunsupported=1 Causes all options to be recorded in the output | |
24 | # everything=off Causes all options to be disabled by default | |
25 | # everything=on Causes all options to be enabled by default | |
26 | # | |
27 | # If awk fails on your platform, try nawk instead. | |
28 | # | |
29 | # These options may also be specified in the original input file (and | |
30 | # are copied to the preprocessed file). | |
31 | ||
32 | BEGIN{ | |
fff5f7d5 | 33 | out="" # intermediate, preprocessed, file |
9c0d9ce3 | 34 | pre=-1 # preprocess (first line) |
72281370 DS |
35 | version="libpng version unknown" # version information |
36 | version_file="" # where to find the version | |
9c0d9ce3 | 37 | err=0 # in-line exit sets this |
fff5f7d5 VZ |
38 | # The following definitions prevent the C preprocessor noticing the lines |
39 | # that will be in the final output file. Some C preprocessors tokenise | |
40 | # the lines, for example by inserting spaces around operators, and all | |
41 | # C preprocessors notice lines that start with '#', most remove comments. | |
42 | # The technique adopted here is to make the final output lines into | |
43 | # C strings (enclosed in double quotes), preceeded by PNG_DFN. As a | |
44 | # consequence the output cannot contain a 'raw' double quote - instead put | |
45 | # @' in, this will be replaced by a single " afterward. See the parser | |
46 | # script dfn.awk for more capabilities (not required here). Note that if | |
47 | # you need a " in a 'setting' in pnglibconf.dfa it must also be @'! | |
48 | dq="@'" # For a single double quote | |
49 | start=" PNG_DFN \"" # Start stuff to output (can't contain a "!) | |
50 | end="\" " # End stuff to output | |
51 | subs="@\" " # Substitute start (substitute a C macro) | |
52 | sube=" \"@" # Substitute end | |
53 | comment=start "/*" # Comment start | |
9c0d9ce3 | 54 | cend="*/" end # Comment end |
fff5f7d5 VZ |
55 | def=start "#define PNG_" # Arbitrary define |
56 | sup="_SUPPORTED" end # end supported option | |
57 | und=comment "#undef PNG_" # Unsupported option | |
58 | une="_SUPPORTED" cend # end unsupported option | |
59 | error=start "ERROR:" # error message, terminate with 'end' | |
9c0d9ce3 DS |
60 | |
61 | # Variables | |
62 | deb=0 # debug - set on command line | |
63 | everything="" # do not override defaults | |
64 | logunsupported=0 # write unsupported options too | |
65 | ||
66 | # Precreate arrays | |
fff5f7d5 | 67 | # for each option: |
9c0d9ce3 DS |
68 | option[""] = "" # list of all options: default enabled/disabled |
69 | done[""] = 1 # marks option as having been output | |
70 | requires[""] = "" # requires by option | |
71 | iffs[""] = "" # if by option | |
72 | enabledby[""] = "" # options that enable it by option | |
fff5f7d5 VZ |
73 | sets[""] = "" # settings set by each option |
74 | setval[""] = "" # value to set (indexed: 'option sets[option]') | |
75 | # for each setting: | |
9c0d9ce3 DS |
76 | setting[""] = "" # requires by setting |
77 | defaults[""] = "" # used for a defaulted value | |
78 | doneset[""] = 1 # marks setting as having been output | |
79 | r[""] = "" # Temporary array | |
80 | ||
81 | # For decorating the output file | |
82 | protect = "" | |
83 | } | |
84 | ||
85 | # The output file must be specified before any input: | |
fff5f7d5 | 86 | out == "" { |
9c0d9ce3 DS |
87 | print "out=output.file must be given on the command line" |
88 | err = 1 | |
89 | exit 1 | |
90 | } | |
91 | ||
92 | # The very first line indicates whether we are reading pre-processed | |
93 | # input or not, this must come *first* because 'PREPROCESSED' needs | |
94 | # to be the very first line in the temporary file. | |
95 | pre == -1{ | |
96 | if ($0 == "PREPROCESSED") { | |
97 | pre = 0 | |
98 | next | |
99 | } else { | |
100 | pre = 1 | |
101 | print "PREPROCESSED" >out | |
102 | # And fall through to continue processing | |
103 | } | |
104 | } | |
105 | ||
72281370 DS |
106 | # While pre-processing if version is set to "search" look for a version string |
107 | # in the following file. | |
108 | pre && version == "search" && version_file == ""{ | |
109 | version_file = FILENAME | |
110 | } | |
111 | ||
112 | pre && version == "search" && version_file != FILENAME{ | |
113 | print "version string not found in", version_file | |
114 | err = 1 | |
115 | exit 1 | |
116 | } | |
117 | ||
118 | pre && version == "search" && $0 ~ /^ \* libpng version/{ | |
119 | version = substr($0, 4) | |
120 | print "version =", version >out | |
121 | next | |
122 | } | |
123 | ||
124 | pre && FILENAME == version_file{ | |
125 | next | |
126 | } | |
127 | ||
9c0d9ce3 DS |
128 | # variable=value |
129 | # Sets the given variable to the given value (the syntax is fairly | |
130 | # free form, except for deb (you are expected to understand how to | |
131 | # set the debug variable...) | |
132 | # | |
133 | # This happens before the check on 'pre' below skips most of the | |
134 | # rest of the actions, so the variable settings happen during | |
135 | # preprocessing but are recorded in the END action too. This | |
136 | # allows them to be set on the command line too. | |
72281370 DS |
137 | $0 ~ /^[ ]*version[ ]*=/{ |
138 | sub(/^[ ]*version[ ]*=[ ]*/, "") | |
139 | version = $0 | |
140 | next | |
141 | } | |
9c0d9ce3 DS |
142 | $0 ~ /^[ ]*everything[ =]*off[ ]*$/{ |
143 | everything = "off" | |
144 | next | |
145 | } | |
146 | $0 ~ /^[ ]*everything[ =]*on[ ]*$/{ | |
147 | everything = "on" | |
148 | next | |
149 | } | |
150 | $0 ~ /^[ ]*logunsupported[ =]*0[ ]*$/{ | |
151 | logunsupported = 0 | |
152 | next | |
153 | } | |
154 | $0 ~ /^[ ]*logunsupported[ =]*1[ ]*$/{ | |
155 | logunsupported = 1 | |
156 | next | |
157 | } | |
158 | $1 == "deb" && $2 == "=" && NF == 3{ | |
159 | deb = $3 | |
160 | next | |
161 | } | |
162 | ||
163 | # Preprocessing - this just copies the input file with lines | |
164 | # that need preprocessing (just chunk at present) expanded | |
165 | # The bare "pre" instead of "pre != 0" crashes under Sunos awk | |
166 | pre && $1 != "chunk"{ | |
167 | print >out | |
168 | next | |
169 | } | |
170 | ||
171 | # The first characters of the line determine how it is processed, | |
172 | # leading spaces are ignored. In general tokens that are not | |
173 | # keywords are the names of options. An option 'name' is | |
174 | # controlled by the definition of the corresponding macros: | |
175 | # | |
176 | # PNG_name_SUPPORTED The option is turned on | |
177 | # PNG_NO_name | |
178 | # PNG_NO_name_SUPPORTED If the first macro is not defined | |
179 | # either of these will turn the option off | |
180 | # | |
181 | # If none of these macros are defined the option is turned on, unless | |
182 | # the keyword 'off' is given in a line relating to the option. The | |
183 | # keyword 'on' can also be given, but it will be ignored (since it is | |
184 | # the default.) | |
185 | # | |
186 | # In the syntax below a 'name' is indicated by "NAME", other macro | |
187 | # values are indicated by "MACRO", as with "NAME" the leading "PNG_" | |
188 | # is omitted, but in this case the "NO_" prefix and the "_SUPPORTED" | |
189 | # suffix are never used. | |
190 | # | |
191 | # Each line is introduced by a keyword - the first non-space characters | |
192 | # on the line. A line starting with a '#' is a comment - it is totally | |
193 | # ignored. Keywords are as follows, a NAME, is simply a macro name | |
194 | # without the leading PNG_, PNG_NO_ or the trailing _SUPPORTED. | |
195 | ||
196 | $1 ~ /^#/ || $0 ~ /^[ ]*$/{ | |
197 | next | |
198 | } | |
199 | ||
200 | # com <comment> | |
201 | # The whole line is placed in the output file as a comment with | |
202 | # the preceding 'com' removed | |
203 | $1 == "com"{ | |
204 | if (NF > 1) { | |
205 | # sub(/^[ ]*com[ ]*/, "") | |
206 | $1 = "" | |
fff5f7d5 | 207 | print comment $0, cend >out |
9c0d9ce3 DS |
208 | } else |
209 | print start end >out | |
210 | next | |
211 | } | |
212 | ||
72281370 DS |
213 | # version |
214 | # Inserts a version comment | |
215 | $1 == "version" && NF == 1{ | |
216 | if (version == "") { | |
217 | print "ERROR: no version string set" | |
218 | err = 1 # prevent END{} running | |
219 | exit 1 | |
220 | } | |
221 | ||
222 | print comment, version, cend >out | |
223 | next | |
224 | } | |
225 | ||
9c0d9ce3 DS |
226 | # file output input protect |
227 | # Informational: the official name of the input file (without | |
228 | # make generated local directories), the official name of the | |
229 | # output file and, if required, a name to use in a protection | |
230 | # macro for the contents. | |
231 | $1 == "file" && NF >= 2{ | |
232 | print comment, $2, cend >out | |
233 | print comment, "Machine generated file: DO NOT EDIT", cend >out | |
234 | if (NF >= 3) | |
235 | print comment, "Derived from:", $3, cend >out | |
236 | protect = $4 | |
237 | if (protect != "") { | |
238 | print start "#ifndef", protect end >out | |
239 | print start "#define", protect end >out | |
240 | } | |
241 | next | |
242 | } | |
243 | ||
fff5f7d5 VZ |
244 | # option NAME ( (requires|enables|if) NAME* | on | off | disabled | |
245 | # sets SETTING VALUE+ )* | |
246 | # | |
9c0d9ce3 DS |
247 | # Declares an option 'NAME' and describes its default setting (disabled) |
248 | # and its relationship to other options. The option is disabled | |
249 | # unless *all* the options listed after 'requires' are set and at | |
250 | # least one of the options listed after 'if' is set. If the | |
251 | # option is set then it turns on all the options listed after 'enables'. | |
252 | # | |
253 | # Note that "enables" takes priority over the required/if/disabled/off | |
254 | # setting of the target option. | |
255 | # | |
256 | # The definition file may list an option as 'disabled': off by default, | |
257 | # otherwise the option is enabled: on by default. A later (and it must | |
258 | # be later) entry may turn an option on or off explicitly. | |
259 | ||
260 | $1 == "option" && NF >= 2{ | |
fff5f7d5 VZ |
261 | opt = $2 |
262 | sub(/,$/,"",opt) | |
263 | onoff = option[opt] # records current (and the default is "", enabled) | |
9c0d9ce3 | 264 | key = "" |
fff5f7d5 VZ |
265 | istart = 3 |
266 | do { | |
267 | if (istart == 1) { # continuation line | |
268 | val = getline | |
269 | ||
270 | if (val != 1) { # error reading it | |
271 | if (val == 0) | |
272 | print "option", opt ": ERROR: missing contination line" | |
273 | else | |
274 | print "option", opt ": ERROR: error reading continuation line" | |
275 | ||
276 | # This is a hard error | |
277 | err = 1 # prevent END{} running | |
278 | exit 1 | |
279 | } | |
280 | } | |
281 | ||
282 | for (i=istart; i<=NF; ++i) { | |
283 | val=$(i) | |
284 | sub(/,$/,"",val) | |
285 | if (val == "on" || val == "off" || val == "disabled") { | |
286 | key = "" | |
287 | if (onoff != val) { | |
288 | # on or off can zap disabled or enabled: | |
289 | if (onoff == "" || (onoff == "disabled" || onoff == "enabled") && | |
290 | (val == "on" || val == "off")) { | |
291 | # It's easy to mis-spell the option when turning it | |
292 | # on or off, so warn about it here: | |
293 | if (onoff == "" && (val == "on" || val == "off")) { | |
294 | print "option", opt ": ERROR: turning unrecognized option", val | |
295 | # For the moment error out - it is safer | |
296 | err = 1 # prevent END{} running | |
297 | exit 1 | |
298 | } | |
299 | onoff = val | |
300 | } else { | |
301 | # Print a message, otherwise the error | |
302 | # below is incomprehensible | |
303 | print "option", opt ": currently", onoff ": attempt to turn", val | |
304 | break | |
9c0d9ce3 | 305 | } |
9c0d9ce3 | 306 | } |
fff5f7d5 VZ |
307 | } else if (val == "requires" || val == "if" || val == "enables" || val =="sets") { |
308 | key = val | |
309 | } else if (key == "requires") { | |
310 | requires[opt] = requires[opt] " " val | |
311 | } else if (key == "if") { | |
312 | iffs[opt] = iffs[opt] " " val | |
313 | } else if (key == "enables") { | |
314 | enabledby[val] = enabledby[val] " " opt | |
315 | } else if (key == "sets") { | |
316 | sets[opt] = sets[opt] " " val | |
317 | key = "setval" | |
318 | set = val | |
319 | } else if (key == "setval") { | |
320 | setval[opt " " set] = setval[opt " " set] " " val | |
321 | } else | |
322 | break # bad line format | |
323 | } | |
324 | ||
325 | istart = 1 | |
326 | } while (i > NF && $0 ~ /,$/) | |
9c0d9ce3 DS |
327 | |
328 | if (i > NF) { | |
329 | # Set the option, defaulting to 'enabled' | |
330 | if (onoff == "") onoff = "enabled" | |
fff5f7d5 | 331 | option[opt] = onoff |
9c0d9ce3 DS |
332 | next |
333 | } | |
334 | # Else fall through to the error handler | |
335 | } | |
336 | ||
fff5f7d5 | 337 | # chunk NAME [requires OPT] [enables LIST] [on|off|disabled] |
9c0d9ce3 DS |
338 | # Expands to the 'option' settings appropriate to the reading and |
339 | # writing of an ancilliary PNG chunk 'NAME': | |
340 | # | |
341 | # option READ_NAME requires READ_ANCILLARY_CHUNKS [READ_OPT] | |
fff5f7d5 | 342 | # option READ_NAME enables NAME LIST |
9c0d9ce3 DS |
343 | # [option READ_NAME off] |
344 | # option WRITE_NAME requires WRITE_ANCILLARY_CHUNKS [WRITE_OPT] | |
fff5f7d5 | 345 | # option WRITE_NAME enables NAME LIST |
9c0d9ce3 DS |
346 | # [option WRITE_NAME off] |
347 | ||
348 | pre != 0 && $1 == "chunk" && NF >= 2{ | |
349 | # 'chunk' is handled on the first pass by writing appropriate | |
350 | # 'option' lines into the intermediate file. | |
fff5f7d5 VZ |
351 | opt = $2 |
352 | sub(/,$/,"",opt) | |
9c0d9ce3 DS |
353 | onoff = "" |
354 | reqread = "" | |
355 | reqwrite = "" | |
fff5f7d5 VZ |
356 | enables = "" |
357 | req = 0 | |
358 | istart = 3 | |
359 | do { | |
360 | if (istart == 1) { # continuation line | |
361 | val = getline | |
362 | ||
363 | if (val != 1) { # error reading it | |
364 | if (val == 0) | |
365 | print "chunk", opt ": ERROR: missing contination line" | |
366 | else | |
367 | print "chunk", opt ": ERROR: error reading continuation line" | |
368 | ||
369 | # This is a hard error | |
370 | err = 1 # prevent END{} running | |
371 | exit 1 | |
372 | } | |
373 | } | |
374 | ||
9c0d9ce3 | 375 | # read the keywords/additional OPTS |
fff5f7d5 VZ |
376 | for (i=istart; i<=NF; ++i) { |
377 | val = $(i) | |
378 | sub(/,$/,"",val) | |
379 | if (val == "on" || val == "off" || val == "disabled") { | |
380 | if (onoff != val) { | |
9c0d9ce3 | 381 | if (onoff == "") |
fff5f7d5 | 382 | onoff = val |
9c0d9ce3 DS |
383 | else |
384 | break # on/off conflict | |
385 | } | |
fff5f7d5 VZ |
386 | req = 0 |
387 | } else if (val == "requires") | |
9c0d9ce3 | 388 | req = 1 |
fff5f7d5 VZ |
389 | else if (val == "enables") |
390 | req = 2 | |
391 | else if (req == 1){ | |
392 | reqread = reqread " READ_" val | |
393 | reqwrite = reqwrite " WRITE_" val | |
394 | } else if (req == 2) | |
395 | enables = enables " " val | |
396 | else | |
9c0d9ce3 | 397 | break # bad line: handled below |
9c0d9ce3 | 398 | } |
fff5f7d5 VZ |
399 | |
400 | istart = 1 | |
401 | } while (i > NF && $0 ~ /,$/) | |
9c0d9ce3 DS |
402 | |
403 | if (i > NF) { | |
404 | # Output new 'option' lines to the intermediate file (out) | |
fff5f7d5 VZ |
405 | print "option READ_" opt, "requires READ_ANCILLARY_CHUNKS" reqread, "enables", opt enables , onoff >out |
406 | print "option WRITE_" opt, "requires WRITE_ANCILLARY_CHUNKS" reqwrite, "enables", opt enables, onoff >out | |
9c0d9ce3 DS |
407 | next |
408 | } | |
409 | # Else hit the error handler below - bad line format! | |
410 | } | |
411 | ||
412 | # setting MACRO ( requires MACRO* )* [ default VALUE ] | |
413 | # Behaves in a similar way to 'option' without looking for NO_ or | |
414 | # _SUPPORTED; the macro is enabled if it is defined so long as all | |
415 | # the 'requires' macros are also defined. The definitions may be | |
416 | # empty, an error will be issued if the 'requires' macros are | |
417 | # *not* defined. If given the 'default' value is used if the | |
418 | # macro is not defined. The default value will be re-tokenised. | |
419 | # (BTW: this is somewhat restrictive, it mainly exists for the | |
420 | # support of non-standard configurations and numeric parameters, | |
421 | # see the uses in scripts/options.dat | |
422 | ||
423 | $1 == "setting" && (NF == 2 || NF >= 3 && ($3 == "requires" || $3 == "default")){ | |
424 | reqs = "" | |
425 | deflt = "" | |
426 | isdef = 0 | |
427 | key = "" | |
428 | for (i=3; i<=NF; ++i) | |
429 | if ($(i) == "requires" || $(i) == "default") { | |
430 | key = $(i) | |
431 | if (key == "default") isdef = 1 | |
432 | } else if (key == "requires") | |
433 | reqs = reqs " " $(i) | |
434 | else if (key == "default") | |
435 | deflt = deflt " " $(i) | |
436 | else | |
437 | break # Format error, handled below | |
438 | ||
439 | setting[$2] = reqs | |
440 | # NOTE: this overwrites a previous value silently | |
441 | if (isdef && deflt == "") | |
442 | deflt = " " # as a flag to force output | |
443 | defaults[$2] = deflt | |
444 | next | |
445 | } | |
446 | ||
447 | # The order of the dependency lines (option, chunk, setting) is irrelevant | |
448 | # - the 'enables', 'requires' and 'if' settings will be used to determine | |
449 | # the correct order in the output and the final values in pnglibconf.h are | |
450 | # not order dependent. 'requires' and 'if' entries take precedence over | |
451 | # 'enables' from other options; if an option requires another option it | |
452 | # won't be set regardless of any options that enable it unless the other | |
453 | # option is also enabled. | |
454 | # | |
455 | # Similarly 'enables' trumps a NO_ definition in CFLAGS or pngusr.h | |
456 | # | |
457 | # For simplicity cycles in the definitions are regarded as errors, | |
458 | # even if they are not ambiguous. | |
459 | # A given NAME can be specified in as many 'option' lines as required, the | |
460 | # definitions are additive. | |
461 | ||
462 | # For backwards compatibility equivalent macros may be listed thus: | |
463 | # | |
464 | # = [NO_]NAME MACRO | |
465 | # Makes -DMACRO equivalent to -DPNG_NO_NAME or -DPNG_NAME_SUPPORTED | |
466 | # as appropriate. | |
467 | # | |
468 | # The definition is injected into the C compiler input when encountered | |
469 | # in the second pass (so all these definitions appear *after* the @ | |
470 | # lines!) | |
471 | # | |
472 | # 'NAME' is as above, but 'MACRO' is the full text of the equivalent | |
473 | # old, deprecated, macro. | |
474 | ||
475 | $1 == "=" && NF == 3{ | |
476 | print "#ifdef PNG_" $3 >out | |
477 | if ($2 ~ /^NO_/) | |
478 | print "# define PNG_" $2 >out | |
479 | else | |
480 | print "# define PNG_" $2 "_SUPPORTED" >out | |
481 | print "#endif" >out | |
482 | next | |
483 | } | |
484 | ||
485 | # Lines may be injected into the C compiler input by preceding them | |
486 | # with an "@" character. The line is copied with just the leading | |
487 | # @ removed. | |
488 | ||
489 | $1 ~ /^@/{ | |
490 | # sub(/^[ ]*@/, "") | |
491 | $1 = substr($1, 2) | |
492 | print >out | |
493 | next | |
494 | } | |
495 | ||
496 | # Check for unreognized lines, because of the preprocessing chunk | |
497 | # format errors will be detected on the first pass independent of | |
498 | # any other format errors. | |
499 | { | |
500 | print "options.awk: bad line (" NR "):", $0 | |
501 | err = 1 # prevent END{} running | |
502 | exit 1 | |
503 | } | |
504 | ||
505 | # For checking purposes names that start with "ok_" or "fail_" are | |
506 | # not output to pnglibconf.h and must be either enabled or disabled | |
507 | # respectively for the build to succeed. This allows interdependencies | |
508 | # between options of the form "at least one of" or "at most one of" | |
509 | # to be checked. For example: | |
510 | # | |
511 | # option FLOATING_POINT enables ok_math | |
512 | # option FIXED_POINT enables ok_math | |
513 | # This ensures that at least one of FLOATING_POINT and FIXED_POINT | |
514 | # must be set for the build to succeed. | |
515 | # | |
516 | # option fail_math requires FLOATING_POINT FIXED_POINT | |
517 | # This means the build will fail if *both* FLOATING_POINT and | |
518 | # FIXED_POINT are set (this is an example; in fact both are allowed.) | |
519 | # | |
520 | # If all these options were given the build would require exactly one | |
521 | # of the names to be enabled. | |
522 | ||
523 | END{ | |
524 | # END{} gets run on an exit (a traditional awk feature) | |
525 | if (err) exit 1 | |
526 | ||
527 | if (pre) { | |
528 | # Record the final value of the variables | |
529 | print "deb =", deb >out | |
530 | if (everything != "") { | |
531 | print "everything =", everything >out | |
532 | } | |
533 | print "logunsupported =", logunsupported >out | |
534 | exit 0 | |
535 | } | |
536 | ||
fff5f7d5 | 537 | # Do the options first (allowing options to set settings). The dependency |
9c0d9ce3 DS |
538 | # tree is thus: |
539 | # | |
540 | # name > name | |
541 | # name requires name | |
542 | # name if name | |
543 | # name enabledby name | |
544 | # | |
545 | # First build a list 'tree' by option of all the things on which | |
546 | # it depends. | |
547 | print "" >out | |
548 | print "/* OPTIONS */" >out | |
549 | print comment, "options", cend >out | |
550 | for (opt in enabledby) tree[opt] = 1 # may not be explicit options | |
551 | for (opt in option) if (opt != "") { | |
552 | o = option[opt] | |
553 | # option should always be one of the following values | |
554 | if (o != "on" && o != "off" && o != "disabled" && o != "enabled") { | |
555 | print "internal option error (" o ")" | |
556 | exit 1 | |
557 | } | |
558 | tree[opt] = "" # so unlisted options marked | |
559 | } | |
560 | for (opt in tree) if (opt != "") { | |
561 | if (tree[opt] == 1) { | |
562 | tree[opt] = "" | |
563 | if (option[opt] != "") { | |
564 | print "internal error (1)" | |
565 | exit 1 | |
566 | } | |
567 | # Macros only listed in 'enables' remain off unless | |
568 | # one of the enabling macros is on. | |
569 | option[opt] = "disabled" | |
570 | } | |
571 | ||
572 | split("", list) # clear 'list' | |
573 | # Now add every requires, iffs or enabledby entry to 'list' | |
574 | # so that we can add a unique list of requirements to tree[i] | |
575 | split(requires[opt] iffs[opt] enabledby[opt], r) | |
576 | for (i in r) list[r[i]] = 1 | |
577 | for (i in list) tree[opt] = tree[opt] " " i | |
578 | } | |
579 | ||
580 | # print the tree for extreme debugging | |
581 | if (deb > 2) for (i in tree) if (i != "") print i, "depends-on" tree[i] | |
582 | ||
583 | # Ok, now check all options marked explicitly 'on' or 'off': | |
584 | # | |
585 | # If an option[opt] is 'on' then turn on all requires[opt] | |
586 | # If an option[opt] is 'off' then turn off all enabledby[opt] | |
587 | # | |
588 | # Error out if we have to turn 'on' an 'off' option or vice versa. | |
589 | npending = 0 | |
590 | for (opt in option) if (opt != "") { | |
591 | if (option[opt] == "on" || option[opt] == "off") { | |
592 | pending[++npending] = opt | |
593 | } | |
594 | } | |
595 | ||
596 | err = 0 # set on error | |
597 | while (npending > 0) { | |
598 | opt = pending[npending--] | |
599 | if (option[opt] == "on") { | |
600 | nreqs = split(requires[opt], r) | |
601 | for (j=1; j<=nreqs; ++j) { | |
602 | if (option[r[j]] == "off") { | |
603 | print "option", opt, "turned on, but requirement", r[j], "is turned off" | |
604 | err = 1 | |
605 | } else if (option[r[j]] != "on") { | |
606 | option[r[j]] = "on" | |
607 | pending[++npending] = r[j] | |
608 | } | |
609 | } | |
610 | } else { | |
611 | if (option[opt] != "off") { | |
612 | print "internal error (2)" | |
613 | exit 1 | |
614 | } | |
615 | nreqs = split(enabledby[opt], r) | |
616 | for (j=1; j<=nreqs; ++j) { | |
617 | if (option[r[j]] == "on") { | |
618 | print "option", opt, "turned off, but enabled by", r[j], "which is turned on" | |
619 | err = 1 | |
620 | } else if (option[r[j]] != "off") { | |
621 | option[r[j]] = "off" | |
622 | pending[++npending] = r[j] | |
623 | } | |
624 | } | |
625 | } | |
626 | } | |
627 | if (err) exit 1 | |
628 | ||
fff5f7d5 VZ |
629 | # Sort options: |
630 | print "PNG_DFN_START_SORT 2" >out | |
631 | ||
9c0d9ce3 DS |
632 | # option[i] is now the complete list of all the tokens we may |
633 | # need to output, go through it as above, depth first. | |
634 | finished = 0 | |
635 | while (!finished) { | |
636 | finished = 1 | |
637 | movement = 0 # done nothing | |
638 | for (i in option) if (!done[i]) { | |
639 | nreqs = split(tree[i], r) | |
640 | if (nreqs > 0) { | |
641 | for (j=1; j<=nreqs; ++j) if (!done[r[j]]) { | |
642 | break | |
643 | } | |
644 | if (j<=nreqs) { | |
645 | finished = 0 | |
646 | continue # next option | |
647 | } | |
648 | } | |
649 | ||
650 | # All the requirements have been processed, output | |
651 | # this option. An option is _SUPPORTED if: | |
652 | # | |
653 | # all 'requires' are _SUPPORTED AND | |
654 | # at least one of the 'if' options are _SUPPORTED AND | |
655 | # EITHER: | |
656 | # The name is _SUPPORTED (on the command line) | |
657 | # OR: | |
658 | # an 'enabledby' is _SUPPORTED | |
659 | # OR: | |
660 | # NO_name is not defined AND | |
661 | # the option is not disabled; an option is disabled if: | |
662 | # option == off | |
663 | # option == disabled && everything != on | |
664 | # option == "" && everything == off | |
665 | if (deb) print "option", i | |
666 | print "" >out | |
667 | print "/* option:", i, option[i] >out | |
668 | print " * requires: " requires[i] >out | |
fff5f7d5 VZ |
669 | print " * if: " iffs[i] >out |
670 | print " * enabled-by:" enabledby[i] >out | |
671 | print " * sets: " sets[i], "*/" >out | |
9c0d9ce3 DS |
672 | print "#undef PNG_on" >out |
673 | print "#define PNG_on 1" >out | |
674 | ||
675 | # requires | |
676 | nreqs = split(requires[i], r) | |
677 | for (j=1; j<=nreqs; ++j) { | |
678 | print "#ifndef PNG_" r[j] "_SUPPORTED" >out | |
679 | print "# undef PNG_on /*!" r[j] "*/" >out | |
680 | # this error appears in the final output if something | |
681 | # was switched 'on' but the processing above to force | |
682 | # the requires did not work | |
683 | if (option[i] == "on") { | |
684 | print error, i, "requires", r[j] end >out | |
685 | } | |
686 | print "#endif" >out | |
687 | } | |
688 | ||
689 | # if | |
690 | nreqs = split(iffs[i], r) | |
691 | print "#undef PNG_no_if" >out | |
692 | if (nreqs > 0) { | |
693 | print "/* if" iffs[i], "*/" >out | |
694 | print "#define PNG_no_if 1" >out | |
695 | for (j=1; j<=nreqs; ++j) { | |
696 | print "#ifdef PNG_" r[j] "_SUPPORTED" >out | |
697 | print "# undef PNG_no_if /*" r[j] "*/" >out | |
698 | print "#endif" >out | |
699 | } | |
700 | print "#ifdef PNG_no_if /*missing if*/" >out | |
701 | print "# undef PNG_on" >out | |
702 | # There is no checking above for this, because we | |
703 | # don't know which 'if' to choose, so whine about | |
704 | # it here: | |
705 | if (option[i] == "on") { | |
706 | print error, i, "needs one of:", iffs[i] end >out | |
707 | } | |
708 | print "#endif" >out | |
709 | } | |
710 | ||
711 | print "#ifdef PNG_on /*requires, if*/" >out | |
712 | # enables | |
713 | print "# undef PNG_not_enabled" >out | |
714 | print "# define PNG_not_enabled 1" >out | |
715 | print " /* enabled by" enabledby[i], "*/" >out | |
716 | nreqs = split(enabledby[i], r) | |
717 | for (j=1; j<=nreqs; ++j) { | |
718 | print "#ifdef PNG_" r[j] "_SUPPORTED" >out | |
719 | print "# undef PNG_not_enabled /*" r[j] "*/" >out | |
720 | # Oops, probably not intended (should be factored | |
721 | # out by the checks above). | |
722 | if (option[i] == "off") { | |
723 | print error, i, "enabled by:", r[j] end >out | |
724 | } | |
725 | print "#endif" >out | |
726 | } | |
727 | ||
728 | print "# ifndef PNG_" i "_SUPPORTED /*!command line*/" >out | |
729 | print "# ifdef PNG_not_enabled /*!enabled*/" >out | |
730 | if (option[i] == "off" || option[i] == "disabled" && everything != "on" || option[i] == "enabled" && everything == "off") { | |
731 | print "# undef PNG_on /*default off*/" >out | |
732 | } else { | |
733 | print "# ifdef PNG_NO_" i >out | |
734 | print "# undef PNG_on /*turned off*/" >out | |
735 | print "# endif" >out | |
736 | print "# ifdef PNG_NO_" i "_SUPPORTED" >out | |
737 | print "# undef PNG_on /*turned off*/" >out | |
738 | print "# endif" >out | |
739 | } | |
740 | print "# endif /*!enabled*/" >out | |
741 | print "# ifdef PNG_on" >out | |
742 | # The _SUPPORTED macro must be defined so that dependent | |
743 | # options output later work. | |
744 | print "# define PNG_" i "_SUPPORTED" >out | |
745 | print "# endif" >out | |
746 | print "# endif /*!command line*/" >out | |
747 | # If PNG_on is still set the option should be defined in | |
748 | # pnglibconf.h | |
749 | print "# ifdef PNG_on" >out | |
750 | if (i ~ /^fail_/) { | |
751 | print error, i, "is on: enabled by:" iffs[i] enabledby[i] ", requires" requires[i] end >out | |
752 | } else if (i !~ /^ok_/) { | |
753 | print def i sup >out | |
fff5f7d5 VZ |
754 | # Supported option, set required settings |
755 | nreqs = split(sets[i], r) | |
756 | for (j=1; j<=nreqs; ++j) { | |
757 | print "# ifdef PNG_set_" r[j] >out | |
758 | # Some other option has already set a value: | |
759 | print error, i, "sets", r[j] ": duplicate setting" end >out | |
760 | print error, " previous value: " end "PNG_set_" r[j] >out | |
761 | print "# else" >out | |
762 | # Else set the default: note that this won't accept arbitrary | |
763 | # values, the setval string must be acceptable to all the C | |
764 | # compilers we use. That means it must be VERY simple; a number, | |
765 | # a name or a string. | |
766 | print "# define PNG_set_" r[j], setval[i " " r[j]] >out | |
767 | print "# endif" >out | |
768 | } | |
9c0d9ce3 DS |
769 | } |
770 | print "# endif /* definition */" >out | |
771 | print "#endif /*requires, if*/" >out | |
772 | if (logunsupported || i ~ /^ok_/) { | |
773 | print "#ifndef PNG_on" >out | |
774 | if (logunsupported) { | |
775 | print und i une >out | |
776 | } | |
777 | if (i ~ /^ok_/) { | |
778 | print error, i, "not enabled: requires:" requires[i] ", enabled by:" iffs[i] enabledby[i] end >out | |
779 | } | |
780 | print "#endif" >out | |
781 | } | |
782 | ||
783 | done[i] = 1 | |
784 | ++movement | |
785 | } | |
786 | ||
787 | if (!finished && !movement) { | |
788 | print "option: loop or missing option in dependency tree, cannot process:" | |
789 | for (i in option) if (!done[i]) { | |
790 | print " option", i, "depends on" tree[i], "needs:" | |
791 | nreqs = split(tree[i], r) | |
792 | if (nreqs > 0) for (j=1; j<=nreqs; ++j) if (!done[r[j]]) { | |
793 | print " " r[j] | |
794 | } | |
795 | } | |
796 | exit 1 | |
797 | } | |
798 | } | |
fff5f7d5 | 799 | print "PNG_DFN_END_SORT" >out |
9c0d9ce3 DS |
800 | print comment, "end of options", cend >out |
801 | ||
fff5f7d5 VZ |
802 | # Do the 'setting' values second, the algorithm the standard |
803 | # tree walk (O(1)) done in an O(2) while/for loop; interations | |
804 | # settings x depth, outputing the deepest required macros | |
805 | # first. | |
806 | print "" >out | |
807 | print "/* SETTINGS */" >out | |
808 | print comment, "settings", cend >out | |
809 | # Sort (in dfn.awk) on field 2, the setting name | |
810 | print "PNG_DFN_START_SORT 2" >out | |
811 | finished = 0 | |
812 | while (!finished) { | |
813 | finished = 1 | |
814 | movement = 0 # done nothing | |
815 | for (i in setting) if (!doneset[i]) { | |
816 | nreqs = split(setting[i], r) | |
817 | if (nreqs > 0) { | |
818 | # By default assume the requires values are options, but if there | |
819 | # is no option with that name check for a setting | |
820 | for (j=1; j<=nreqs; ++j) if (option[r[j]] == "" && !doneset[r[j]]) { | |
821 | break | |
822 | } | |
823 | if (j<=nreqs) { | |
824 | finished = 0 | |
825 | continue # try a different setting | |
826 | } | |
827 | } | |
828 | ||
829 | # All the requirements have been processed, output | |
830 | # this setting. | |
831 | if (deb) print "setting", i | |
832 | deflt = defaults[i] | |
833 | # Remove any spurious trailing spaces | |
834 | sub(/ *$/,"",deflt) | |
835 | # A leading @ means leave it unquoted so the preprocessor | |
836 | # can substitute the build time value | |
837 | if (deflt ~ /^ @/) | |
838 | deflt = " " subs substr(deflt, 3) sube | |
839 | print "" >out | |
840 | print "/* setting: ", i >out | |
841 | print " * requires:" setting[i] >out | |
842 | print " * default: ", defaults[i] deflt, "*/" >out | |
843 | for (j=1; j<=nreqs; ++j) { | |
844 | if (option[r[j]] != "") | |
845 | print "#ifndef PNG_" r[j] "_SUPPORTED" >out | |
846 | else | |
847 | print "#ifndef PNG_" r[j] >out | |
848 | print error, i, "requires", r[j] end >out | |
849 | print "# endif" >out | |
850 | } | |
851 | # The precedence is: | |
852 | # | |
853 | # 1) External definition; trumps: | |
854 | # 2) Option 'sets' value; trumps: | |
855 | # 3) Setting 'default' | |
856 | # | |
857 | print "#ifdef PNG_" i >out | |
858 | # PNG_<i> is defined, so substitute the value: | |
859 | print def i, subs "PNG_" i sube end >out | |
860 | print "#else /* use default */" >out | |
861 | print "# ifdef PNG_set_" i >out | |
862 | # Value from an option 'sets' argument | |
863 | print def i, subs "PNG_set_" i sube end >out | |
864 | # This is so that subsequent tests on the setting work: | |
865 | print "# define PNG_" i, "1" >out | |
866 | if (defaults[i] != "") { | |
867 | print "# else /*default*/" >out | |
868 | print def i deflt end >out | |
869 | print "# define PNG_" i, "1" >out | |
870 | } | |
871 | print "# endif /* defaults */" >out | |
872 | print "#endif /* setting", i, "*/" >out | |
873 | ||
874 | doneset[i] = 1 | |
875 | ++movement | |
876 | } | |
877 | ||
878 | if (!finished && !movement) { | |
879 | print "setting: loop or missing setting in 'requires', cannot process:" | |
880 | for (i in setting) if (!doneset[i]) { | |
881 | print " setting", i, "requires" setting[i] | |
882 | } | |
883 | exit 1 | |
884 | } | |
885 | } | |
886 | print "PNG_DFN_END_SORT" >out | |
887 | print comment, "end of settings", cend >out | |
888 | ||
9c0d9ce3 DS |
889 | # Regular end - everything looks ok |
890 | if (protect != "") { | |
fff5f7d5 | 891 | print start "#endif", "/*", protect, "*/" end >out |
9c0d9ce3 DS |
892 | } |
893 | } |