home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1998 February / PCOnline_02_1998.iso / filesbbs / os2 / pgp263.arj / PGP263I.SRC / PGP263II.ZIP / src / config.c < prev    next >
C/C++ Source or Header  |  1996-01-09  |  19KB  |  751 lines

  1. /*    config.c  - config file parser by Peter Gutmann
  2.     Parses config file for PGP
  3.  
  4.     (c) Copyright 1990-1996 by Philip Zimmermann.  All rights reserved.
  5.     The author assumes no liability for damages resulting from the use
  6.     of this software, even if the damage results from defects in this
  7.     software.  No warranty is expressed or implied.
  8.  
  9.     Note that while most PGP source modules bear Philip Zimmermann's
  10.     copyright notice, many of them have been revised or entirely written
  11.     by contributors who frequently failed to put their names in their
  12.     code.  Code that has been incorporated into PGP from other authors
  13.     was either originally published in the public domain or is used with
  14.     permission from the various authors.
  15.  
  16.     PGP is available for free to the public under certain restrictions.
  17.     See the PGP User's Guide (included in the release package) for
  18.     important information about licensing, patent restrictions on
  19.     certain algorithms, trademarks, copyrights, and export controls.
  20.  
  21.     Modified 24 Jun 92 - HAJK
  22.     Misc fixes for VAX C restrictions
  23.  
  24.     Updated by Peter Gutmann to only warn about unrecognized options,
  25.     so future additions to the config file will give old versions a
  26.     chance to still run.  A number of code cleanups, too.  */
  27.  
  28. #include <ctype.h>
  29. #include <string.h>
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <limits.h>
  33. #include "usuals.h"
  34. #include "fileio.h"
  35. #include "language.h"    /*added by Naoki */
  36. #include "pgp.h"
  37. #include "config.h"
  38. #include "charset.h"
  39.  
  40. /* Various maximum/minimum allowable settings for config options */
  41.  
  42. #define MIN_MARGINALS    1
  43. #define MIN_COMPLETE    1
  44. #define MAX_COMPLETE    4
  45. #define MIN_CERT_DEPTH    0
  46. #define MAX_CERT_DEPTH    8
  47.  
  48. /* Prototypes for local functions */
  49.  
  50. static int lookup( char *key, int keyLength, char *keyWords[], int range );
  51. static int extractToken( char *buffer, int *endIndex, int *length );
  52. static int getaString( char *buffer, int *endIndex );
  53. static int getAssignment( char *buffer, int *endIndex, INPUT_TYPE settingType );
  54. static void processAssignment( int intrinsicIndex );
  55.  
  56. /* The external config variables we can set here are referenced in pgp.h */
  57.  
  58. /* Return values */
  59.  
  60. #define ERROR    -1
  61. #define OK        0
  62.  
  63. /* The types of error we check for */
  64.  
  65. enum { NO_ERROR, ILLEGAL_CHAR_ERROR, LINELENGTH_ERROR };
  66.  
  67. #define CPM_EOF        0x1A    /* ^Z = CPM EOF char */
  68.  
  69. #define MAX_ERRORS    3    /* Max.no.errors before we give up */
  70.  
  71. #define LINEBUF_SIZE    100    /* Size of input buffer */
  72.  
  73. static int line;        /* The line on which an error occurred */
  74. static int errCount;        /* Total error count */
  75. static boolean hasError;    /* Whether this line has an error in it */
  76.  
  77. /* The settings parsed out by getAssignment() */
  78.  
  79. static char str[ LINEBUF_SIZE ];
  80. static int value;
  81. static char *errtag;        /* Prefix for printing error messages */
  82. static char optstr[ 100 ];    /* Option being processed */
  83. #ifdef MACTC5
  84. extern boolean use_ftypes, wipe_warning, recycle_passwd;
  85. #endif
  86.  
  87. /* A .CFG file roughly follows the format used in the world-famous HPACK
  88.    archiver and is as follows:
  89.  
  90.     - Leading spaces/tabs (whitespace) are ignored.
  91.  
  92.     - Lines with a '#' as the first non-whitespace character are treated
  93.       as comment lines.
  94.  
  95.     - All other lines are treated as config options for the program.
  96.  
  97.     - Lines may be terminated by either linefeeds, carriage returns, or
  98.       carriage return/linefeed pairs (the latter being the DOS default
  99.       method of storing text files).
  100.  
  101.     - Config options have the form:
  102.  
  103.       <option> '=' <setting>
  104.  
  105.       where <setting> may be 'on', 'off', a numeric value, or a string
  106.       value.
  107.  
  108.     - If strings have spaces or the '#' character inside them they must be
  109.       surrounded by quote marks '"' */
  110.  
  111. /* Intrinsic variables */
  112.  
  113. #define NO_INTRINSICS        (sizeof(intrinsics) / sizeof(intrinsics[0]))
  114. #define CONFIG_INTRINSICS    BATCHMODE
  115.  
  116. enum {
  117.     ARMOR, COMPRESS, SHOWPASS, KEEPBINARY, LANGUAGE,
  118.     MYNAME, TEXTMODE, TMP, TZFIX, VERBOSE, BAKRING,
  119.     ARMORLINES, COMPLETES_NEEDED, MARGINALS_NEEDED, PAGER,
  120.     CERT_DEPTH, CHARSET, CLEARSIG, SELF_ENCRYPT,
  121.     INTERACTIVE, PUBRING, SECRING, RANDSEED,
  122.     COMMENT, AUTOSIGN,
  123.         LEGAL_KLUDGE,
  124. #ifdef MACTC5
  125.     FILE_TYPES, WIPE_WARNING, RECYCLE_PASSWD, MULTIPLE_RECIPIENTS,
  126. #endif
  127.     /* options below this line can only be used as command line
  128.      * "long" options */
  129.     BATCHMODE, FORCE, NOMANUAL, MAKERANDOM
  130.     };
  131.  
  132. static char *intrinsics[] = {
  133.     "ARMOR", "COMPRESS", "SHOWPASS", "KEEPBINARY", "LANGUAGE",
  134.     "MYNAME", "TEXTMODE", "TMP", "TZFIX", "VERBOSE", "BAKRING",
  135.     "ARMORLINES", "COMPLETES_NEEDED", "MARGINALS_NEEDED", "PAGER",
  136.     "CERT_DEPTH", "CHARSET", "CLEARSIG", "ENCRYPTTOSELF", 
  137.     "INTERACTIVE", "PUBRING", "SECRING", "RANDSEED",
  138.     "COMMENT", "AUTOSIGN", 
  139.         "LEGAL_KLUDGE",
  140. #ifdef MACTC5
  141.     "FILE_TYPES", "WIPE_WARNING", "RECYCLE_PASSWORDS", "MULTIPLE_RECIPIENTS",
  142. #endif
  143.     /* command line only */
  144.     "BATCHMODE", "FORCE", "NOMANUAL", "MAKERANDOM"
  145.     };
  146.  
  147. static INPUT_TYPE intrinsicType[] = {
  148.     BOOL, BOOL, BOOL, BOOL, STRING,
  149.     STRING, BOOL, STRING, NUMERIC, NUMERIC, STRING,
  150.     NUMERIC, NUMERIC, NUMERIC, STRING,
  151.     NUMERIC, STRING, BOOL, BOOL,
  152.     BOOL, STRING, STRING, STRING,
  153.     STRING, BOOL,
  154.         BOOL,
  155. #ifdef MACTC5
  156.     BOOL, BOOL, BOOL, BOOL,
  157. #endif
  158.     /* command line only */
  159.     BOOL, BOOL, BOOL, NUMERIC
  160.     };
  161.  
  162. /* Possible settings for variables */
  163.  
  164. #define NO_SETTINGS            2
  165.  
  166. static char *settings[] = { "OFF", "ON" };
  167.  
  168. /* Search a list of keywords for a match */
  169.  
  170. static int lookup( char *key, int keyLength, char *keyWords[], int range )
  171. {
  172.     int index, position = 0, noMatches = 0;
  173.  
  174.     strncpy( optstr, key, keyLength );
  175.     optstr[ keyLength ] = '\0';
  176.  
  177.     /* Make the search case insensitive */
  178.     for( index = 0; index < keyLength; index++ )
  179.         key[ index ] = to_upper( key[ index ] );
  180.  
  181.     for( index = 0; index < range; index++ )
  182.         if( !strncmp( key, keyWords[ index ], keyLength ) )
  183.             {
  184.             if( strlen( keyWords[ index ] ) == keyLength )
  185.                 return index;    /* exact match */
  186.             position = index;
  187.             noMatches++;
  188.             }
  189.  
  190.     switch( noMatches )
  191.         {
  192.         case 0:
  193.             fprintf( stderr, "%s: unknown keyword: \"%s\"\n",
  194.                      errtag, optstr );
  195.             break;
  196.         case 1:
  197.             return( position );    /* Match succeeded */
  198.         default:
  199.             fprintf( stderr, "%s: \"%s\" is ambiguous\n",
  200.                      errtag, optstr );
  201.         }
  202.     return ERROR;
  203. }
  204.  
  205. /* Extract a token from a buffer */
  206.  
  207. static int extractToken( char *buffer, int *endIndex, int *length )
  208. {
  209.     int index = 0, tokenStart;
  210.     char ch;
  211.  
  212.     /* Skip whitespace */
  213.     for( ch = buffer[ index ]; ch && ( ch == ' ' || ch == '\t' );
  214.          ch = buffer[ index ] )
  215.         index++;
  216.     tokenStart = index;
  217.  
  218.     /* Find end of setting */
  219.     while( index < LINEBUF_SIZE && ( ch = buffer[ index ] ) != '\0'
  220.            && ch != ' ' && ch != '\t' )
  221.         index++;
  222.     *endIndex += index;
  223.     *length = index - tokenStart;
  224.  
  225.     /* Return start position of token in buffer */
  226.     return tokenStart;
  227. }
  228.  
  229. /* Get a string constant */
  230.  
  231. static int getaString( char *buffer, int *endIndex )
  232.     {
  233.     boolean noQuote = FALSE;
  234.     int stringIndex = 0, bufferIndex = 1;
  235.     char ch = *buffer;
  236.  
  237.     /* Skip whitespace */
  238.     while( ch && ( ch == ' ' || ch == '\t' ) )
  239.         ch = buffer[ bufferIndex++ ];
  240.  
  241.     /* Check for non-string */
  242.     if( ch != '\"' )
  243.         {
  244.         *endIndex += bufferIndex;
  245.  
  246.         /* Check for special case of null string */
  247.         if( !ch )
  248.             {
  249.             *str = '\0';
  250.             return OK;
  251.             }
  252.  
  253.         /* Use nasty non-rigorous string format */
  254.         noQuote = TRUE;
  255.         }
  256.  
  257.     /* Get first char of string */
  258.     if( !noQuote )
  259.         ch = buffer[ bufferIndex++ ];
  260.  
  261.     /* Get string into string */
  262.     while( ch && ch != '\"' )
  263.         {
  264.         /* Exit on '#' if using non-rigorous format */
  265.         if( noQuote && ch == '#' )
  266.             break;
  267.  
  268.         str[ stringIndex++ ] = ch;
  269.         ch = buffer[ bufferIndex++ ];
  270.         }
  271.  
  272.     /* If using the non-rigorous format, stomp trailing spaces */
  273.     if( noQuote )
  274.         while( stringIndex > 0 && str[ stringIndex - 1 ] == ' ' )
  275.             stringIndex--;
  276.  
  277.     str[ stringIndex++ ] = '\0';
  278.     *endIndex += bufferIndex;
  279.  
  280.     /* Check for missing string terminator */
  281.     if( ch != '\"' && !noQuote )
  282.         {
  283.         if( line )
  284.             fprintf( stderr, "%s: unterminated string in line %d\n",
  285.                      errtag, line );
  286.         else
  287.             fprintf( stderr, "unterminated string: '\"%s'\n", str );
  288.         hasError = TRUE;
  289.         errCount++;
  290.         return ERROR;
  291.         }
  292.  
  293.     return OK;
  294. }
  295.  
  296. /* Get an assignment to an intrinsic */
  297.  
  298. static int getAssignment( char *buffer, int *endIndex, INPUT_TYPE settingType )
  299. {
  300.     int settingIndex = 0, length;
  301.     long longval;
  302.     char *p;
  303.  
  304.     buffer += extractToken( buffer, endIndex, &length );
  305.  
  306.     /* Check for an assignment operator */
  307.     if( *buffer != '=' )
  308.         {
  309.         if( line )
  310.             fprintf( stderr, "%s: expected '=' in line %d\n",
  311.                      errtag, line );
  312.         else
  313.             fprintf( stderr, "%s: expected '=' after \"%s\"\n",
  314.                      errtag, optstr);
  315.         hasError = TRUE;
  316.         errCount++;
  317.         return ERROR;
  318.         }
  319.     buffer++;    /* Skip '=' */
  320.  
  321.     buffer += extractToken( buffer, endIndex, &length );
  322.  
  323.     switch( settingType )
  324.         {
  325.         case BOOL:
  326.             /* Check for known intrinsic - really more general
  327.                than just checking for TRUE or FALSE */
  328.             settingIndex = lookup( buffer, length, settings,
  329.                                    NO_SETTINGS );
  330.             if( settingIndex == ERROR )
  331.                 {
  332.                 hasError = TRUE;
  333.                 errCount++;
  334.                 return ERROR;
  335.                 }
  336.  
  337.             value = ( settingIndex == 0 ) ? FALSE : TRUE;
  338.             break;
  339.  
  340.         case STRING:
  341.             /* Get a string */
  342.             getaString( buffer, &length );
  343.             break;
  344.  
  345.         case NUMERIC:
  346.             longval = strtol(buffer, &p, 0);
  347.             if (p == buffer+length &&
  348.                 longval <= INT_MAX && longval >= INT_MIN) {
  349.                 value = (int)longval;
  350.                 break;
  351.             }
  352.             if( line )
  353.                 fprintf( stderr,
  354.                   "%s: numeric argument expected in line %d\n",
  355.                          errtag, line );
  356.             else
  357.                 fprintf( stderr,
  358.                    "%s: numeric argument required for \"%s\"\n",
  359.                          errtag, optstr);
  360.             hasError = TRUE;
  361.             errCount++;
  362.             return ERROR;
  363.         }
  364.  
  365.     return settingIndex;
  366. }
  367.  
  368. /* Process an assignment */
  369.  
  370. static void processAssignment( int intrinsicIndex )
  371.     {
  372.     if( !hasError )
  373.         switch( intrinsicIndex )
  374.             {
  375.             case ARMOR:
  376.                 emit_radix_64 = value;
  377.                 break;
  378.  
  379.             case ARMORLINES:
  380.                 pem_lines = value;
  381.                 break;
  382.  
  383.             case AUTOSIGN:
  384.                 sign_new_userids = value;
  385.                 break;
  386.  
  387.             case BAKRING:
  388.                 strcpy( floppyring, str );
  389.                 break;
  390.  
  391.             case BATCHMODE:
  392.                 batchmode = value;
  393.                 break;
  394.  
  395.             case CERT_DEPTH:
  396.                 max_cert_depth = value;
  397.                 if( max_cert_depth < MIN_CERT_DEPTH )
  398.                     max_cert_depth = MIN_CERT_DEPTH;
  399.                 if( max_cert_depth > MAX_CERT_DEPTH )
  400.                     max_cert_depth = MAX_CERT_DEPTH;
  401.                 break;
  402.  
  403.             case CHARSET:
  404.                 strncpy( charset, str, 16 );
  405.                 break;
  406.  
  407.             case CLEARSIG:
  408.                 clear_signatures = value;
  409.                 break;
  410.  
  411.             case COMMENT:
  412.                 strcpy( globalCommentString, str );
  413.                 break;
  414.  
  415.             case COMPLETES_NEEDED:
  416.                 compl_min = value;
  417.                 /* Keep within range */
  418.                 if( compl_min < MIN_COMPLETE )
  419.                     compl_min = MIN_COMPLETE;
  420.                 if( compl_min > MAX_COMPLETE )
  421.                     compl_min = MAX_COMPLETE;
  422.                 break;
  423.  
  424.             case COMPRESS:
  425.                 compress_enabled = value;
  426.                 break;
  427.  
  428.             case FORCE:
  429.                 force_flag = value;
  430.                 break;
  431.  
  432.             case INTERACTIVE:
  433.                 interactive_add = value;
  434.                 break;
  435.  
  436.             case KEEPBINARY:
  437.                 keepctx = value;
  438.                 break;
  439.  
  440.             case LANGUAGE:
  441.                 strncpy( language, str, 15 );
  442.                 break;
  443.  
  444.             case LEGAL_KLUDGE:
  445.                 if (!value)
  446. #ifdef USA
  447.                                         fprintf(stdout,
  448. LANG("The legal_kludge cannot be disabled in US version.\n"));
  449. #else
  450.                     version_byte = VERSION_BYTE_OLD;
  451. #endif
  452.                 break;
  453.  
  454.             case MAKERANDOM:
  455.                 makerandom = value;
  456.                 break;
  457. #ifdef MACTC5                
  458.             case FILE_TYPES:
  459.                 use_ftypes = value;
  460.                 break;
  461.             
  462.             case WIPE_WARNING:
  463.                 wipe_warning = value;
  464.                 break;
  465.             
  466.             case RECYCLE_PASSWD:
  467.                 recycle_passwd = value;
  468.                 break;
  469.  
  470.             case MULTIPLE_RECIPIENTS:
  471.                 fprintf(stdout, LANG("The multiple_recipients flag is unnecessary in this \
  472. version of MacPGP.\
  473. \nPlease remove this entry from your configuration file.\n"));
  474.                 break;
  475. #endif
  476.  
  477.             case MARGINALS_NEEDED:
  478.                 marg_min = value;
  479.                 /* Keep within range */
  480.                 if( marg_min < MIN_MARGINALS )
  481.                     marg_min = MIN_MARGINALS;
  482.                 break;
  483.  
  484.             case MYNAME:
  485.                 strcpy( my_name, str );
  486. #ifdef EBCDIC
  487.     CONVERT_TO_CANONICAL_CHARSET(my_name);
  488. #endif
  489.                 break;
  490.  
  491.             case NOMANUAL:
  492.                 nomanual = value;
  493.                 break;
  494.  
  495.             case PAGER:
  496.                 strcpy( pager, str );
  497.                 break;
  498.  
  499.             case PUBRING:
  500.                 strcpy( globalPubringName, str );
  501.                 break;
  502.  
  503.             case RANDSEED:
  504.                 strcpy( globalRandseedName, str );
  505.                 break;
  506.  
  507.             case SECRING:
  508.                 strcpy( globalSecringName, str );
  509.                 break;
  510.  
  511.             case SELF_ENCRYPT:
  512.                 encrypt_to_self = value;
  513.                 break;
  514.  
  515.             case SHOWPASS:
  516.                 showpass = value;
  517.                 break;
  518.  
  519.             case TEXTMODE:
  520.                 if( value )
  521.                     literal_mode = MODE_TEXT;
  522.                 else
  523.                     literal_mode = MODE_BINARY;
  524.                 break;
  525.  
  526.             case TMP:
  527.                 /* directory pathname to store temp files */
  528.                 settmpdir( str );
  529.                 break;
  530.  
  531.             case TZFIX:
  532.                 /* How many hours to add to time() to get GMT.
  533.                    We just compute the seconds from hours to
  534.                    get the GMT shift */
  535.                 timeshift = 3600L * ( long ) value;
  536.                 break;
  537.  
  538.             case VERBOSE:
  539.                 if( value < 1 )
  540.                     {
  541.                     quietmode = TRUE;
  542.                     verbose = FALSE;
  543.                     }
  544.                 else
  545.                     if( value == 1 )
  546.                         {
  547.                         quietmode = FALSE;
  548.                         verbose = FALSE;
  549.                         }
  550.                     else
  551.                         {
  552.                         /* Value > 1 */
  553.                         quietmode = FALSE;
  554.                         verbose = TRUE;
  555.                         }
  556.                 break;
  557.  
  558.             }
  559. }
  560.  
  561. /* Process an option on a line by itself.  This expects options which are
  562.    taken from the command-line, and is less finicky about errors than the
  563.    config-file version */
  564.  
  565. int processConfigLine( char *option )
  566. {
  567.     int index, intrinsicIndex;
  568.     char ch;
  569.  
  570.     /* Give it a pseudo-linenumber of 0 */
  571.     line = 0;
  572.  
  573.     errtag = "pgp";
  574.     errCount = 0;
  575.     for( index = 0;
  576.          index < LINEBUF_SIZE && ( ch = option[ index ] ) != '\0' &&
  577.                 ch != ' ' && ch != '\t' && ch != '=';
  578.          index++ );
  579.     if( ( intrinsicIndex = lookup( ( char * ) option, index, intrinsics,
  580.                       NO_INTRINSICS ) ) == ERROR )
  581.         return -1;
  582.     if( option[ index ] == '\0' && intrinsicType[ intrinsicIndex ] == BOOL)
  583.         {
  584.         /* Boolean option, no '=' means TRUE */
  585.         value = TRUE;
  586.         processAssignment( intrinsicIndex );
  587.         }
  588.     else
  589.         /* Get the value to set to, either as a string, a numeric
  590.            value, or a boolean flag */
  591.         if( getAssignment( ( char * ) option + index,
  592.                &index, intrinsicType[ intrinsicIndex ] ) != ERROR )
  593.             processAssignment( intrinsicIndex );
  594.  
  595.     return errCount ? -1 : 0;
  596. }
  597.  
  598. /* Process a configuration file */
  599.  
  600. int processConfigFile( char *configFileName )
  601. {
  602.     FILE *configFilePtr;
  603.     int ch = 0, theChar;
  604.     int errType, errPos = 0, lineBufCount, intrinsicIndex;
  605.     int index;
  606.     char inBuffer[ LINEBUF_SIZE ];
  607.  
  608.     line = 1;
  609.     errCount = 0;
  610.     errtag = file_tail( configFileName );
  611.  
  612.     if( ( configFilePtr = fopen( configFileName, FOPRTXT ) ) == NULL )
  613.         {
  614.         fprintf( stderr, "Cannot open configuration file %s\n",
  615.                  configFileName );
  616.         return OK;    /* Treat it as if it were an empty file */
  617.         }
  618.  
  619.     /* Process each line in the configFile */
  620.     while( ch != EOF )
  621.         {
  622.         /* Skip whitespace */
  623.         while( ( ( ch = getc( configFilePtr ) ) == ' ' || ch == '\t' )
  624.               && ch != EOF )
  625.             ;
  626.  
  627.         /* Get a line into the inBuffer */
  628.         hasError = FALSE;
  629.         lineBufCount = 0;
  630.         errType = NO_ERROR;
  631.         while( ch != '\r' && ch != '\n' && ch != CPM_EOF && ch != EOF )
  632.             {
  633.             /* Check for an illegal char in the data */
  634. #ifdef EBCDIC
  635.             if( iscntrl(ch) && !isspace(ch) && ch != EOF )
  636. #else
  637.             if( ( ch < ' ' || ch > '~' ) &&
  638.                   ch != '\r' && ch != '\n' &&
  639.                   ch != ' ' && ch != '\t' && ch != CPM_EOF &&
  640.                   ch != EOF )
  641. #endif
  642.                 {
  643.                 if( errType == NO_ERROR )
  644.                     /* Save pos of first illegal char */
  645.                     errPos = lineBufCount;
  646.                 errType = ILLEGAL_CHAR_ERROR;
  647.                 }
  648.  
  649.             /* Make sure the path is of the correct length.  Note
  650.                that the code is ordered so that a LINELENGTH_ERROR
  651.                takes precedence over an ILLEGAL_CHAR_ERROR */
  652.             if( lineBufCount > LINEBUF_SIZE )
  653.                 errType = LINELENGTH_ERROR;
  654.             else
  655.                 inBuffer[ lineBufCount++ ] = ch;
  656.  
  657.             if( ( ch = getc( configFilePtr ) ) == '#' )
  658.                 {
  659.                 /* Skip comment section and trailing
  660.                    whitespace */
  661.                 while( ch != '\r' && ch != '\n' &&
  662.                        ch != CPM_EOF && ch != EOF )
  663.                   ch = getc( configFilePtr );
  664.                 break;
  665.                 }
  666.             }
  667.  
  668.         /* Skip trailing whitespace and add der terminador */
  669.         while( lineBufCount &&
  670.                ( ( theChar = inBuffer[ lineBufCount - 1 ] ) == ' ' ||
  671.                theChar == '\t' ) )
  672.           lineBufCount--;
  673.         inBuffer[ lineBufCount ] = '\0';
  674.  
  675.         /* Process the line unless its a blank or comment line */
  676.         if( lineBufCount && *inBuffer != '#' )
  677.             {
  678.             switch( errType )
  679.                 {
  680.                 case LINELENGTH_ERROR:
  681.                     fprintf( stderr,
  682.                         "%s: line '%.30s...' too long\n",
  683.                              errtag, inBuffer );
  684.                     errCount++;
  685.                     break;
  686.  
  687.                 case ILLEGAL_CHAR_ERROR:
  688.                     fprintf( stderr, "> %s\n  ", inBuffer );
  689.                     fprintf( stderr, "%*s^\n", errPos, "" );
  690.                     fprintf( stderr,
  691.                     "%s: bad character in command on line %d\n",
  692.                              errtag, line );
  693.                     errCount++;
  694.                     break;
  695.  
  696.                 default:
  697.                     for( index = 0;
  698.                          index < LINEBUF_SIZE &&
  699.                          ( ch = inBuffer[ index ] ) != '\0'
  700.                          && ch != ' ' && ch != '\t'
  701.                          && ch != '=';
  702.                          index++ )
  703.                         /*Do nothing*/ ;
  704.  
  705.                     /* Try and find the intrinsic.  We
  706.                        don't treat unknown intrinsics as
  707.                        an error to allow older versions to
  708.                        be used with new config files */
  709.                     intrinsicIndex = lookup(inBuffer,
  710.                         index, intrinsics,
  711.                         CONFIG_INTRINSICS );
  712.                 
  713.                     if( intrinsicIndex == ERROR )
  714.                         break;
  715.  
  716.                     /* Get the value to set to, either as
  717.                        a string, a numeric value, or a
  718.                        boolean flag */
  719.                     getAssignment( inBuffer + index, &index,
  720.                          intrinsicType[ intrinsicIndex ] );
  721.                     processAssignment( intrinsicIndex );
  722.                     break;
  723.                 }
  724.             }
  725.  
  726.         /* Handle special-case of ^Z if configFile came off an
  727.            MSDOS system */
  728.         if( ch == CPM_EOF )
  729.             ch = EOF;
  730.  
  731.         /* Exit if there are too many errors */
  732.         if( errCount >= MAX_ERRORS )
  733.             break;
  734.  
  735.         line++;
  736.         }
  737.  
  738.     fclose( configFilePtr );
  739.  
  740.     /* Exit if there were errors */
  741.     if( errCount )
  742.         {
  743.         fprintf( stderr, "%s: %s%d error(s) detected\n\n",
  744.                  configFileName, ( errCount >= MAX_ERRORS ) ?
  745.                  "Maximum level of " : "", errCount );
  746.         return ERROR;
  747.         }
  748.  
  749.     return OK;
  750. }
  751.