home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
cidsam.zip
/
SAMPLE3.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-28
|
24KB
|
406 lines
/*********************************/
/* NOTE */
/* */
/* This sample code has been */
/* provided by IBM. It is not */
/* warranted for any particular */
/* use or purpose. */
/* */
/* IBM releases this code into */
/* the public domain. You may */
/* use it, modify it, or */
/* incorporate it into other */
/* products without restriction. */
/*********************************/
/* SAMPLE3.C */
/* */
/* This sample program uses the same Response File APIs as SAMPLE2, */
/* plus the RFMergeLists API.
/* It adds a common complication, though. Often configuration data */
/* consists of variable-length lists of information. For example, */
/* consider an application that deals with network adapter cards. */
/* Configuration information for this program might include data about */
/* each of the adapters in the machine. There might be one adapter, */
/* or there might be 2, 3 or 4. */
/* */
/* A common way of handling this situation is response files is with */
/* _named lists_. Here's an example for the network adapter program: */
/* */
/* Adapter = ( */
/* * adapter 0 */
/* name = 0 */
/* type = token_ring */
/* ) */
/* */
/* Adapter = ( */
/* * adapter 1 */
/* name = 1 */
/* type = ethernet */
/* ) */
/* */
/* Of course we could choose some keyword other than 'name' to identify */
/* which adapter we are dealing with, but 'name' is convenient and */
/* mnemonic enough for this example, at least. */
/* */
/* The complication this adds to a Response File program is that */
/* we may have to identify a response file entry not just by its */
/* keyword but also by its name. */
/* */
/* For example, in SAMPLE2 we scanned through the list of keywords */
/* encountered so far so we could overlay earlier specifications with */
/* later ones. In this sample, we want to overlay a previously- */
/* encountered keyword only if the name is the same. */
/* */
/* */
/*************************************************************************
**************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "hlrfio.h" /* This header file contains the prototypes for */
/* The Response File APIs, and defines for the */
/* codes returned by the Response File APIs */
char *ResponseFileName = "test.rsp"; /* This is the name of the response*/
/* file we will open first. It */
/* might contain imbedded */
/* (included) response files, but */
/* that's OK. */
/*************************************************************************/
/* This structure is an example of a *linked list*. Structures like */
/* this are useful for storing response file data in memory. */
/*************************************************************************/
struct keyword_value_pair { /* Structure to hold the keywords */
/* and values as they are read */
char *kw; /* Pointer to the keyword. */
int type; /* Type: string or list */
char *val; /* Pointer to the value */
char *name; /* Pointer to the name associated */
/* with a List type keyword. */
struct keyword_value_pair *next; /* linked list pointer */
};
/*************************************************************************/
/* Function prototypes (Response File API prototypes are in hlrfio.h) */
/*************************************************************************/
struct keyword_value_pair *processString(char *keyword, char *value,
struct keyword_value_pair *first);
struct keyword_value_pair *processList(char *keyword, char *value,
struct keyword_value_pair *first);
char *findName(char *namestring, char *list);
struct keyword_value_pair *findKeyword(char *keyword, char *name,
struct keyword_value_pair *first);
char *newCopy(char *model);
void printData(struct keyword_value_pair *first);
void printItem(char *keyword, int type, char *value);
/*************************************************************************
**************************************************************************/
/*************************************************************************/
/* The main() routine is very similar to SAMPLE1. It opens the main */
/* response file, sequentially reads all keywords and values, processes */
/* them, and prints the data out. The processing is a little more */
/* complicated: we call processString when the value is string type, */
/* and processList when it is list type. */
/* */
/* As each keyword and value are placed in a memory structure, we keep */
/* a chain of them. The variable first points to the first structure; */
/* subsequent pointers are in each structure's 'next' member. */
/*************************************************************************/
int main(int argc, char **argv)
{
int rc; /* return code */
char *keyword; /* Holds address of the keyword */
char *value; /* Holds address of the value */
unsigned type; /* Indicates the type of the value */
/* (string or list) */
struct keyword_value_pair *first; /* Pointer to first keyword/value. */
struct keyword_value_pair *new; /* Pointer to a new keyword/value. */
struct keyword_value_pair *latest; /* Pointer to most recent kwd/val. */
first = (struct keyword_value_pair *)0; /* initialize 'first' pointer*/
latest= (struct keyword_value_pair *)0;
rc = RFOpen(ResponseFileName); /* Open the response file. If the */
/* open was successful, RFH0 is */
/* returned. Otherwise, RFHERR. */
if (rc == RFH0) /* If the open worked, */
{ /* look at each keyword/value pair*/
while (RFGetNextKeyword(&keyword, &value, &type) == RFH0)
{ /* Check if the value returned is a*/
if (type == RFHSTRING) /* string. If so, */
new = processString(keyword, value, first);/* process it. */
else /* Otherwise it must be a list so */
new = processList(keyword, value, first); /* process it. */
if (new) /* If we allocated a new structure */
if (latest) /* If this is not the first one, */
{ /* put the new one in the chain. */
latest->next = new;
latest = new; /* keep track of the end of the */
} /* chain. */
else /* But if this *is* the first one, */
{ /* then it will head the chain. */
latest = new;
first = latest;
}
} /* After all the response files are*/
printData(first); /* read, print the data out. */
} /* Note we don't have to close the */
} /* response file explicitely */
/*************************************************************************
**************************************************************************/
/*************************************************************************/
/* processString() */
/* */
/* This routine takes a keyword and value and puts them in a memory */
/* structure. This is very easy. First we see if the keyword has */
/* already been encountered. If it has, we replace the old value with */
/* the current one. If not, we create a new structure for the pair. */
/* */
/* Note that the we need to make a permanent copy of the keyword and */
/* value strings returned from RFGetNextKeyword(). If we don't, */
/* we will not have access to them later when we need them. */
/* */
/* Also note that we check to see if a keyword has already been */
/* encountered (routine findKeyword()). If it has, we don't need */
/* to allocate a new structure; we just replace the value pointer. */
/*************************************************************************/
struct keyword_value_pair *processString(char *keyword, char *value,
struct keyword_value_pair *first)
{
int structsize;
struct keyword_value_pair *Structure;/* address of the new or old */
/* memory structure. */
/* Try to find an previous */
/* listing for this keyword. */
if (Structure = findKeyword(keyword, NULL, first)) /* If found, */
{
free(Structure->val); /* free memory used for the old */
Structure->val = newCopy(value);/* value, and substitute a new */
/* copy of the new value */
Structure->type = RFHSTRING; /* Note this is a string type */
return((struct keyword_value_pair *)NULL);
}
else /* But if this is the first use */
{ /* of this keyword, */
structsize = sizeof(struct keyword_value_pair);
/* Allocate memory for the struct */
Structure = (struct keyword_value_pair *)malloc(structsize);
if (Structure) /*If it was successfully allocated*/
{ /* make a new copy of the keyword*/
Structure->kw = newCopy(keyword);
Structure->val = newCopy(value); /* and the value */
Structure->name = NULL; /* String values don't have names */
Structure->type = RFHSTRING; /* Note this is a string type */
/* Make sure the chain pointer is */
/* empty; this structure will be */
/* added at the end of the list, */
/* and a NULL pointer lets us */
/* indicate that this is the end. */
Structure->next = (struct keyword_value_pair *)NULL;
}
return(Structure);
}
}
/*************************************************************************
**************************************************************************/
/*************************************************************************/
/* processList() */
/* */
/* This routine takes a keyword and list and puts them in a memory */
/* structure. This is only a little bit harder. */
/* */
/* This is very much like processString(), except we use the */
/* RFCopyList function to make a permanent copy of the list. */
/*************************************************************************/
struct keyword_value_pair *processList(char *keyword, char *value,
struct keyword_value_pair *first)
{
char *listname = NULL; /* Name in this list */
char *oldval, *newval; /* Old and new list values */
struct keyword_value_pair *Structure;/* address of the new or old */
/* memory structure. */
/* Make a persistant copy of the */
newval = RFCopyList(value); /* list. */
/* See if there is a Name keyword */
/* in this list. */
listname = findName("name", newval);
/* Now see if there was a keyword */
/* with that name earlier. */
if (Structure = findKeyword(keyword, listname, first))
{ /* If it exists, just merge the */
/* two lists. */
oldval = Structure->val; /* Keep pointer to current value. */
/* Merge the old and new lists */
Structure->val = RFMergeLists(oldval, newval);
free(oldval); /* Free space used by old value */
free(newval); /* and new value. They're merged. */
Structure->type = RFHLIST; /* note that this is a list. */
free(listname); /* We don't need the name anymore */
return((struct keyword_value_pair *)NULL);
}
else
{ /* If this is a new keyword, */
/* Allocate memory for the struct */
Structure = (struct keyword_value_pair *)
malloc(sizeof(struct keyword_value_pair));
if (Structure) /*If it was successfully allocated*/
{ /* make a new copy of the keyword*/
Structure->kw = newCopy(keyword);
Structure->val = newval; /* and the value */
Structure->name = listname; /* Record the name, if any */
Structure->type = RFHLIST; /* Note this is a list type */
Structure->next = (struct keyword_value_pair *)NULL;
}
return(Structure);
}
}
/*************************************************************************
**************************************************************************/
/*************************************************************************/
/* This routine searches through a list for a keyword that matches the */
/* first argument, and returns a persistant copy of the value string */
/* associated with the keyword. For example, if the first argument is */
/* the string "name", and the list contains a line */
/* name = something */
/* then the string "something" is returned. */
/*************************************************************************/
char *findName(char *namestring, char *list)
{
char *keyword, *value, *start;
unsigned type;
start = list;
while (RFGetNextKwdInList(&start, &keyword, &value, &type) == RFH0)
if (type == RFHSTRING)
if (stricmp(namestring, keyword) == 0)
return(newCopy(value));
return(NULL);
}
/*************************************************************************/
/* This routine looks up the current keyword to see if we have already */
/* encountered it. It uses the pointer first to find the first */
/* structure, then 'walks the chain' looking at each keyword found so */
/* far. If it finds a matching keyword, it returns a pointer to the */
/* structure; otherwise, it returns NULL. */
/* */
/* Note that this routine treats keywords without regard to case; */
/* MyKeyword is assumed to be the same as mYkEYWORD. This is not */
/* a requirement, but it is a useful convention. */
/* */
/* Note that we don't count a keyword as matching if it has a different */
/* name than the one already encountered. */
/*************************************************************************/
struct keyword_value_pair *findKeyword(char *keyword, char *name,
struct keyword_value_pair *first)
{
struct keyword_value_pair *next;
for (next = first; next; next = next->next)
if (stricmp(keyword, next->kw) == 0)
if (!next->name)
return(next);
else
if (stricmp(name, next->name) == 0);
return(next);
return((struct keyword_value_pair *)NULL);
}
/*************************************************************************
**************************************************************************/
/*************************************************************************/
/* This routine makes a permanent copy of the string that is passed to it*/
/* and returns the address of the string. */
/*************************************************************************/
char *newCopy(char *model)
{
char *p;
/* Allocate memory for the */
p = (char *)malloc(strlen(model) + 1); /* permanent copy */
if (p) /* If memory was allocated */
strcpy(p, model); /* make the copy. */
return(p);
}
/*************************************************************************/
/* printData() */
/* Print out whatever we have in memory */
/*************************************************************************/
void printData(struct keyword_value_pair *first)
{
struct keyword_value_pair *next;
for (next = first; next; next = next->next)
printItem(next->kw, next->type, next->val);
}
/*************************************************************************
**************************************************************************/
/*************************************************************************/
/* printItem() */
/* Because we want to display the contents of list values, this routine */
/* uses the Response File API RFGetNextKwdInList() to extract them. */
/* */
/* Note that this routine is called recursively because there may be */
/* lists imbedded within lists. */
/*************************************************************************/
void printItem(char *keyword, int type, char *value)
{
char *listkw, *listval; /* to hold keywords from within lists */
unsigned int listtype;
char *start; /* holds our place in the list */
if (type == RFHSTRING) /* string types are easy */
if (!value) /* We just have to check if there is */
printf("%s\n", keyword); /* is a value or not */
else
printf("%s = %s\n", keyword, value);
else /* list types a little harder */
{
printf("[BEGIN %s]\n", keyword);
start = value;
/* Read each item in the list */
while (RFGetNextKwdInList(&start, &listkw, &listval, &listtype)
== RFH0)
{ /* If this list contains an imbedded */
/* list, we have to make a copy of the*/
/* embedded list. This is because */
/* none of the objects that come back */
/* from RF API calls are permanent, */
/* and we need to use RF calls to */
/* process this imbedded list. */
if (listtype == RFHLIST)
{
listkw = newCopy(listkw);
listval = RFCopyList(listval);
}
/* Now we can process the list by */
/* calling ourselves recursively. */
printItem(listkw, listtype, listval);
/* If we made our own copies earlier, */
/* we can free them up now that we */
/* are done. */
if (listtype == RFHLIST)
{
free(listkw);
free(listval);
}
}
printf("[END %s]\n", keyword);
}
}