home *** CD-ROM | disk | FTP | other *** search
- /*
- * config - used to set up option files for programs with to many conditional
- * compilation defines.
- *
- * copyright (c) 1989, Mike Meyer
- *
- * Usage: config <configfile>
- * .h files are generated in /<configfile> setting the options
- * as specified in <configfile>. But first, config.options is
- * read to find out what options you can & can't set for the
- * program being configed. See config.doc and make-config.doc
- * for details.
- */
-
- /*
- * There are three magic globals - options, required and actions. required
- * keeps track of the options that you _have_ to specify, and whether
- * it's seen them or not. options keeps track of the options you can
- * specify, and the current value. The syntax for both is the
- * same: X.<name> holds the value of option <name>, or whether
- * required.<name> has been seen or not. Since there's no easy
- * way to walk through all the members on a stem (yet), we also
- * have to keep track of the names. They are stored in X.1 through
- * X.N, where there are currently N names in X. Just to keep everything
- * in one place, N is kept in X.0. Actions keeps track of any actions
- * that have been specified. Since they have no names, the actions
- * themselves are tracked in actions.N, with actions.0 holding the
- * number of actions specified.
- */
-
- /*
- * Main routine - initialize the globals, read in the base config file,
- * read in and apply the options the user selects, then write the
- * appropriate include files out.
- */
-
- arg system
- undefined = '/\/\.* ' /* value for options not in .options files */
- namerequired = '/\...* ' /* value for required options not yet used */
- options. = undefined /* none are defined yet */
- required. = undefined /* Haven't seen it yet */
-
- options.0 = 0 /* No options yet */
- required.0 = 0 /* and no required options */
- actions.0 = 0 /* and no actions */
-
- if system = "" then do
- say "usage: config CONFIGFILE"
- exit 10
- end
-
- if ~open(basefile, 'config.options', 'Read') then do
- say "Can't find config base"
- exit 20
- end
- call buildoptions basefile
- call close basefile
-
- if ~open(configfile, system, 'Read') then do
- say "Can't find config file" system
- exit 20
- end
- call applyoptions configfile
- call close configfile
-
- call dumpoptions system
- exit 0
-
- /*
- * buildoptions - given an input file, it builds the option & required data
- * structure for that file.
- */
- buildoptions: procedure expose options. required. actions. namerequired
- arg optfile
-
- do forever
- call readline optfile
- if eof(optfile) & name = "" then leave
- if name == 'action' then do
- new = getnextaction()
- actions.new = value
- end
- else if value ~= 'required' then do
- new = getnextoption()
- options.new = name
- if value = 'option' then value = 'off'
- options.name = value
- end
- else do
- new = getnextrequired()
- required.new = name
- required.name = namerequired
- end
- end
- return
-
- /*
- * applyoptions - given a file, we apply each option line to the existing
- * database.
- */
- applyoptions: procedure expose options. required. actions. undefined namerequired
- arg optfile
-
- requireddone = 0
- do forever
- call readline optfile
- if eof(optfile) & name = "" then leave
- if name = 'option' then do
- name = value
- value = 'on'
- end
- if options.name ~= undefined then do
- if ~requireddone then do
- requireddone = checkrequire()
- if ~requireddone then do
- say "Option" name "specified before required options"
- exit 10
- end
- end
- options.name = value
- end
- else if required.name ~= undefined then do
- if required.name ~= namerequired then do
- say 'Required' name 'seen twice.'
- exit 10
- end
- required.name = value
- if ~open(reqfile, value || '.options', 'Read') then do
- say "Invalid value:" value "for option:" name
- exit 20
- end
- call buildoptions reqfile
- call close reqfile
- end
- else say 'Unkown option' name 'ignored.'
- end
- return
-
- /*
- * dumpoptions - output the include files as specified by this config file.
- */
- dumpoptions: procedure expose options. required. actions.
- arg conf
-
-
- if ~exists('/' || conf) then 'makedir /' || conf
-
- do i=1 to options.0
- name = options.i
- if options.name = 'off' then out = ""
- else if options.name = 'on' then out = "#define" upper(name)
- else out = "#define" upper(name) options.name
- call dumpinc conf, name, out
- end
-
- do i=1 to required.0
- name = required.i
- out = "#define" upper(required.name)
- call dumpinc conf, name, out
- end
-
- 'cd /' || conf
- do i=1 to actions.0
- actions.i
- end
- return
-
- /*
- * readline - read a line in, and put the appropriate parts in the globals
- * 'name' and 'value'.
- */
- readline: procedure expose name value
- arg file
-
- do forever
- line = translate(readln(file), " ", " ") /* tabs */
- parse var line name value "# "
- if name ~= "#" & name ~= "" then leave
- if eof(file) then do
- name = ""
- return
- end
- end
- value = strip(value)
- return
- /*
- * getnextoption - returns the number for the next free option.
- */
- getnextoption: procedure expose options.0
-
- options.0 = options.0 + 1
- return options.0
-
- /*
- * getnextrequired - returns the number for the next free required.
- */
- getnextrequired: procedure expose required.0
-
- required.0 = required.0 + 1
- return required.0
-
- /*
- * getnextaction - returns the number for the next free action.
- */
- getnextaction: procedure expose actions.0
-
- actions.0 = actions.0 + 1
- return actions.0
-
- /*
- * checkrequire - return 1 if all required options have been seen, 0
- * otherwise.
- */
- checkrequire: procedure expose required. namerequired
-
- do i=1 to required.0
- name = required.i
- if required.name = namerequired then return 0
- end
- return 1
-
- /*
- * dumpinc - creates a new include file, but only if it's different from
- * the current one.
- */
- dumpinc: procedure
- parse arg dir, file, line
-
- name = '/' || dir || '/' || file || ".h"
- if open(incfile, name, 'Read') then do
- old = readln(incfile)
- call close incfile
- if old = line then return
- end
- if ~open(incfile, name, 'Write') then do
- say "Can't create include file" name
- return
- end
- call writeln incfile, line
- call close incfile
- return
-