Home | History | Annotate | Download | only in scripts
      1 #!/bin/awk -f
      2 # scripts/options.awk - library build configuration control
      3 #
      4 # last changed in libpng version 1.6.11 - June 5, 2014
      5 #
      6 # Copyright (c) 1998-2014 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{
     33    out=""                       # intermediate, preprocessed, file
     34    pre=-1                       # preprocess (first line)
     35    version="libpng version unknown" # version information
     36    version_file=""              # where to find the version
     37    err=0                        # in-line exit sets this
     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
     54    cend="*/" end                # Comment end
     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'
     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
     67    # for each option:
     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
     73    sets[""] = ""      # settings set by each option
     74    setval[""] = ""    # value to set (indexed: 'option sets[option]')
     75    # for each setting:
     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:
     86 out == "" {
     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 
    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 
    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.
    137 $0 ~ /^[ 	]*version[ 	]*=/{
    138    sub(/^[  ]*version[  ]*=[  ]*/, "")
    139    version = $0
    140    next
    141 }
    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 = ""
    207       print comment $0, cend >out
    208    } else
    209       print start end >out
    210    next
    211 }
    212 
    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 
    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 
    244 # option NAME ( (requires|enables|if) NAME* | on | off | disabled |
    245 #                sets SETTING VALUE+ )*
    246 #     
    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{
    261    opt = $2
    262    sub(/,$/,"",opt)
    263    onoff = option[opt]  # records current (and the default is "", enabled)
    264    key = ""
    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 continuation 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" || val =="enabled") {
    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
    305                }
    306             }
    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 ~ /,$/)
    327 
    328    if (i > NF) {
    329       # Set the option, defaulting to 'enabled'
    330       if (onoff == "") onoff = "enabled"
    331       option[opt] = onoff
    332       next
    333    }
    334    # Else fall through to the error handler
    335 }
    336 
    337 # chunk NAME [requires OPT] [enables LIST] [on|off|disabled]
    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]
    342 #   option READ_NAME enables NAME LIST
    343 #   [option READ_NAME off]
    344 #   option WRITE_NAME requires WRITE_ANCILLARY_CHUNKS [WRITE_OPT]
    345 #   option WRITE_NAME enables NAME LIST
    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.
    351    opt = $2
    352    sub(/,$/,"",opt)
    353    onoff = ""
    354    reqread = ""
    355    reqwrite = ""
    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 continuation 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 
    375       # read the keywords/additional OPTS
    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) {
    381                if (onoff == "")
    382                   onoff = val
    383                else
    384                   break # on/off conflict
    385             }
    386             req = 0
    387          } else if (val == "requires")
    388             req = 1
    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
    397             break # bad line: handled below
    398       }
    399 
    400       istart = 1
    401    } while (i > NF && $0 ~ /,$/)
    402 
    403    if (i > NF) {
    404       # Output new 'option' lines to the intermediate file (out)
    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
    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 unrecognized 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 
    537    # Do the options first (allowing options to set settings).  The dependency
    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' to 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 
    629    # Sort options:
    630    print "PNG_DFN_START_SORT 2" >out
    631 
    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
    669          print " *   if:        " iffs[i] >out
    670          print " *   enabled-by:" enabledby[i] >out
    671          print " *   sets:      " sets[i], "*/" >out
    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          have_ifs = 0
    691          nreqs = split(iffs[i], r)
    692          print "#undef PNG_no_if" >out
    693          if (nreqs > 0) {
    694             have_ifs = 1
    695             print "/* if" iffs[i], "*/" >out
    696             print "#define PNG_no_if 1" >out
    697             for (j=1; j<=nreqs; ++j) {
    698                print "#ifdef PNG_" r[j] "_SUPPORTED" >out
    699                print "#   undef PNG_no_if /*" r[j] "*/" >out
    700                print "#endif" >out
    701             }
    702             print "#ifdef PNG_no_if /*missing if*/" >out
    703             print "#   undef PNG_on" >out
    704             # There is no checking above for this, because we
    705             # don't know which 'if' to choose, so whine about
    706             # it here:
    707             if (option[i] == "on") {
    708                print error, i, "needs one of:", iffs[i] end >out
    709             }
    710             print "#endif" >out
    711          }
    712 
    713          print "#ifdef PNG_on /*requires, if*/" >out
    714          # enables
    715          print "#   undef PNG_not_enabled" >out
    716          print "#   define PNG_not_enabled 1" >out
    717          print "   /* enabled by" enabledby[i], "*/" >out
    718          nreqs = split(enabledby[i], r)
    719          for (j=1; j<=nreqs; ++j) {
    720             print "#ifdef PNG_" r[j] "_SUPPORTED" >out
    721             print "#   undef PNG_not_enabled /*" r[j] "*/" >out
    722             # Oops, probably not intended (should be factored
    723             # out by the checks above).
    724             if (option[i] == "off") {
    725                print error, i, "enabled by:", r[j] end >out
    726             }
    727             print "#endif" >out
    728          }
    729 
    730          print "#   ifndef PNG_" i "_SUPPORTED /*!command line*/" >out
    731          print "#    ifdef PNG_not_enabled /*!enabled*/" >out
    732          # 'have_ifs' here means that everything = "off" still allows an 'if' on
    733          # an otherwise enabled option to turn it on; otherwise the 'if'
    734          # handling is effectively disabled by 'everything = off'
    735          if (option[i] == "off" || option[i] == "disabled" && everything != "on" || option[i] == "enabled" && everything == "off" && !have_ifs) {
    736             print "#      undef PNG_on /*default off*/" >out
    737          } else {
    738             print "#      ifdef PNG_NO_" i >out
    739             print "#       undef PNG_on /*turned off*/" >out
    740             print "#      endif" >out
    741             print "#      ifdef PNG_NO_" i "_SUPPORTED" >out
    742             print "#       undef PNG_on /*turned off*/" >out
    743             print "#      endif" >out
    744          }
    745          print "#    endif /*!enabled*/" >out
    746          print "#    ifdef PNG_on" >out
    747          # The _SUPPORTED macro must be defined so that dependent
    748          # options output later work.
    749          print "#      define PNG_" i "_SUPPORTED" >out
    750          print "#    endif" >out
    751          print "#   endif /*!command line*/" >out
    752          # If PNG_on is still set the option should be defined in
    753          # pnglibconf.h
    754          print "#   ifdef PNG_on" >out
    755          if (i ~ /^fail_/) {
    756             print error, i, "is on: enabled by:" iffs[i] enabledby[i] ", requires" requires[i] end >out
    757          } else if (i !~ /^ok_/) {
    758             print def i sup >out
    759             # Supported option, set required settings
    760             nreqs = split(sets[i], r)
    761             for (j=1; j<=nreqs; ++j) {
    762                print "#    ifdef PNG_set_" r[j] >out
    763                # Some other option has already set a value:
    764                print error, i, "sets", r[j] ": duplicate setting" end >out
    765                print error, "   previous value: " end "PNG_set_" r[j] >out
    766                print "#    else" >out
    767                # Else set the default: note that this won't accept arbitrary
    768                # values, the setval string must be acceptable to all the C
    769                # compilers we use.  That means it must be VERY simple; a number,
    770                # a name or a string.
    771                print "#     define PNG_set_" r[j], setval[i " " r[j]] >out
    772                print "#    endif" >out
    773             }
    774          }
    775          print "#   endif /* definition */" >out
    776          print "#endif /*requires, if*/" >out
    777          if (logunsupported || i ~ /^ok_/) {
    778             print "#ifndef  PNG_on" >out
    779             if (logunsupported) {
    780                print und i une >out
    781             }
    782             if (i ~ /^ok_/) {
    783                print error, i, "not enabled: requires:" requires[i] ", enabled by:" iffs[i] enabledby[i] end >out
    784             }
    785             print "#endif" >out
    786          }
    787 
    788          done[i] = 1
    789          ++movement
    790       }
    791 
    792       if (!finished && !movement) {
    793          print "option: loop or missing option in dependency tree, cannot process:"
    794          for (i in option) if (!done[i]) {
    795             print "  option", i, "depends on" tree[i], "needs:"
    796             nreqs = split(tree[i], r)
    797             if (nreqs > 0) for (j=1; j<=nreqs; ++j) if (!done[r[j]]) {
    798                print "   " r[j]
    799             }
    800          }
    801          exit 1
    802       }
    803    }
    804    print "PNG_DFN_END_SORT" >out
    805    print comment, "end of options", cend >out
    806 
    807    # Do the 'setting' values second, the algorithm the standard
    808    # tree walk (O(1)) done in an O(2) while/for loop; interations
    809    # settings x depth, outputing the deepest required macros
    810    # first.
    811    print "" >out
    812    print "/* SETTINGS */" >out
    813    print comment, "settings", cend >out
    814    # Sort (in dfn.awk) on field 2, the setting name
    815    print "PNG_DFN_START_SORT 2" >out
    816    finished = 0
    817    while (!finished) {
    818       finished = 1
    819       movement = 0 # done nothing
    820       for (i in setting) if (!doneset[i]) {
    821          nreqs = split(setting[i], r)
    822          if (nreqs > 0) {
    823             # By default assume the requires values are options, but if there
    824             # is no option with that name check for a setting
    825             for (j=1; j<=nreqs; ++j) if (option[r[j]] == "" && !doneset[r[j]]) {
    826                break
    827             }
    828             if (j<=nreqs) {
    829                finished = 0
    830                continue # try a different setting
    831             }
    832          }
    833 
    834          # All the requirements have been processed, output
    835          # this setting.
    836          if (deb) print "setting", i
    837          deflt = defaults[i]
    838          # Remove any spurious trailing spaces
    839          sub(/ *$/,"",deflt)
    840          # A leading @ means leave it unquoted so the preprocessor
    841          # can substitute the build time value
    842          if (deflt ~ /^ @/)
    843             deflt = " " subs substr(deflt, 3) sube
    844          print "" >out
    845          print "/* setting: ", i >out
    846          print " *   requires:" setting[i] >out
    847          print " *   default: ", defaults[i] deflt, "*/" >out
    848          for (j=1; j<=nreqs; ++j) {
    849             if (option[r[j]] != "")
    850                print "#ifndef PNG_" r[j] "_SUPPORTED" >out
    851             else
    852                print "#ifndef PNG_" r[j] >out
    853             print error, i, "requires", r[j] end >out
    854             print "# endif" >out
    855          }
    856          # The precedence is:
    857          #
    858          #  1) External definition; trumps:
    859          #  2) Option 'sets' value; trumps:
    860          #  3) Setting 'default'
    861          #
    862          print "#ifdef PNG_" i >out
    863          # PNG_<i> is defined, so substitute the value:
    864          print def i, subs "PNG_" i sube end >out
    865          print "#else /* use default */" >out
    866          print "# ifdef PNG_set_" i >out
    867          # Value from an option 'sets' argument
    868          print def i, subs "PNG_set_" i sube end >out
    869          # This is so that subsequent tests on the setting work:
    870          print "#  define PNG_" i, "1" >out
    871          if (defaults[i] != "") {
    872             print "# else /*default*/" >out
    873             print def i deflt end >out
    874             print "#  define PNG_" i, "1" >out
    875          }
    876          print "# endif /* defaults */" >out
    877          print "#endif /* setting", i, "*/" >out
    878 
    879          doneset[i] = 1
    880          ++movement
    881       }
    882 
    883       if (!finished && !movement) {
    884          print "setting: loop or missing setting in 'requires', cannot process:"
    885          for (i in setting) if (!doneset[i]) {
    886             print "  setting", i, "requires" setting[i]
    887          }
    888          exit 1
    889       }
    890    }
    891    print "PNG_DFN_END_SORT" >out
    892    print comment, "end of settings", cend >out
    893 
    894    # Regular end - everything looks ok
    895    if (protect != "") {
    896       print start "#endif", "/*", protect, "*/" end >out
    897    }
    898 }
    899