Dear all,
Having read and thought about Jim and Nick's comments, how about this as
a modified proposal? I've added more detail and put some notes at the end.
I haven't always given credit for suggestions but have often incorporated
them silently.
William
------------------------------------------------------------------------
1. Macro substitution library
-----------------------------
This library could be used directly by applications which need to support
macro substitution. It will be implemented on all platforms.
1.1 Core library
----------------
The core library provides a minimal set of core operations. Some utility
routines, described later, use core routines to provide a more convenient
interface for some purposes.
a) long macOpen ( MAC_HANDLE *handle );
Creates a new macro substitution context and returns an opaque handle to
that context. An application can, if it desires, have several active
contexts, although most will not.
b) long macIoctl( MAC_HANDLE handle, char *name, void *value );
Provides control over various "tuning" parameters. An initial list (which
can grow) might be:
name default value
---- -------------
errRoutine errPrintf ?
subsChars "$()"
verbose TRUE
c) long macRead ( MAC_HANDLE handle, char *name, long maxlen, char *value );
Returns up to maxlen characters of the value of macro "name". Will always
be zero-terminated. If value had to be truncated, function return will be
1 (if not, it will be 0).
If the value itself contains a macro reference then the reference will be
expanded recursively. This expansion will detect a direct or indirect self
reference.
Any attempt to translate an undefined macro will leave the macro reference
unchanged and will return -1 as the function value
d) long macWrite( MAC_HANDLE handle, char *name, char *value );
Sets the value of the macro "name". If "value" is NULL, undefines "name"
(it's not an error if "name" was already undefined). Macros referenced
by "value" need not be defined at this point (like the default GNU make
behavior).
Should there be control (as GNU make has via the "=" or ":=" operator)
over whether macros should be expanded recursively or simply? If so there
should be a flags argument to macWrite().
e) long macClose( MAC_HANDLE handle );
Marks a handle invalid, and frees all storage associated with it.
f) long macPush( MAC_HANDLE handle );
Marks the start of a new scoping level such that all definitions made up
until the next macPop() call will be lost on macPop() and those current
at macPush() will be re-instated.
May not be implemented first time round.
g) long macPop( MAC_HANDLE handle );
See above.
h) Error handling
Let's assume that these routines conform to 0 (=OK) for success, -1 (=ERROR)
for failure, and small positive values for extra info.
Let's also assume that errors are reported using an errPrintf()-compatible
routine (or printf()?).
A "verbose" variable will control error reporting.
1.2 Utility library
-------------------
These are convenience functions.
a) macConvert( char *defns, char **pairs[] );
This takes a set of macro definitions in "a=xxx,b=yyy" format and converts
them into an array of pointers to character strings which are, in order,
"first name", "first value", "second name", "second value" etc. The array
is terminated with two NULL pointers and all storage is allocated contig-
uously so that it can be freed with a single call to free().
This routine is independent of any handle and provides a generally useful
service which may be used elsewhere. Any macro references in values are
not expanded at this point since the referenced macros may be defined or
redefined before the macro actually has to be translated.
a) long macDefine( MAC_HANDLE handle, char *pairs[] );
This takes an array of pairs as defined above and installs them as
definitions by calling macWrite(). The pairs array is terminated by
a NULL pointer.
If macWrite() has a flags field to control recursive expansion, so also
should macDefine().
g) long macSubst( MAC_HANDLE handle, char *src, long maxlen, char *dest );
This operates on a string which may contain macro references. It parses
the string looking for macro references and passes them to macRead() for
translation. It returns the expanded string in the supplied argument.
Any undefined macros will be left unexpanded. The function value will
be 0 for success, -1 if any translations failed and 1 if successful
except that there were two many characters for the supplied string.
h) long macReport( MAC_HANDLE handle );
This dumps details of current definitions to standard output. It's purely
for debugging purposes.
2. Macro substitution tool
--------------------------
A "macsub" (or "mactool"?) application will be written which would use the
above library and use a command like:
macsub a=b,c=d e=f -Iaaa -Ibbb
to parse a file like:
# comment
%include filename
%xxx = ppp
%yyy = $(xxx)
<arbitrary text containing macro references>
There would also be options to read and write specified files, control the
comment character, control the command prefix, change the macro substitution
characters etc.
Syntax would be a loose subset of corresponding GNU make syntax (see later
discussion of whether we should take our lead from shells or makes).
The use of a command prefix should be optional and perhaps it should default
to an empty string. However there will be cases where the file in question
has a syntax over which we have no control, which may include assignments,
"set" commands, "define" commands etc. This is why I proposed a command
prefix, which might be an arbitrary string such as "macro " or might just
be "%" as in the above example.
The tool can also support the following syntax (or perhaps some equivalent
syntax which will sit more easily inside a file that may have a completely
different syntax from it?):
file gizmo_database.db
{
i1{ pre=part1,parm=big, alarm_limit=20 }
i2{ pre=part2,parm=medium,alarm_limit=30 }
}
as an implied multiple include of "gizmo_database.db" with the specified
macro definitions for each include (here's a good application for macPush()
and macPop() actually). Can someone enlighten me as to the significance of the
"i1" and "i2" bits? Are they needed?
3. Notes
--------
1. I did not add a "subs" argument to macOpen() since this seemed to me rather
like adding the first line to be written to a file to the fopen() call. I
felt that macWrite() should be the only core routine that should be able to
define a macro... but feel free to disagree with this point of view.
2. I added the requirement that the pairs array be NULL-terminated. An alter-
native would be to have a count argument to macDefine() (which Jim called
macModify()).
3. I swapped the parameters to macConvert() to be input followed by output.
I also fixed my "maxlen" parameters similarly. An alternative to the use
of maxlen would be to allocate the returned string and use a char **.
4. Jim said:
> I feel that one of the important uses for this library is dbLoadRecords()
> which runs on the IOC. This tools should not be openning any more than one
> file. The substitions are required to be on the vxWorks command
> line as they are today and nothing must be embedded in the ".db", except
> the $(var) variables. In other words, I feel that in many instances that
> embedding substitution information at the top of files is not appropriate.
Agreed. My best current example for embedding information would be where
you want to generate a master .alhConfig file which wants to include the
same file n times, one for each IOC and wants to set the ioc macro approp-
riately each time (of course, we don't have many IOCs...). Of course, this
is also solved by the "file" proposal.
5. Jim also said:
> 1) Allow syntax such as "A=$(B),B=$(C),C=3"
> or "pv_name=$(subsystem)$(sector)$(crate),subsystem=RF,sector=5,crate=7"
>
> 2) Dissallow and print an error message for "A=$(B),B=$(C),C=$(A)".
>
> 3) Allow "A=\$(B)" to assign $(B) to A instead of the value of B.
>
> 4) Allow A=\,,B=\",C="this,is\" a test",C='this,\' is a test'
> to perform as expected.
>
> Items 3 and 4 are checked by what I called macConvert(), 1 and 2 are
> probably checked by the core library.
...and Nick said:
> (Pedantic point) should we have literal `$' represented by \$ (shell
> syntax) or $$ (make syntax)?
>
> > 4) Allow A=\,,B=\",C="this,is\" a test",C='this,\' is a test'
> > to perform as expected.
>
> This also highlights differences between shell and make syntaxes.
>
> I would like to add a point (which works in make, but not in csh):
>
> 5) A=$(B$(C)) should work...
>
> On balance (and at the moment - my feelings may change) I would lean
> towards a make syntax rather than a shell syntax.
I also favor going with make syntax rather than shell syntax. I would
also imagine that supporting $(fred:%=%.o) type pattern operators might
be useful in the future, and these can be modeled on make too. Similarly
other built-in macros.
- Navigate by Date:
- Prev:
Re: macro substitution Nick Rees
- Next:
EPICS support for Precision Micro Control products? Paul Stomski
- Index:
1994
1995
<1996>
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
Re: macro substitution Nick Rees
- Next:
Re: macro substitution William Lupton
- Index:
1994
1995
<1996>
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
|