README file for etc/macLib directory
------------------------------------

This directory contains all files necessary to build and test the
EPICS macro library macLib. The specification for this library
appears later in this file.

Files in this release are:

-rw-r--r--  1 wlupton       141 Sep 22  1995 Makefile
-rw-r--r--  1 wlupton       522 Jun 23 20:42 Makefile.Unix
-rw-r--r--  1 wlupton       473 Jun 23 20:43 Makefile.Vx

-rw-r--r--  1 wlupton      5052 Jun 25 23:17 NOTES
-rw-r--r--  1 wlupton     10429 Jun 25 23:34 README

-rw-r--r--  1 wlupton     20158 Jun 25 23:40 macCore.c
-rw-r--r--  1 wlupton      5056 Jun 25 21:33 macLib.h
-rw-r--r--  1 wlupton      2050 Jun 25 23:18 macTest.c
-rw-r--r--  1 wlupton      7307 Jun 25 23:13 macUtil.c

25-Jun-96, William Lupton (wlupton@keck.hawaii.edu), CVS tag: macLib-1-0
------------------------------------------------------------------------

first release

------------------------------------------------------------------------

This is the original final specification for the EPICS macro library:

From wlupton Mon Feb 19 14:10:08 1996
To: tech-talk@aps.anl.gov
Subject: Re: macro substitution
Content-Length: 9716
X-Lines: 251
Status: RO

Dear all,

  Here's yet another proposal for the macro library. There has been some
private discussion between myself, Jim and Marty, and I hope that this
is nearly final (or final enough to be implemented). After all the
discussion, the actual implementation is going to be a breeze!

  The biggest changes are a move a way from the "filesystem-like"
routine names and a reduction in the emphasis placed on the standalone
tool.

  I'm afraid there are still a few minor issues to be resolved but
probably nothing that can't wait for an alpha release.

  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 basic operations. Some
utility routines, described later, use core routines to provide a more
convenient interface for some purposes.

a) long macCreateHandle( MAC_HANDLE **handle, char *pairs[] );
   void macSuppressWarning(MAC_HANDLE *handle,int falseTrue);

   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.

   If desired, an initial set of macro definitions may be loaded
   ("pairs" is set to NULL to avoid this). The definitions are in the
   "standard" pairs format, as described under macParseDefns().

   Note that MAC_HANDLE is a typedef for the context structure. The
   opaque handle is of type "MAC_HANDLE *", which is a pointer to the
   context structure. The memory for this context is allocated by this
   routine.

   macSuppressWarning can be called to suppress the marning message
   when macExpandString cant expand a macro. A non zero value will
   suppress the messages.


b) long macGetXxxx( MAC_HANDLE *handle, <Xxxx-specific> );
   long macPutXxxx( MAC_HANDLE *handle, <Xxxx-specific> );

   These routines replace the earlier-proposed macIoctl(). "Xxxx" is the
   name of the attribute in question. An initial list (which can grow)
   might be:

   Attribute			default value
   ---------			-------------
   ErrRoutine			errPrintf
   Verbose			TRUE

   StartChars			"$"
   LeftChars			"{("
   RightChars			"})"
   SeparChars			","
   AssignChars			"="

   A NULL handle can be used to set or get global values (used by
   macParseDefns()).

c) long macGetValue ( MAC_HANDLE *handle, char *name,
					  char *value, long maxlen );

   Returns up to maxlen characters of the value of macro "name". "value"
   will be zero-terminated if the length of the value is less than
   maxlen. The function value will be the number of characters copied to
   "value" (see below for behavior if the macro is undefined). If maxlen
   is zero, no characters will be copied to "value" (which can be NULL)
   and the call can be used to check whether the macro is defined. Note
   that truncation of the value is therefore not reported. Is this a
   problem?

   If the macro is undefined, the macro reference will be returned in
   the value string (if permitted by maxlen) and the function value will
   be _minus_ the number of characters copied. Note that treatment of
   maxlen is intended to be consistent with what people are used to with
   strncpy().

   "name" can either be just the macro name or can have the syntax of a
   macro reference (e.g. it can be "fred" or "$(fred)"). In the latter
   case, any characters after the logical end of the macro reference
   will be ignored (this is to ease expansion of a string which may
   contain many macro references), but no means of returning the number
   of characters scanned in "name" is provided. [It may prove expedient
   to make macGetValue() simpler and provide a separate routine with
   more parameters which returns this information.]

   If the name or value contains a macro reference then the reference
   will be expanded recursively. This expansion will detect a direct or
   indirect self reference.

   Macro references begin with a "$" immediately followed by either a
   "(" or a "{" character. The reference is terminated by the matching
   ")" or "}" character. These characters can be changed via
   macPut{Start,Left,Right}Chars() above.

d) long macPutValue( 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.

   The function value is the length of the value.

e) long macDeleteHandle( MAC_HANDLE *handle );

   Marks a handle invalid, and frees all storage associated with it.

   Note that this does not free any strings into which macro values have
   been returned. Macro values are always returned into strings which
   were pre-allocated by the caller.

f) long macPushScope( MAC_HANDLE *handle );

   Marks the start of a new scoping level such that all definitions made
   up until the next macPopScope() call will be lost on macPopScope()
   and those current at macPushScope() will be re-instated.

   May not be implemented first time round.

g) long macPopScope( MAC_HANDLE *handle );

   See above.

h) Error handling

   These routines conform to 0 (=OK) for success, -1 (=ERROR) for
   failure, and small positive values for extra info. I contravened this
   for macGetValue() and macExpandString() because I felt that it was
   worth returning information both on success / failure and on value
   length.

   Errors are reported using an errPrintf()-compatible routine.

   A "verbose" variable will control error reporting.


1.2 Utility library
-------------------

These are convenience functions. If other useful functions emerge during
implementation, the list may grow.

a) macParseDefns( MAC_HANDLE  *handle, 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 contiguously 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.

   Shell-style escapes and quotes are supported, as are things like
   "A=B,B=$(C$(A)),CA=CA,CB=CB" (sets B to "CB"). White space is
   significant within values but ignored elsewhere (i.e. surrounding "="
   and "," characters).

   Probably noone will ever want to, but the special meanings of "$",
   "{", "}", "(", ")", "=" and "," can all be changed via macPutXxxx()
   calls.  This routine does not have a handle argument, so they must be
   changed globally for it to use the new definitions. Should it have a
   handle argument? This makes it more of a pain to use but guarantees
   that there will be no conflicts. I think it should really.

   The function value is the number of definitions encountered, or -1 if
   the supplied string is invalid.

b) long macInstallMacros( MAC_HANDLE *handle, char *pairs[] );

   This takes an array of pairs as defined above and installs them as
   definitions by calling macPutValue(). The pairs array is terminated
   by a NULL pointer.

   The function value is the number of macros defined.

c) long macExpandString( MAC_HANDLE *handle, char *src,
					     char *dest, long maxlen );

   This operates on a string which may contain macro references. It
   parses the string looking for such references and passes them to
   macGetValue() for translation. It returns the expanded string in the
   supplied argument.

   The function value is similar to that of macGetValue(). Its absolute
   value is the number of characters copied. If negative, at least one
   undefined macro has been left unexpanded.

d) long macReportMacros( MAC_HANDLE *handle );

   This reports details of current definitions to standard output (or
   standard error?). It's purely for debugging purposes.


2. Macro substitution tool
--------------------------

This section is hardly changed from the previous version. The library will
be implemented first.

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 will also be options to read and write specified files, control the
comment character, control the command prefix, change the macro substitution
characters etc.

Syntax will be a loose subset of corresponding shell syntax.

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
{
    instance1{ pre=part1,parm=big,   alarm_limit=20 }
    instance2{ 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
macPushScope() and macPopScope() actually).
