home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cidsam.zip / SAMPLE3.C < prev    next >
C/C++ Source or Header  |  1993-06-28  |  24KB  |  406 lines

  1.                   /*********************************/
  2.                   /*              NOTE             */
  3.                   /*                               */
  4.                   /* This sample code has been     */
  5.                   /* provided by IBM.  It is not   */
  6.                   /* warranted for any particular  */
  7.                   /* use or purpose.               */
  8.                   /*                               */
  9.                   /* IBM releases this code into   */
  10.                   /* the public domain.  You may   */
  11.                   /* use it, modify it, or         */
  12.                   /* incorporate it into other     */
  13.                   /* products without restriction. */
  14.                   /*********************************/
  15. /* SAMPLE3.C                                                             */
  16. /*                                                                       */
  17. /* This sample program uses the same Response File APIs as SAMPLE2,      */
  18. /* plus the RFMergeLists API.
  19. /* It adds a common complication, though.  Often configuration data      */
  20. /* consists of variable-length lists of information.  For example,       */
  21. /* consider an application that deals with network adapter cards.        */
  22. /* Configuration information for this program might include data about   */
  23. /* each of the adapters in the machine.  There might be one adapter,     */
  24. /* or there might be 2, 3 or 4.                                          */
  25. /*                                                                       */
  26. /* A common way of handling this situation is response files is with     */
  27. /* _named lists_.  Here's an example for the network adapter program:    */
  28. /*                                                                       */
  29. /*            Adapter = (                                                */
  30. /*  * adapter 0                                                          */
  31. /*                        name = 0                                       */
  32. /*                        type = token_ring                              */
  33. /*                      )                                                */
  34. /*                                                                       */
  35. /*            Adapter = (                                                */
  36. /*  * adapter 1                                                          */
  37. /*                        name = 1                                       */
  38. /*                        type = ethernet                                */
  39. /*                      )                                                */
  40. /*                                                                       */
  41. /* Of course we could choose some keyword other than 'name' to identify  */
  42. /* which adapter we are dealing with, but 'name' is convenient and       */
  43. /* mnemonic enough for this example, at least.                           */
  44. /*                                                                       */
  45. /* The complication this adds to a Response File program is that         */
  46. /* we may have to identify a response file entry not just by its         */
  47. /* keyword but also by its name.                                         */
  48. /*                                                                       */
  49. /* For example, in SAMPLE2 we scanned through the list of keywords       */
  50. /* encountered so far so we could overlay earlier specifications with    */
  51. /* later ones.  In this sample, we want to overlay a previously-         */
  52. /* encountered keyword only if the name is the same.                     */
  53. /*                                                                       */
  54. /*                                                                       */
  55. /*************************************************************************  
  56. **************************************************************************/
  57. #include <stdio.h>           
  58. #include <stdlib.h>
  59. #include <string.h>
  60. #include "hlrfio.h"      /* This header file contains the prototypes for */
  61.                          /* The Response File APIs, and defines for the  */
  62.                          /* codes returned by the Response File APIs     */
  63.  
  64. char *ResponseFileName = "test.rsp";  /* This is the name of the response*/
  65.                                       /* file we will open first.  It    */
  66.                                       /* might contain imbedded          */
  67.                                       /* (included) response files, but  */
  68.                                       /* that's OK.                      */
  69.  
  70. /*************************************************************************/
  71. /* This structure is an example of a *linked list*.  Structures like     */
  72. /* this are useful for storing response file data in memory.             */
  73. /*************************************************************************/
  74. struct keyword_value_pair   {         /* Structure to hold the keywords  */
  75.                                       /* and values as they are read     */
  76.          char *kw;                    /* Pointer to the keyword.         */
  77.          int  type;                   /* Type: string or list            */
  78.          char *val;                   /* Pointer to the value            */
  79.          char *name;                  /* Pointer to the name associated  */
  80.                                       /*  with a List type keyword.      */
  81.          struct keyword_value_pair *next;  /* linked list pointer        */
  82.                             };      
  83.  
  84.  
  85. /*************************************************************************/
  86. /* Function prototypes (Response File API prototypes are in hlrfio.h)    */
  87. /*************************************************************************/
  88. struct keyword_value_pair *processString(char *keyword, char *value,
  89.                                         struct keyword_value_pair *first);
  90. struct keyword_value_pair *processList(char *keyword, char *value,
  91.                                         struct keyword_value_pair *first);
  92. char *findName(char *namestring, char *list);
  93. struct keyword_value_pair *findKeyword(char *keyword, char *name,
  94.                                           struct keyword_value_pair *first);
  95. char *newCopy(char *model);
  96. void printData(struct keyword_value_pair *first);
  97. void printItem(char *keyword, int type, char *value);
  98. /*************************************************************************  
  99. **************************************************************************/
  100.  
  101. /*************************************************************************/
  102. /* The main() routine is very similar to SAMPLE1.  It opens the main     */
  103. /* response file, sequentially reads all keywords and values, processes  */
  104. /* them, and prints the data out.  The processing is a little more       */
  105. /* complicated: we call processString when the value is string type,     */
  106. /* and processList when it is list type.                                 */
  107. /*                                                                       */
  108. /* As each keyword and value are placed in a memory structure, we keep   */
  109. /* a chain of them.  The variable first points to the first structure;   */
  110. /* subsequent pointers are in each structure's 'next' member.            */
  111. /*************************************************************************/
  112. int main(int argc, char **argv)
  113. {
  114.    int rc;                            /* return code                     */
  115.    char *keyword;                     /* Holds address of the keyword    */
  116.    char *value;                       /* Holds address of the value      */
  117.    unsigned type;                     /* Indicates the type of the value */
  118.                                       /* (string or list)                */
  119.    struct keyword_value_pair *first;  /* Pointer to first keyword/value. */
  120.    struct keyword_value_pair *new;    /* Pointer to a new keyword/value. */
  121.    struct keyword_value_pair *latest; /* Pointer to most recent kwd/val. */
  122.  
  123.    first = (struct keyword_value_pair *)0;  /* initialize 'first' pointer*/
  124.    latest= (struct keyword_value_pair *)0;
  125.  
  126.    rc = RFOpen(ResponseFileName);     /* Open the response file.  If the */
  127.                                       /* open was successful, RFH0 is    */
  128.                                       /* returned.  Otherwise, RFHERR.   */
  129.    if (rc == RFH0)                    /* If the open worked,             */
  130.      {                                /*  look at each keyword/value pair*/
  131.         while (RFGetNextKeyword(&keyword, &value, &type) == RFH0)
  132.  
  133.           {                           /* Check if the value returned is a*/
  134.              if (type == RFHSTRING)   /* string.   If so,                */
  135.                new = processString(keyword, value, first);/* process it. */
  136.              else                     /* Otherwise it must be a list  so */
  137.                new = processList(keyword, value, first); /* process it.  */
  138.  
  139.              if (new)                 /* If we allocated a new structure */
  140.                if (latest)            /* If this is not the first one,   */
  141.                  {                    /* put the new one in the chain.   */
  142.                    latest->next = new;
  143.                    latest = new;      /* keep track of the end of the    */
  144.                  }                    /*   chain.                        */
  145.                else                   /* But if this *is* the first one, */
  146.                  {                    /* then it will head the chain.    */
  147.                    latest = new;
  148.                    first = latest;
  149.                  }
  150.           }                           /* After all the response files are*/
  151.         printData(first);             /* read, print the data out.       */
  152.       }                               /* Note we don't have to close the */
  153. }                                     /* response file explicitely       */
  154. /*************************************************************************  
  155. **************************************************************************/
  156.  
  157. /*************************************************************************/
  158. /* processString()                                                       */
  159. /*                                                                       */
  160. /* This routine takes a keyword and value and puts them in a memory      */
  161. /* structure.  This is very easy.  First we see if the keyword has       */
  162. /* already been encountered.  If it has, we replace the old value with   */
  163. /* the current one.  If not, we create a new structure for the pair.     */
  164. /*                                                                       */
  165. /* Note that the we need to make a permanent copy of the keyword and     */
  166. /* value strings returned from RFGetNextKeyword().  If we don't,         */
  167. /* we will not have access to them later when we need them.              */
  168. /*                                                                       */
  169. /* Also note that we check to see if a keyword has already been          */
  170. /* encountered (routine findKeyword()).  If it has, we don't need        */
  171. /* to allocate a new structure; we just replace the value pointer.       */
  172. /*************************************************************************/
  173. struct keyword_value_pair *processString(char *keyword, char *value,
  174.                                         struct keyword_value_pair *first)
  175. {
  176.    int structsize;
  177.    struct keyword_value_pair *Structure;/* address of the new or old     */
  178.                                        /* memory structure.              */
  179.  
  180.                                        /* Try to find an previous        */
  181.                                        /* listing for this keyword.      */
  182.    if (Structure = findKeyword(keyword, NULL, first))   /* If found,           */
  183.      {
  184.         free(Structure->val);          /* free memory used for the old   */
  185.         Structure->val = newCopy(value);/* value, and substitute a new   */
  186.                                        /* copy of the new value          */
  187.         Structure->type = RFHSTRING;   /* Note this is a string type     */
  188.         return((struct keyword_value_pair *)NULL);
  189.      }
  190.    else                                /* But if this is the first use   */
  191.      {                                 /* of this keyword,               */
  192.        structsize = sizeof(struct keyword_value_pair);
  193.                                        /* Allocate memory for the struct */
  194.        Structure = (struct keyword_value_pair *)malloc(structsize);
  195.        if (Structure)                  /*If it was successfully allocated*/
  196.          {                             /*  make a new copy of the keyword*/
  197.            Structure->kw = newCopy(keyword);
  198.            Structure->val = newCopy(value); /* and the value             */
  199.            Structure->name = NULL;     /* String values don't have names */
  200.            Structure->type = RFHSTRING; /* Note this is a string type    */
  201.                                        /* Make sure the chain pointer is */
  202.                                        /* empty; this structure will be  */
  203.                                        /* added at the end of the list,  */
  204.                                        /* and a NULL pointer lets us     */
  205.                                        /* indicate that this is the end. */
  206.            Structure->next = (struct keyword_value_pair *)NULL;
  207.          }
  208.        return(Structure);
  209.      }
  210. }
  211. /*************************************************************************  
  212. **************************************************************************/
  213.  
  214.  
  215. /*************************************************************************/
  216. /* processList()                                                         */
  217. /*                                                                       */
  218. /* This routine takes a keyword and list and  puts them in a memory      */
  219. /* structure.  This is only a little bit harder.                         */
  220. /*                                                                       */
  221. /* This is very much like processString(), except we use the             */
  222. /* RFCopyList function to make a permanent copy of the list.             */
  223. /*************************************************************************/
  224. struct keyword_value_pair *processList(char *keyword, char *value,
  225.                                         struct keyword_value_pair *first)
  226. {
  227.    char *listname = NULL;              /* Name in this list              */
  228.    char *oldval, *newval;              /* Old and new list values        */
  229.    struct keyword_value_pair *Structure;/* address of the new or old     */
  230.                                        /* memory structure.              */
  231.                                        
  232.                                        /* Make a persistant copy of the  */ 
  233.    newval = RFCopyList(value);         /* list.                          */ 
  234.                                        /* See if there is a Name keyword */
  235.                                        /* in this list.                  */
  236.    listname = findName("name", newval);
  237.                                        /* Now see if there was a keyword */
  238.                                        /* with that name earlier.        */
  239.    if (Structure = findKeyword(keyword, listname, first))
  240.      {                                 /* If it exists, just merge the   */
  241.                                        /* two lists.                     */
  242.         oldval = Structure->val;       /* Keep pointer to current value. */
  243.                                        /* Merge the old and new lists    */
  244.         Structure->val = RFMergeLists(oldval, newval);
  245.         free(oldval);                  /* Free space used by old value   */
  246.         free(newval);                  /* and new value. They're merged. */
  247.         Structure->type = RFHLIST;     /* note that this is a list.      */
  248.         free(listname);                /* We don't need the name anymore */
  249.         return((struct keyword_value_pair *)NULL);
  250.      }
  251.    else                            
  252.      {                                 /* If this is a new keyword,      */
  253.                                        /* Allocate memory for the struct */
  254.        Structure = (struct keyword_value_pair *)
  255.                                  malloc(sizeof(struct keyword_value_pair));
  256.        if (Structure)                  /*If it was successfully allocated*/
  257.          {                             /*  make a new copy of the keyword*/
  258.            Structure->kw = newCopy(keyword);
  259.            Structure->val = newval;    /* and the value                  */
  260.            Structure->name = listname; /* Record the name, if any        */
  261.            Structure->type = RFHLIST;  /* Note this is a list   type     */
  262.            Structure->next = (struct keyword_value_pair *)NULL;
  263.          }
  264.        return(Structure);
  265.      }
  266. }
  267. /*************************************************************************  
  268. **************************************************************************/
  269.  
  270. /*************************************************************************/
  271. /* This routine searches through a list for a keyword that matches the   */
  272. /* first argument, and returns a persistant copy of the value string     */
  273. /* associated with the keyword.  For example, if the first argument is   */
  274. /* the string "name", and the list contains a line                       */
  275. /*            name = something                                           */
  276. /* then the string "something" is returned.                              */
  277. /*************************************************************************/
  278. char *findName(char *namestring, char *list)
  279. {
  280.    char *keyword, *value, *start;
  281.    unsigned type;
  282.  
  283.    start = list;
  284.    while (RFGetNextKwdInList(&start, &keyword, &value, &type) == RFH0)
  285.      if (type == RFHSTRING)
  286.        if (stricmp(namestring, keyword) == 0)
  287.          return(newCopy(value));
  288.    return(NULL);
  289. }
  290.  
  291. /*************************************************************************/
  292. /* This routine looks up the current keyword to see if we have already   */
  293. /* encountered it.  It uses the pointer first to find the first          */
  294. /* structure, then  'walks the chain' looking at each keyword found so   */
  295. /* far.  If it finds a matching keyword, it returns a pointer to the     */
  296. /* structure; otherwise, it returns NULL.                                */
  297. /*                                                                       */
  298. /* Note that this routine treats keywords without regard to case;        */
  299. /* MyKeyword is assumed to be the same as mYkEYWORD.  This is not        */
  300. /* a requirement, but it is a useful convention.                         */
  301. /*                                                                       */
  302. /* Note that we don't count a keyword as matching if it has a different  */
  303. /* name than the one already encountered.                                */
  304. /*************************************************************************/
  305. struct keyword_value_pair *findKeyword(char *keyword, char *name,
  306.                                           struct keyword_value_pair *first)
  307. {
  308.    struct keyword_value_pair *next;
  309.  
  310.    for (next = first; next; next = next->next)
  311.       if (stricmp(keyword, next->kw) == 0)
  312.         if (!next->name)
  313.           return(next);
  314.         else
  315.           if (stricmp(name, next->name) == 0);
  316.             return(next);
  317.    return((struct keyword_value_pair *)NULL);
  318. }
  319. /*************************************************************************  
  320. **************************************************************************/
  321.  
  322.  
  323. /*************************************************************************/
  324. /* This routine makes a permanent copy of the string that is passed to it*/
  325. /* and returns the address of the string.                                */
  326. /*************************************************************************/
  327. char *newCopy(char *model)
  328. {
  329.    char *p;
  330.                  
  331.                                           /* Allocate memory for the     */
  332.    p = (char *)malloc(strlen(model) + 1); /* permanent copy              */
  333.    if (p)                                 /* If memory was allocated     */
  334.      strcpy(p, model);                    /* make the copy.              */
  335.    return(p);
  336. }
  337.  
  338. /*************************************************************************/
  339. /* printData()                                                           */
  340. /* Print out whatever we have in memory                                  */
  341. /*************************************************************************/
  342. void printData(struct keyword_value_pair *first)
  343. {
  344.    struct keyword_value_pair *next;
  345.  
  346.    for (next = first; next; next = next->next)
  347.       printItem(next->kw, next->type, next->val);
  348. }
  349. /*************************************************************************  
  350. **************************************************************************/
  351.  
  352.  
  353. /*************************************************************************/
  354. /* printItem()                                                           */
  355. /* Because we want to display the contents of list values, this routine  */
  356. /* uses the Response File API RFGetNextKwdInList() to extract them.      */
  357. /*                                                                       */
  358. /* Note that this routine is called recursively because there may be     */
  359. /* lists imbedded within lists.                                          */
  360. /*************************************************************************/
  361. void printItem(char *keyword, int type, char *value)
  362. {
  363.    char *listkw, *listval;         /* to hold keywords from within lists */
  364.    unsigned int listtype;
  365.    char *start;                    /* holds our place in the list        */
  366.  
  367.    if (type == RFHSTRING)           /* string types are easy              */
  368.      if (!value)                    /* We just have to check if there is  */
  369.        printf("%s\n", keyword);     /* is a value or not                  */
  370.      else
  371.        printf("%s = %s\n", keyword, value);
  372.    else                            /* list types a little harder         */
  373.      {
  374.         printf("[BEGIN %s]\n", keyword);
  375.         start = value;
  376.                                    /* Read each item in the list         */
  377.         while (RFGetNextKwdInList(&start, &listkw, &listval, &listtype)
  378.                                                                    == RFH0)
  379.           {                        /* If this list contains an imbedded  */
  380.                                    /* list, we have to make a copy of the*/
  381.                                    /* embedded list.  This is because    */
  382.                                    /* none of the objects that come back */
  383.                                    /* from RF API calls are permanent,   */
  384.                                    /* and we need to use RF calls to     */
  385.                                    /* process this imbedded list.        */
  386.             if (listtype == RFHLIST)
  387.               {
  388.                 listkw = newCopy(listkw);
  389.                 listval = RFCopyList(listval);
  390.               }
  391.                                    /* Now we can process the list by     */
  392.                                    /* calling ourselves recursively.     */
  393.             printItem(listkw, listtype, listval);
  394.                                    /* If we made our own copies earlier, */
  395.                                    /* we can free them up now that we    */
  396.                                    /* are done.                          */
  397.             if (listtype == RFHLIST)
  398.               {
  399.                 free(listkw);
  400.                 free(listval);
  401.               }
  402.           }
  403.         printf("[END %s]\n", keyword);
  404.       }
  405. }
  406.