home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / c / condor40.zip / CONDOR / src / util_lib / config.c < prev    next >
C/C++ Source or Header  |  1989-05-15  |  9KB  |  425 lines

  1. /* 
  2. ** Copyright 1986, 1987, 1988, 1989 University of Wisconsin
  3. ** 
  4. ** Permission to use, copy, modify, and distribute this software and its
  5. ** documentation for any purpose and without fee is hereby granted,
  6. ** provided that the above copyright notice appear in all copies and that
  7. ** both that copyright notice and this permission notice appear in
  8. ** supporting documentation, and that the name of the University of
  9. ** Wisconsin not be used in advertising or publicity pertaining to
  10. ** distribution of the software without specific, written prior
  11. ** permission.  The University of Wisconsin makes no representations about
  12. ** the suitability of this software for any purpose.  It is provided "as
  13. ** is" without express or implied warranty.
  14. ** 
  15. ** THE UNIVERSITY OF WISCONSIN DISCLAIMS ALL WARRANTIES WITH REGARD TO
  16. ** THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17. ** FITNESS. IN NO EVENT SHALL THE UNIVERSITY OF WISCONSIN  BE LIABLE FOR
  18. ** ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19. ** WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  20. ** ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  21. ** OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22. ** 
  23. ** Authors:  Allan Bricker and Michael J. Litzkow,
  24. **              University of Wisconsin, Computer Sciences Dept.
  25. ** 
  26. */ 
  27.  
  28.  
  29. /*
  30. ** This file implements a configuration table which is read from the config
  31. ** file.  The file contains lines of the form "string = value" where either
  32. ** "string" or "value" may contain references to other (previously defined)
  33. ** parameters of the form "$(parameter)".  Blank lines and lines beginning
  34. ** with '#' are considered comments.  Forward references are not allowed,
  35. ** but multiple and or nested references are allowed.  The table is stored
  36. ** as a chain bucket hash table.
  37. */
  38.  
  39. #include <stdio.h>
  40. #include <ctype.h>
  41. #include <pwd.h>
  42. #include <netdb.h>
  43. #include "trace.h"
  44. #include "expr.h"
  45. #include "files.h"
  46. #include "debug.h"
  47. #include "except.h"
  48. #include "config.h"
  49. #include "clib.h"
  50.  
  51. static char *_FileName_ = __FILE__;        /* Used by EXCEPT (see except.h)     */
  52.  
  53. char    *strdup(), *getline(), *expand_macro(), *malloc(), *ltrunc(),
  54.         *index(), *rindex(), *lookup_macro();
  55.  
  56. int        ConfigLineNo;
  57.  
  58. #define ISIDCHAR(c)        (isalnum(c) || ((c) == '_'))
  59. #define ISOP(c)        (((c) == '=') || ((c) == ':'))
  60.  
  61.  
  62.  
  63. /*
  64. ** Just compute a hash value for the given string such that
  65. ** 0 <= value < size 
  66. */
  67. hash( string, size )
  68. register char    *string;
  69. register int    size;
  70. {
  71.     register unsigned int        answer;
  72.  
  73.     answer = 1;
  74.  
  75.     for( ; *string; string++ ) {
  76.         answer <<= 1;
  77.         answer += (int)*string;
  78.     }
  79.     answer >>= 1;    /* Make sure not negative */
  80.     answer %= size;
  81.     return answer;
  82. }
  83.  
  84. /*
  85. ** Insert the parameter name and value into the given hash table.
  86. */
  87. insert( name, value, table, table_size )
  88. char    *name;
  89. char    *value;
  90. BUCKET    *table[];
  91. int        table_size;
  92. {
  93.     register BUCKET    *ptr;
  94.     int        loc;
  95.     BUCKET    *bucket;
  96.  
  97.         /* Make sure not already in hash table */
  98.     lower_case( name );
  99.     loc = hash( name, table_size );
  100.     for( ptr=table[loc]; ptr; ptr=ptr->next ) {
  101.         if( strcmp(name,ptr->name) == 0 ) {
  102.             free( ptr->value );
  103.             ptr->value = strdup( value );
  104.             return;
  105.         }
  106.     }
  107.  
  108.         /* Insert it */
  109.     bucket = (BUCKET *)malloc( sizeof(BUCKET) );
  110.     bucket->name = strdup( name );
  111.     bucket->value = strdup( value );
  112.     bucket->next = table[ loc ];
  113.     table[loc] = bucket;
  114. }
  115.  
  116. /*
  117. ** Read in the config file and produce the hash table (table).
  118. */
  119. read_config( tilde, config_name, context, table, table_size, expand_flag )
  120. char    *tilde, *config_name;
  121. CONTEXT *context;
  122. BUCKET    *table[];
  123. int        table_size;
  124. int        expand_flag;
  125. {
  126.     FILE    *conf_fp;
  127.     EXPR    *expr, *scan();
  128.     char    *name, *value;
  129.     char    *ptr;
  130.     char    op;
  131.     char    file_name[1024];
  132.  
  133.     ConfigLineNo = 0;
  134.  
  135.     (void)sprintf(file_name, "%s/%s", tilde, config_name);
  136.     conf_fp = fopen(file_name, "r");
  137.     if( conf_fp == NULL ) {
  138.         return( -1 );
  139.     }
  140.  
  141.     for(;;) {
  142.         name = getline(conf_fp);
  143.         if( name == NULL ) {
  144.             break;
  145.         }
  146.  
  147.             /* Skip over comments */
  148.         if( *name == '#' || blankline(name) )
  149.             continue;
  150.  
  151.         ptr = name;
  152.         while( *ptr ) {
  153.             if( isspace(*ptr) || ISOP(*ptr) ) {
  154.                 break;
  155.             } else {
  156.                 ptr++;
  157.             }
  158.         }
  159.  
  160.         if( !*ptr ) {
  161.             (void)fclose( conf_fp );
  162.             return( -1 );
  163.         }
  164.  
  165.         if( ISOP(*ptr) ) {
  166.             op = *ptr;
  167.             *ptr++ = '\0';
  168.         } else {
  169.             *ptr++ = '\0';
  170.             while( *ptr && !ISOP(*ptr) ) {
  171.                 ptr++;
  172.             }
  173.  
  174.             if( !*ptr ) {
  175.                 (void)fclose( conf_fp );
  176.                 return( -1 );
  177.             }
  178.  
  179.             op = *ptr++;
  180.         }
  181.  
  182.             /* Skip to next non-space character */
  183.         while( *ptr && isspace(*ptr) ) {
  184.             ptr++;
  185.         }
  186.  
  187.         value = ptr;
  188.  
  189.             /* Expand references to other parameters */
  190.         name = expand_macro( name, table, table_size );
  191.         if( name == NULL ) {
  192.             (void)fclose( conf_fp );
  193.             return( -1 );
  194.         }
  195.  
  196.             /* Check that "name" is a legal identifier */
  197.         ptr = name;
  198.         while( *ptr ) {
  199.             char c = *ptr++;
  200.             if( !ISIDCHAR(c) ) {
  201.                 (void) fclose( conf_fp );
  202.                 fprintf( stderr,
  203.         "Configuration Error File <%s>, Line %d: Illegal Identifier: <%s>\n",
  204.                     file_name, ConfigLineNo, name );
  205.                 return( -1 );
  206.             }
  207.         }
  208.  
  209.         if( expand_flag == EXPAND_IMMEDIATE ) {
  210.             value = expand_macro( value, table, table_size );
  211.             if( value == NULL ) {
  212.                 (void)fclose( conf_fp );
  213.                 return( -1 );
  214.             }
  215.         }
  216.  
  217.         if( op == ':' ) {
  218.             if( context != NULL ) {
  219.                 char *evalue;
  220.                 char *line;
  221.  
  222.                 if( expand_flag == EXPAND_IMMEDIATE ) {
  223.                     evalue = value;
  224.                 } else {
  225.                     evalue = expand_macro( value, table, table_size );
  226.                     if( evalue == NULL ) {
  227.                         (void)fclose( conf_fp );
  228.                         return( -1 );
  229.                     }
  230.                 }
  231.  
  232.                 line = malloc( (unsigned)(strlen(name) + strlen(evalue) + 4) );
  233.  
  234.                 if( line == NULL ) {
  235.                     EXCEPT("Out of memory" );
  236.                 }
  237.  
  238.                 (void)sprintf(line, "%s = %s", name, evalue);
  239.  
  240.                 expr = scan( line );
  241.                 if( expr == NULL ) {
  242.                     EXCEPT("Expression syntax error in <%s> line %d",
  243.                             file_name, ConfigLineNo );
  244.                 }
  245.  
  246.                 store_stmt( expr, context );
  247.  
  248.                 free( line );
  249.             }
  250.         } else if( op == '=' ) {
  251.             lower_case( name );
  252.  
  253.                 /* Put the value in the Configuration Table */
  254.             insert( name, value, table, table_size );
  255.         } else {
  256.             fprintf( stderr,
  257.             "Configuration Error File <%s>, Line %d: Syntax Error\n",
  258.                 file_name, ConfigLineNo );
  259.             (void)fclose( conf_fp );
  260.             return -1;
  261.         }
  262.  
  263.         free( name );
  264.         free( value );
  265.     }
  266.  
  267.     (void)fclose( conf_fp );
  268.     return 0;
  269. }
  270.  
  271. /*
  272. ** Read one line and any continuation lines that go with it.  Lines ending
  273. ** with <white space><backslash> are continued onto the next line.
  274. */
  275. char *
  276. getline( fp )
  277. FILE    *fp;
  278. {
  279.     static char    buf[2048];
  280.     int        len;
  281.     char    *read_buf = buf;
  282.     char    *line = NULL;
  283.     char    *ptr;
  284.  
  285.  
  286.     for(;;) {
  287.         len = sizeof(buf) - (read_buf - buf);
  288.         if( len <= 0 ) {
  289.             EXCEPT( "Config file line too long" );
  290.         }
  291.         if( fgets(read_buf,len,fp) == NULL )
  292.             return line;
  293.  
  294.         ConfigLineNo++;
  295.         
  296.             /* See if a continuation is indicated */
  297.         line = ltrunc( read_buf );
  298.         if( line != read_buf ) {
  299.             (void)strcpy( read_buf, line );
  300.         }
  301.         if( (ptr = rindex(line,'\\')) == NULL )
  302.             return buf;
  303.         if( *(ptr+1) != '\0' )
  304.             return buf;
  305.  
  306.             /* Ok read the continuation and concatenate it on */
  307.         read_buf = ptr;
  308.     }
  309. }
  310.  
  311. /*
  312. ** Transform the given string into lower case in place.
  313. */
  314. lower_case( str )
  315. register char    *str;
  316. {
  317.     for( ; *str; str++ ) {
  318.         if( *str >= 'A' && *str <= 'Z' )
  319.             *str |= 040;
  320.     }
  321. }
  322.     
  323. /*
  324. ** Expand parameter references of the form "left$(middle)right".  This
  325. ** is deceptively simple, but does handle multiple and or nested references.
  326. */
  327. char *
  328. expand_macro( value, table, table_size )
  329. char    *value;
  330. BUCKET    *table[];
  331. int        table_size;
  332. {
  333.     char *tmp = strdup( value );
  334.     char *left, *name, *tvalue, *right;
  335.     char *rval;
  336.  
  337.     while( get_var(tmp, &left, &name, &right) ) {
  338.         tvalue = lookup_macro( name, table, table_size );
  339.         if( tvalue == NULL ) {
  340.             free( tmp );
  341.             return( NULL );
  342.         }
  343.  
  344.         rval = malloc( (unsigned)(strlen(left) + strlen(tvalue) +
  345.                                                         strlen(right) + 1));
  346.         (void)sprintf( rval, "%s%s%s", left, tvalue, right );
  347.         free( tmp );
  348.         tmp = rval;
  349.     }
  350.  
  351.     return( tmp );
  352. }
  353.  
  354. get_var( value, leftp, namep, rightp )
  355. register char *value, **leftp, **namep, **rightp;
  356. {
  357.     char *left, *left_end, *name, *right;
  358.     char *tvalue;
  359.  
  360.     tvalue = value;
  361.     left = value;
  362.  
  363.     for(;;) {
  364. tryagain:
  365.         value = index( tvalue, '$' );
  366.         if( value == NULL ) {
  367.             return( 0 );
  368.         }
  369.  
  370.         if( *++value == '(' ) {
  371.             left_end = value - 1;
  372.             name = ++value;
  373.             while( *value && *value != ')' ) {
  374.                 char c = *value++;
  375.                 if( !ISIDCHAR(c) ) {
  376.                     tvalue = name;
  377.                     goto tryagain;
  378.                 }
  379.             }
  380.  
  381.             if( *value == ')' ) {
  382.                 right = value;
  383.                 break;
  384.             } else {
  385.                 tvalue = name;
  386.                 goto tryagain;
  387.             }
  388.         } else {
  389.             tvalue = value;
  390.             goto tryagain;
  391.         }
  392.     }
  393.  
  394.     *left_end = '\0';
  395.     *right++ = '\0';
  396.  
  397.     *leftp = left;
  398.     *namep = name;
  399.     *rightp = right;
  400.  
  401.     return( 1 );
  402. }
  403.  
  404. /*
  405. ** Return the value associated with the named parameter.  Return NULL
  406. ** if the given parameter is not defined.
  407. */
  408. char *
  409. lookup_macro( name, table, table_size )
  410. char    *name;
  411. BUCKET    *table[];
  412. int        table_size;
  413. {
  414.     int                loc;
  415.     register BUCKET    *ptr;
  416.  
  417.     lower_case( name );
  418.     loc = hash( name, table_size );
  419.     for( ptr=table[loc]; ptr; ptr=ptr->next ) {
  420.         if( !strcmp(name,ptr->name) )
  421.             return ptr->value;
  422.     }
  423.     return NULL;
  424. }
  425.