home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
cidsam.zip
/
API.TXT
next >
Wrap
Text File
|
1993-06-28
|
29KB
|
724 lines
SAMPLE RESPONSE FILE CODE
Introduction
The sample code in this package shows how CID response files can be
read and parsed, and how response file processing is used in a CID
installation program. The samples are organized like this:
o Low-level file and parsing APIs. These routines handle the
basic file and parsing services needed to use response files.
They can be used to build higher-level services.
These routines make only minimal assumptions about the nature
of the response files. The routines can be modified for another
set of assumptions, but for this example the assumptions are
- Blank lines and lines in which the first non-blank
character is '*' or ';' (asterisk or semicolon) are
comment lines. Their contents are ignored.
- Response file data lines consist of a _keyword_ and a
_value_, seperated by an equal ('=') sign.
The _keyword_ begins with the first non-blank character
in the line and ends with the last non-blank character
before the equal sign. Blank characters and equal signs
are not valid in a keyword.
The _value_ begins with the first non-blank character to
the right of the equal sign and ends with the last non-blank
character in the line.
There can be only one keyword/value pair per line.
- _Values_ can be of two types: _strings_ and _lists_.
A _string_ is any character sequence to the right of the
equal sign. The only illegal string is a single left
parenthesis '('.
A _list_ is a sequence of keyword/value pairs. The start
of a list is indicated by a single left parenthesis to the
right of the equal sign. The end of a list is indicated by
a right parenthesis on a line by itself. The following is
an example of a keyword with a _list_ value:
MyList = (
ListValue.1 = orange
ListValue.2 = red
MyImbeddedList = (
ImbeddedListValue.1 = Cabbage
ImbeddedListValue.2 = Sprouts
ImneddedListValue.3 = Kale
)
ListValue.3 = green
)
These low-level APIs are discussed in detail under "RFIO Routines" below.
[Introduction] 1
o Higher-level APIs for processing response files. These routines use
the low-level APIs to provide a simple interface for application
programs. They make further assumptions. Again, the routines can
be modified to change these assumptions.
- The keyword 'include' (in any case) has special meaning.
When it is found in a response file, the value (a _string_)
is the name of another response file that is to be
immediately opened and processed. If the response file
A.RSP contains the lines
keywordA1 = value1
keywordA2 = value2
include = B.RSP
keywordA3 = value3
and the response file B.RSP contains the lines
keywordB1 = XXX
keywordB2 = ZZZ
then the high-level APIs will process the response files
as if they were a single file containing
keywordA1 = value1
keywordA2 = value2
keywordA3 = value3
keywordB1 = XXX
keywordB2 = ZZZ
If a fully-qualified path is specified for the _value_,
then that file is used. If a relative path is specified,
it is searched for on
The current working directory
Each path in the current environment PATH variable
Each path in the current enviornment DPATH variable
- Errors are to be logged to a certain log file from a certain
message file. The error handling assumptions are discussed
in more detail under "Error Handling" below.
The high-level APIs are discussed in detail under "HLRFIO Routines"
below.
o Sample applications. Three complete programs that use the APIs
discussed above are provided. They are
- SAMPLE1. This is a very simple application that creates
a file to put Response File information into the process
environment.
- SAMPLE2. This is a more complicated example that enforces
some common Response File rules and deals with _list_ type
values.
- SAMPLE3. This example deals with Named Lists, a technique
that allows response file (as defined above) to handle
variable-length tables.
[Introduction] 2
o A complete CID installation program, written in REXX. This program is
based on working code, and can be used as a template for a CID
install program. Unlike the samples discussed above, however, it will
probably not run as-is on your workstation. It uses several programs
that are not included with this package of samples. For the most part,
you would need to write your own versions of these programs anyway.
Two of the programs are included in this package for reference. The
are
- GETBOOTD. This little program returns an integer that
represents the drive from which the workstation was last
booted.
- CHKLVL. This program checks the release level of programs
that record their release information in ibmlvl.ini.
o A make file.
[Introduction] 3
HLRFIO Routines
The high-level Response File APIs provide a simple interface to response files
that meet the assumptions listed above. Many response file programs need only
two of the routines -- RFOpen() and RFGetNextKeywordInFile(). The routines
are all in module HLRFIO.C (and HLRFIO.OBJ) and are collectively referred to
as the "HLRFIO routines."
The HLRFIO routines fall into three categories:
- File handling routines
RFOpen() opens a response file and readies it for processing.
RFClose() closes the response file. Normally it is not
necessary to call this routine.
- Response File parsing routines
RFGetNextKeyword() returns the next keyword/value pair.
RFGetNextKwdInList() returns the next keyword/value pair
from a _list_ type value.
- List handling routine
RFCopyList() makes a memory copy of a _list_ value.
To use any of the HLRFIO routines in your program, include the header file
hlrfio.h and link your program with HLRFIO.OBJ.
UINT RFOpen(char *pszFilename)
This routine opens the file pszFilename as a response file.
It returns 0 (RFH0) for success, 3 (RFHERR) for failure.
Use this routine to open the first or 'main' response file.
Subsequent opens of included response file are done under the
covers and do not require your any action by your program.
Example:
rc = RFOpen("My.rsp");
if (rc == RFH0)
<proceed>
UINT RFClose(void)
This function closes a response file. RFClose is not required
unless the caller wants to free resources (memory and file
handles) in use by rfio. A call to RFOpen automatically closes
down any previously open Response File, so there is no need to call
RFClose() between Response Files. This function always returns RFH0.
[HLRFIO Routines] 4
UINT RFGetNextKeyword(char **ppszKeyword, char **ppszValue,
UINT *puiType)
This function stores pointers to the next keyword and value, and
stores an indicator of the type of value (string or list) (RFHLIST
and RFHSTRING respectively).
Do not issue a free() against *ppxzKeyword or *ppszValue.
If you need a copy of the keyword and/or value, make one.
The values will be erased and the space they take up will be
freed on the next call to RFGetNextKeyword().
This function returns RF0 as long as everything is OK,
RFEOF when the last keyword and value have already been returned,
or RFERR when a fatal error has occured.
Example:
char *keyword, *value;
unsigned int type;
while (RFGetNextKeyword(&keyword, &value, &type) == RFH0)
<process the keyword/value pair>
UINT RFGetNextKwdInList(char **ppszStart, char **ppszKeyword,
char **ppszValue, UINT *puiType)
This functions parses out the keywords and values from inside
a _list_ value. The variable *ppszStart keeps track of where
you are within the list. Before the first call, set
*ppszStart to the address of the list; on subsequent calls,
the value will be automatically updated.
Otherwise, this call works like RFGetNextKeyword, returning
the next keyword, value and type. Like RFGetNextKeyword, it
returns RF0 as long as everything is OK, RFEOF when the last
keyword and value have already been returned, or RFERR when a
fatal error has occured.
Example:
char *keyword, *value;
char *listPosition, *listKeyword, *listValue;
char *listCopy;
unsigned int type, listType;
rc = RFGetNextKeyword(&keyword, &value, &type);
if (rc == RFH0)
if (type = RFHLIST)
{
<we want to make a copy of the value here: see below>
listPosition = listCopy;
while (RFGetNextKwdInList(&listPosition, &listKeyword,
&listValue, &listType);
< process the keyword/value pair from the list>
}
[HLRFIO Routines] 5
VOID *RFCopyList(void *from)
This routine makes a copy of the _list_ value pointed to by "from".
The copy is persistant. The memory it takes up can be released
by issuing a free() on the value returned from this function.
Take care that the "from" value is really a _list_ type value.
The routine makes a copy of everything from "from" to the next
occurance of two adjacent null characters.
The reason for having this routine is that _values_ returned from
RFGetNextKeyword() are not permanent. The memory they occupy is
freed on the next call to RFGetNextKeyword or RFGetNextKwdInList.
So if we want to manipulate the list, we need to make our own
private copy.
Example:
char *keyword, *value;
char *listPosition, *listKeyword, *listValue;
char *listCopy;
unsigned int type, listType;
rc = RFGetNextKeyword(&keyword, &value, &type);
if (rc == RFH0)
if (type = RFHLIST)
{
listCopy = RHCopyList(value); // Make private copy of list
listPosition = listCopy;
while (RFGetNextKwdInList(&listPosition, &listKeyword,
&listValue, &listType);
< process the keyword/value pair from the list>
free(listCopy); // Free space used for private copy
}
void *RFMergeLists(void *List1, void *List2)
This routine merges two _list_ type values into a single list.
The two lists passed to this routine should be persistant copies.
The resulting list is also persistant. It may be freed with a
free() call when no longer needed.
When the lists are merged, the routine assumes that List2 contains
the most current information. All the contents of List2 are copied
to the merged list, then, for any keywords in List1 that do not
also appear in List2, the keyword and value are copied to the merged
list.
Imbedded lists are not merged recursively. Any list value in List2
will replace the corresponding imbedded list from List1.
[HLRFIO Routines] 6
RFIO Routines
The low-level Response File APIs provide a more flexible but more
complicated way to manipulate Response Files. Their main purpose is to
provide building blocks for higher level code like the HLRFIO routines.
These routines are all in module RFIO.C and are referred to as the RFIO
Routines below. Because HLRFIO uses the RFIO routines, if you need to
change any of the assumptions about response file structure you will
probably need to make changes to the RFIO routines.
The RFIO Routines fall into three catagories:
- File Open and Close Routines
RF_Open_File() opens and returns a handle for a
response file.
RF_Close_FIle() closes a response file and returns
the previous handle, if any.
- Routines for handling included response files
RF_Create_Root_Ise() creates a structure used to
control included response file. It is called once,
before the first RF_Open_File().
RF_Get_Current_File_Name() returns the name of the
current active response file.
RF_Get_Current_RFHANDLE() returns the handle of the
current active response file.
- Sequential File I/O routines
RF_Get_Next_Kwd_In_File() extracts the next keyword/
value pair from the current file.
RF_Get_Next_Kwd_In_List() extracts the next keyword/
value pair from a _list_ type value.
RF_Get_Next_Wanted_Keyword_In_File() extracts the
next occurance of a particular keyword or keywords
in the file.
To use any of the RFIO routines in a program, include the header file rfioe.h
and link to RFIO.OBJ.
RFHANDLE RF_Open_File (
char *filename, // The name of the resp file
RFISP root_isp // Pointer to the root of the
// include stack
int *DosRc // Where to put DOS rtrn code
);
[RFIO Routines] 7
RF_Open_File returns a handle that can be used with the other RF
commands on success, or (RFHANDLE)NULL when there is an error.
In the case of an error, errno is put at *DosRc;
DosRc is unchanged if the operation is successfull.
filename points to an asciiz string containing the path and name of
the response file. RF_Open_File does not presume a particular
file suffix, so you have to give the whole thing i.e. \sd\myrf.rsp
RF_Open_File first tries DosFindFirst on the file spec. If it is
not found, and the filespec is relative, then each unit of DPATH is
searched. If still not found, each unit of PATH is searched.
The file name is allowed to be ambiguous, but only the first
occurance found is returned.
root_isp is a pointer to a structure of type RFIS, which is used to
handle the imbedding of included files. A call to RF_Open_File
preserves the handle of the file previously opened by RF_Open_File
when it returns the new handle. RF_Close_File returns the previous
handle, it there was one. So RF_Open and RF_Close can be used
together to painlessly process imbedded references to other files.
RF_Open_File checks for include file loops. If an open is issued
for file that is already in the include stack, it will be ignored;
the current RFHANDLE will be returned with no error indication.
The question arises what should the caller do if she is trying to
open an imbed file and NULL (file not found) is returned. Normally,
this will be a fatal error. If the caller wants to recover and
resume processing, however, she can call RF_Get_Current_RFHANDLE()
to get the handle of the file that included the imbed; then resume
processing.
RFHANDLE RF_Close_File (
RFHANDLE rfh // Value returned from open
RFISP root_isp // Pointer to root of include
// stack
);
RF_Close_File closes the response file.
rfh is the RFHANDLE to be close. Close looks in the include stack,
and closes the file associated with rfh and all files below it on
the stack (normally, rfh will probably be at the bottom of the
stack).
root_isp is a pointer to the root entry of the include stack.
RF_Close_File returns the RFHANDLE that was in effect when rfh
was opened, or (RFHANDLE)NULL if rfh was the first file opened.
RFISP RF_Create_Root_ISE (void);
This routine creates the root imbed (a.k.a. include) stack entry.
A user of RFIO calls it exactly once, before the exection of the
first RF_Open_File call. It returns a value passed to all subsequent
Open and Close calls. On an out-of-memory condition, it returns
(RFISP)NULL.
[RFIO Routines] 8
char *RF_Get_Current_File_Name(
RFISP root_isp;
);
This routine returns a pointer to the full name by which the
currently active response file was found. You need to free()
the string after you use it.
If there is no response file currently open, or if there is an
out-of-memory condition, NULL is returned.
char *RF_Get_Current_RFHANDLE(
RFISP root_isp;
);
This routine returns the RFHANDLE of the currently active
response file.
If there is no response file currently open, NULL is returned.
int RF_Get_Next_Kwd_In_File (
RFHANDLE rfh, // Value returned from open
char **kwp, // Where to put the pointer
// to the key word.
char **valp, // Where to put the pointer
// to the value.
int *valtypep // Where to put the type of
// value
); // (0 = string; 1 = list)
This function reads the next response file entry, parses it,
creates a place to put the pieces, and puts the pieces there. It
returns pointers to the keyword string and the value string; both the
strings are null-terminated. Comment lines and blank lines are
skipped. In the case of a list, a pointer to the whole list is
returned.
rfh is the handle returned from the RF_Open_File call.
kwp is the address of a character pointer where the routine will put
the address of the keyword string.
valp is the address of a character pointer where the routine will put
the address of the value string.
valtypep is a pointer to an integer where the routine will put the
type of value returned. 0 if a simple value string, or 1 if a
list.
Returns
RF0 to indicate success
RFOOS to indicate an out-of-memory condition
RFEOF to indicate end-of-file
RFERR if their is an I/O error or other DOS error.
The OS error code is stuffed at *valtypep.
RFSYNTAX to indicate a Response File syntax error
You can get the file name with a call to
RF_Get_Current_File_Name().
[RFIO Routines] 9
The offending line at *valp, and the line number at
*type.
int RF_Get_Next_Kwd_In_List(
char **start, // val returned from
// RF_Get_Next_Kwd_In_File()
char **kwp, // Where to put the pointer
// to the key word.
char **valp, // Where to put the pointer
// to the value.
int *valtypep // Where to put the type of
// value
); // (0 = string; 1 = list)
This is like RF_Get_Next_Kwd_In_File() except that it works on lists
in memory. Instead of an RFHANDLE, it takes a double char pointer
that keeps track of where it is in the list.
It is used to sequentially parse list values returned from
RF_Get_Next_Kwd_In_File().
start is a pointer to a char pointer. On
the first invocation, the caller must set it to the valp parameter
returned by RF_Get_Next_Kwd_In_File(). On subsequent calls, it is a
value set by this routine. The caller should not modify this value
after setting it to valp.
Note that nested lists are supported.
This routine returns the same values as RF_Get_Next_Keyword_In_List.
When RFEOF is returned, it really means that end-of-list has been
reached.
int RF_Get_Next_Wanted_Kwd_In_File(
RFHANDLE rfh, // Value returned from open
char **kwdlist,// A pointer to an array of
// character pointers. Each
// element of the array
// points to a string that
// contains the name
// of a keyword of interest.
char **kwp, // Where to put the pointer
// to the key word.
char **valp, // Where to put the pointer
// to the value.
int *valtypep // Where to put the type of
// value
); // (0 = string; 1 = list)
This routine works just lie RF_Get_Next_Kwd_In_File() except that you
can restrict the keywords returned to those you specify. The keywords
to be returned are pointed to by kwdlist. This variable should point
to a vector of pointers to strings that contains the names of keywords
of interest. The strings must be asciiz; the last element in the
vector of pointers must be NULL.
Here's an example:
[RFIO Routines] 10
char *kwdvector[] = {
"kwd1",
"keyword2",
"kword3",
NULL
}
while (RF_Get_Next_Wanted_Kwd_In_File(rfh, kwdvector, kwp, valp,
typep) != RFEOF)
{
<process your keyword>
free(kwp);
free(valp);
}
This routine returnes the same values as RF_Get_Next_Wanted_Kwd_In_File.
RFEOF means the last matching keyword has already been returned.
Error Handling
The part of this sample code that is least likely to suit your needs is the
error handling. The code that handles errors is in a seperate module,
CIDLOG.C. The interface to the error handling routine is fairly standard.
The call is
CID_Log(MessageNumber, ...)
where a variable number (0 to 10) pointers to asciiz strings can be passed as
optional parameters. But message numbers and the behavior of the error handling
routine will probably have to change for your particular application.
The message numbers are defined in hlrfio.h. Suggested message text is in
respfile.msg (source in respfile.txt).
Sample Code Files in This Package
The following files of sample code are included.
makefile A make file for all the code in this package.
When run, it generates
respfile.msg
sample1.exe
sample2.exe
sample3.exe
[Files in This Package] 11
getbootd.exe
chklvl.exe
respfile.msg An OS/2 message file containing the error
messages emitted by the Response File APIs.
respfile.txt Source for respfile.msg
cidlog.c Source for the error logging routine.
cidlog.h Header file for the error logging routine.
findfile.c Source for the routine that searches for
response files across the PATH and DPATH.
findfile.h Corresponding header file.
hlrfio.c Source for the high-level Response File APIs
hlrfio.h Corresponding header file.
rfio.c Source for the low-level Response File APIs
rfio.h Corresponding header file.
sample1.c A simple example using the high level APIs to
process a response file. When compiled and
linked, it is a working program.
sample1.def Linker def file for sample1
sample2.c A more complex example. Also a working program.
sample2.def Linker def file for sample2
sample3.c A more complex example yet. Also a working
program.
sample3.def Linker def file for sample3
sampinst.cmd A REXX command file that implements a full
CID install
getbootd.c A program to find out what drive was
last booted from.
getboot.def
chklvl.c A program to find out the installed level
of a package.
chklvl.def
test.rsp Test response file to be used with the
sample programs.
[Files in This Package] 12