This is config.c in view mode; [Download] [Up]
/* config.c - config file parser by Peter Gutmann Parses config file for PGP Modified 24 Jun 92 - HAJK Misc fixes for VAX C restrictions. */ #include <ctype.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include "usuals.h" #include "fileio.h" #include "pgp.h" #include "config.h" #include "charset.h" static int lookup( char *key, int keyLength, char *keyWords[], int range ); static int extractToken( char *buffer, int *endIndex, int *length ); static int getaString( char *buffer, int *endIndex ); static int getAssignment( char *buffer, int *endIndex, INPUT_TYPE settingType ); static void processAssignment( int intrinsicIndex ); /* The external config variables we can set here are referenced in pgp.h */ /* Return values */ #define ERROR -1 #define OK 0 /* The types of error we check for */ enum { NO_ERROR, ILLEGAL_CHAR_ERROR, LINELENGTH_ERROR }; #define CPM_EOF 0x1A /* ^Z = CPM EOF char */ #define MAX_ERRORS 3 /* Max.no.errors before we give up */ #define LINEBUF_SIZE 100 /* Size of input buffer */ static int line; /* The line on which an error occurred */ static int errCount; /* Total error count */ static boolean hasError; /* Whether this line has an error in it */ /* The settings parsed out by getAssignment() */ static char str[ LINEBUF_SIZE ]; static int value; static boolean flag; static char *errtag; /* prefix for printing error messages */ static char optstr[100]; /* option being processed */ /* A .CFG file roughly follows the format used in the world-famous HPACK archiver and is as follows: - Leading spaces/tabs (whitespace) are ignored. - Lines with a '#' as the first non-whitespace character are treated as comment lines. - All other lines are treated as config options for the program. - Lines may be terminated by either linefeeds, carriage returns, or carriage return/linefeed pairs (the latter being the DOS default method of storing text files). - Config options have the form: <option> '=' <setting> where <setting> may be 'on', 'off', a numeric value, or a string value. - If strings have spaces or the '#' character inside them they must be surrounded by quote marks '"' */ /* Intrinsic variables */ #define NO_INTRINSICS (sizeof(intrinsics) / sizeof(intrinsics[0])) enum { ARMOR, COMPRESS, SHOWPASS, KEEPBINARY, LANGUAGE, MYNAME, TEXTMODE, TMP, TZFIX, VERBOSE, BAKRING, ARMORLINES, COMPLETES_NEEDED, MARGINALS_NEEDED, PAGER, CERT_DEPTH, CHARSET, CLEAR, SELF_ENCRYPT, INTERACTIVE, PKCS_COMPAT, ARMOR_VERSION, VERSION_BYTE, /* options below this line can only be used as command line * "long" options */ #define CONFIG_INTRINSICS BATCHMODE BATCHMODE, FORCE }; static char *intrinsics[] = { "ARMOR", "COMPRESS", "SHOWPASS", "KEEPBINARY", "LANGUAGE", "MYNAME", "TEXTMODE", "TMP", "TZFIX", "VERBOSE", "BAKRING", "ARMORLINES", "COMPLETES_NEEDED", "MARGINALS_NEEDED", "PAGER", "CERT_DEPTH", "CHARSET", "CLEARSIG", "ENCRYPTTOSELF", "INTERACTIVE", "PKCS_COMPAT", "ARMOR_VERSION", "VERSION_BYTE", /* command line only */ "BATCHMODE", "FORCE", }; static INPUT_TYPE intrinsicType[] = { BOOL, BOOL, BOOL, BOOL, STRING, STRING, BOOL, STRING, NUMERIC, NUMERIC, STRING, NUMERIC, NUMERIC, NUMERIC, STRING, NUMERIC, STRING, BOOL, BOOL, BOOL, NUMERIC, STRING, NUMERIC, /* command line only */ BOOL, BOOL, }; /* Possible settings for variables */ #define NO_SETTINGS 2 static char *settings[] = { "OFF", "ON" }; /* Search a list of keywords for a match */ static int lookup( char *key, int keyLength, char *keyWords[], int range ) { int indx, pos = 0, matches = 0; strncpy(optstr, key, keyLength); optstr[keyLength] = '\0'; /* Make the search case insensitive */ for( indx = 0; indx < keyLength; indx++ ) key[ indx ] = to_upper( key[ indx ] ); for( indx = 0; indx < range; indx++ ) if( !strncmp( key, keyWords[ indx ], keyLength ) ) { if (strlen(keyWords[indx]) == keyLength) return indx; /* exact match */ pos = indx; ++matches; } switch (matches) { case 0: fprintf(stderr, "%s: unknown keyword: \"%s\"\n", errtag, optstr); break; case 1: return pos; default: fprintf(stderr, "%s: \"%s\" is ambiguous\n", errtag, optstr); } return ERROR; } /* Extract a token from a buffer */ static int extractToken( char *buffer, int *endIndex, int *length ) { int indx = 0, tokenStart; char ch; /* Skip whitespace */ for( ch = buffer[ indx ]; ch && ( ch == ' ' || ch == '\t' ); ch = buffer[ indx ] ) indx++; tokenStart = indx; /* Find end of setting */ while( indx < LINEBUF_SIZE && ( ch = buffer[ indx ] ) != '\0' && ch != ' ' && ch != '\t' ) indx++; *endIndex += indx; *length = indx - tokenStart; /* Return start position of token in buffer */ return( tokenStart ); } /* Get a string constant */ static int getaString( char *buffer, int *endIndex ) { boolean noQuote = FALSE; int stringIndex = 0, bufIndex = 1; char ch = *buffer; /* Skip whitespace */ while( ch && ( ch == ' ' || ch == '\t' ) ) ch = buffer[ bufIndex++ ]; /* Check for non-string */ if( ch != '\"' ) { *endIndex += bufIndex; /* Check for special case of null string */ if( !ch ) { *str = '\0'; return( OK ); } /* Use nasty non-rigorous string format */ noQuote = TRUE; } /* Get first char of string */ if( !noQuote ) ch = buffer[ bufIndex++ ]; /* Get string into string */ while( ch && ch != '\"' ) { /* Exit on '#' if using non-rigorous format */ if( noQuote && ch == '#' ) break; str[ stringIndex++ ] = ch; ch = buffer[ bufIndex++ ]; } /* If using the non-rigorous format, stomp trailing spaces */ if( noQuote ) while( stringIndex > 0 && str[ stringIndex - 1 ] == ' ' ) stringIndex--; str[ stringIndex++ ] = '\0'; *endIndex += bufIndex; /* Check for missing string terminator */ if( ch != '\"' && !noQuote ) { if (line) fprintf(stderr, "%s: unterminated string in line %d\n", errtag, line ); else fprintf(stderr, "unterminated string: '\"%s'\n", str ); hasError = TRUE; errCount++; return( ERROR ); } return( OK ); } /* Get an assignment to an intrinsic */ static int getAssignment( char *buffer, int *endIndex, INPUT_TYPE settingType ) { int settingIndex = 0, length; buffer += extractToken( buffer, endIndex, &length ); /* Check for an assignment operator */ if ( *buffer != '=' ) { if (line) fprintf(stderr, "%s: expected '=' in line %d\n", errtag, line ); else fprintf(stderr, "%s: expected '=' after \"%s\"\n", errtag, optstr); hasError = TRUE; errCount++; return( ERROR ); } buffer++; /* Skip '=' */ buffer += extractToken( buffer, endIndex, &length ); switch( settingType ) { case BOOL: /* Check for known intrinsic - really more general than just checking for TRUE or FALSE */ if( ( settingIndex = lookup( buffer, length, settings, NO_SETTINGS ) ) == ERROR ) { hasError = TRUE; errCount++; return( ERROR ); } flag = ( settingIndex == 0 ) ? FALSE : TRUE; break; case STRING: /* Get a string */ getaString( buffer, &length ); break; case NUMERIC: /* Get numeric input. Error checking is a pain since atoi() has no real equivalent of NAN */ value = atoi( buffer ); break; } return( settingIndex ); } /* Process an assignment */ static void processAssignment( int intrinsicIndex ) { if( !hasError ) switch( intrinsicIndex ) { case ARMOR: emit_radix_64 = flag; break; case COMPRESS: compress_enabled = flag; break; case SHOWPASS: showpass = flag; break; case KEEPBINARY: keepctx = flag; break; case LANGUAGE: strncpy(language, str, 15); break; case BAKRING: strcpy(floppyring, str); break; case MYNAME: strcpy(my_name, str); break; case TEXTMODE: if( flag ) literal_mode = MODE_TEXT; else literal_mode = MODE_BINARY; break; case TMP: /* directory pathname to store temp files */ settmpdir(str); break; case TZFIX: /* How many hours to add to time() to get GMT. */ /* Compute seconds from hours to shift to GMT: */ timeshift = 3600L * (long) value; break; case VERBOSE: switch (value) { case 0: quietmode = TRUE; verbose = FALSE; break; case 1: quietmode = FALSE; verbose = FALSE; break; case 2: quietmode = FALSE; verbose = TRUE; break; default: quietmode = FALSE; verbose = FALSE; } break; case ARMORLINES: pem_lines = value; break; case MARGINALS_NEEDED: marg_min = value; if (marg_min < 1) marg_min = 1; break; case COMPLETES_NEEDED: compl_min = value; if (compl_min < 1) compl_min = 1; if (compl_min > 4) compl_min = 4; break; case CERT_DEPTH: max_cert_depth = value; if (max_cert_depth < 0) max_cert_depth = 0; if (max_cert_depth > 8) max_cert_depth = 8; break; case PAGER: strcpy(pager, str); break; case CHARSET: strcpy(charset, str); break; case CLEAR: clear_signatures = flag; break; case SELF_ENCRYPT: encrypt_to_self = flag; break; case INTERACTIVE: interactive_add = flag; break; case ARMOR_VERSION: strncpy(armor_version, str, MAX_VERSION_LENGTH); armor_version[MAX_VERSION_LENGTH-1] = '\0'; break; case VERSION_BYTE: version_byte = value; if (version_byte < VERSION_BYTE_MIN) version_byte = VERSION_BYTE_MIN; if (version_byte > VERSION_BYTE_MAX) version_byte = VERSION_BYTE_MAX; break; case BATCHMODE: batchmode = flag; break; case FORCE: force_flag = flag; break; case PKCS_COMPAT: pkcs_compat = value; break; } } /* Process an option on a line by itself. This expects options which are taken from the command-line, and is less finicky about errors than the config-file version */ int processConfigLine( char *option ) { int indx, intrinsicIndex; char ch; /* Give it a pseudo-linenumber of 0 */ line = 0; errtag = "pgp"; errCount = 0; for( indx = 0; indx < LINEBUF_SIZE && ( ch = option[ indx ] ) != '\0' && ch != ' ' && ch != '\t' && ch != '='; indx++ ); if( ( intrinsicIndex = lookup( ( char * ) option, indx, intrinsics, NO_INTRINSICS ) ) == ERROR ) return -1; if (option[indx] == '\0' && intrinsicType[intrinsicIndex] == BOOL) { /* boolean option, no '=' means TRUE */ flag = TRUE; processAssignment(intrinsicIndex); } else /* Get the value to set to, either as a string, a numeric value, or a boolean flag */ if (getAssignment( ( char * ) option + indx, &indx, intrinsicType[ intrinsicIndex ] ) != ERROR) processAssignment( intrinsicIndex ); return(errCount ? -1 : 0); } /* Process a config file */ int processConfigFile( char *configFileName ) { FILE *configFilePtr; int ch = 0, theCh; int errType, errPos = 0, lineBufCount, intrinsicIndex; int indx; char inBuffer[ LINEBUF_SIZE ]; line = 1; errCount = 0; errtag = "config.txt"; if( ( configFilePtr = fopen( configFileName, FOPRTXT ) ) == NULL ) { fprintf(stderr, "Cannot open configuration file %s\n", configFileName ); return( OK ); /* treat like empty config file */ } /* Process each line in the configFile */ while( ch != EOF ) { /* Skip whitespace */ while( ( ( ch = getc( configFilePtr ) ) == ' ' || ch == '\t' ) && ch != EOF ) ; /* Get a line into the inBuffer */ hasError = FALSE; lineBufCount = 0; errType = NO_ERROR; while( ch != '\r' && ch != '\n' && ch != CPM_EOF && ch != EOF ) { /* Check for an illegal char in the data */ if( ( ch < ' ' || ch > '~' ) && ch != '\r' && ch != '\n' && ch != ' ' && ch != '\t' && ch != CPM_EOF && ch != EOF ) { if( errType == NO_ERROR ) /* Save position of first illegal char */ errPos = lineBufCount; errType = ILLEGAL_CHAR_ERROR; } /* Make sure the path is of the correct length. Note that the code is ordered so that a LINELENGTH_ERROR takes precedence over an ILLEGAL_CHAR_ERROR */ if( lineBufCount > LINEBUF_SIZE ) errType = LINELENGTH_ERROR; else inBuffer[ lineBufCount++ ] = ch; if( ( ch = getc( configFilePtr ) ) == '#' ) { /* Skip comment section and trailing whitespace */ while( ch != '\r' && ch != '\n' && ch != CPM_EOF && ch != EOF ) ch = getc( configFilePtr ); break; } } /* Skip trailing whitespace and add der terminador */ while(lineBufCount && (( theCh = inBuffer[ lineBufCount - 1 ] ) == ' ' || theCh == '\t' )) lineBufCount--; inBuffer[ lineBufCount ] = '\0'; /* Process the line unless its a blank or comment line */ if( lineBufCount && *inBuffer != '#' ) { switch( errType ) { case LINELENGTH_ERROR: fprintf(stderr, "%s: line '%.30s...' too long\n", errtag, inBuffer ); errCount++; break; case ILLEGAL_CHAR_ERROR: fprintf(stderr, "> %s\n ", inBuffer ); fprintf(stderr, "%*s^\n", errPos, ""); fprintf(stderr, "%s: bad character in command on line %d\n", errtag, line ); errCount++; break; default: for( indx = 0; indx < LINEBUF_SIZE && ( ch = inBuffer[ indx ] ) != '\0' && ch != ' ' && ch != '\t' && ch != '='; indx++ ) ; if( ( intrinsicIndex = lookup( inBuffer, indx, intrinsics, CONFIG_INTRINSICS ) ) == ERROR ) { errCount++; } else { /* Get the value to set to, either as a string, a numeric value, or a boolean flag */ getAssignment( inBuffer + indx, &indx, intrinsicType[ intrinsicIndex ] ); processAssignment( intrinsicIndex ); } } } /* Handle special-case of ^Z if configFile came off an MSDOS system */ if( ch == CPM_EOF ) ch = EOF; /* Exit if there are too many errors */ if( errCount >= MAX_ERRORS ) break; line++; } fclose( configFilePtr ); /* Exit if there were errors */ if( errCount ) { fprintf(stderr, "%s: %s%d error(s) detected\n\n", configFileName, ( errCount >= MAX_ERRORS ) ? "Maximum level of " : "", errCount ); return( ERROR ); } return( OK ); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.