/***************************************************************************** * General routines to configuration file reading: * * The config file (same name as program, type .cfg) must have th following * * format: one variable setup per line, each line consists of two params. * * The first is variable name, which is text string without white spaces. * * The second param. contains its value, which might be boolean (TRUE/FALSE), * * integer, or real type. * * The main routine should get a structure consists of 3 elements per * * variable: the string to match, the variable to save the data read from * * config file, and the type (Boolean, Integer, Real), for type checking. * * See config.h for exact definition of this data structure. * * * * Version 0.2 - adding String Type. * * * * Written by: Gershon Elber Ver 0.2, Jan. 1989 * *****************************************************************************/ #ifdef __MSDOS__ #include #include #include #include #endif /* __MSDOS__ */ #include #include #include "irit_sm.h" #include "config.h" /* #define DEBUG Uncomment it for simple test case (see config.bat). */ #define TAB 9 /* Some fatal errors that cause this module to die... */ #define ERR_ONLY_NAME 1 #define ERR_BOOL_EXPECTED 2 #define ERR_INT_EXPECTED 3 #define ERR_REAL_EXPECTED 4 #define ERR_STRING_EXPECTED 5 #define ERR_NOT_EXISTS 6 static char *ConfigPath; static void UpdateVariable(char *Line, ConfigStruct *SetUp, int NumVar, int LineCount); static void PrintConfigError(int ErrorNum, int LineCount); static FILE *FindFile(char *FileName); /***************************************************************************** * Routine to print the current configuration data structure contents. * *****************************************************************************/ void ConfigPrint(ConfigStruct *SetUp, int NumVar) { int i; fprintf(stderr, "\nCurrent defaults:\n\n"); for (i = 0; i < NumVar; i++) switch (SetUp[i].VarType) { case SU_BOOLEAN_TYPE: if (* ((int *) SetUp[i].VarData)) fprintf(stderr, "\t%-20s = TRUE\n", SetUp[i].VarName); else fprintf(stderr, "\t%-20s = FALSE\n", SetUp[i].VarName); break; case SU_INTEGER_TYPE: fprintf(stderr, "\t%-20s = %d\n", SetUp[i].VarName, * ((int *) SetUp[i].VarData)); break; case SU_REAL_TYPE: #ifdef __MSDOS__ fprintf(stderr, "\t%-20s = %g\n", SetUp[i].VarName, #else fprintf(stderr, "\t%-20s = %lg\n", SetUp[i].VarName, #endif /* __MSDOS__ */ * ((RealType *) SetUp[i].VarData)); break; case SU_STRING_TYPE: fprintf(stderr, "\t%-20s = \"%s\"\n", SetUp[i].VarName, * ((char **) SetUp[i].VarData)); break; } } /***************************************************************************** * Main routine of config module. Gets the program name (it updates the type) * * PrgmName, and the structure defines the acceptable variables Setup. * *****************************************************************************/ void Config(char *PrgmName, ConfigStruct *SetUp, int NumVar) { int i, LineCount = 0; char CfgName[PATH_NAME_LEN], Line[LINE_LEN_LONG], *Cptr; FILE *f; i = strlen(PrgmName) - 1; /* Skip the full path name: */ while (i && PrgmName[i] != '\\' && PrgmName[i] != '/' && PrgmName[i] != ':') i--; if (i) i++; strcpy(CfgName, &PrgmName[i]); Cptr = strchr(CfgName, '.'); if (Cptr != NULL) *Cptr = 0; /* Delete old type. */ strcat(CfgName, ".cfg"); /* And add the config file type. */ if ((f = FindFile(CfgName)) == NULL) return; /* Search via path var. */ while (!feof(f)) { fgets(Line, LINE_LEN_LONG, f); LineCount++; i = 0; /* Delete all the part after the ; (The comment) if was any. */ while (Line[i] != 0 && Line[i] != ';') i++; if (Line[i]) Line[i] = 0; i = 0; /* Now test if that line is empty or not: */ while (Line[i] != 0 && Line[i] <= ' ') i++; /* Skip white spaces. */ if (Line[i]) UpdateVariable(Line, SetUp, NumVar, LineCount); } fclose(f); } /***************************************************************************** * Routine to interpret the input Line and update the appropriate variable * * in SetUp data structure. NumVar holds number of entries in SetUp Table. * *****************************************************************************/ static void UpdateVariable(char *Line, ConfigStruct *SetUp, int NumVar, int LineCount) { int i, j; char VarName[LINE_LEN_LONG], VarData[LINE_LEN_LONG], *StrStart, *StrEnd, *NewStr; RealType Dummy; /* Force linking of floating point scanf routines. */ i = j = 0; while (Line[i] > ' ') { /* Copy the Variable name: */ VarName[i] = Line[i]; i++; } VarName[i] = 0; while (Line[i] != 0 && Line[i] <= ' ') i++; if (Line[i] == 0) PrintConfigError(ERR_ONLY_NAME, LineCount); while (Line[i] >= ' ' || Line[i] == TAB) /* Copy the Variable data: */ VarData[j++] = Line[i++]; VarData[j] = 0; for (i = 0; i < NumVar; i++) if (strcmp(VarName, SetUp[i].VarName) == 0) switch (SetUp[i].VarType) { case SU_BOOLEAN_TYPE: if (strnicmp(VarData, "True", 4) == 0 || strnicmp(VarData, "False", 5) == 0) *((int *) SetUp[i].VarData) = (strnicmp (VarData, "True", 4) == 0); else PrintConfigError(ERR_BOOL_EXPECTED, LineCount); return; case SU_INTEGER_TYPE: if (sscanf(VarData, "%d", (int *) SetUp[i].VarData) != 1) PrintConfigError(ERR_INT_EXPECTED, LineCount); return; case SU_REAL_TYPE: #ifdef __MSDOS__ if (sscanf(VarData, "%f", &Dummy) != 1) { #else if (sscanf(VarData, "%lf", &Dummy) != 1) { #endif /* __MSDOS__ */ PrintConfigError(ERR_REAL_EXPECTED, LineCount); return; } *((RealType *) SetUp[i].VarData) = Dummy; return; case SU_STRING_TYPE: if ((StrStart = strchr(VarData, '"')) != NULL && (StrEnd = strrchr(VarData, '"')) != NULL && StrEnd != StrStart) { NewStr = malloc(1 + ((unsigned int) (StrEnd - StrStart))); j = 0; while (++StrStart != StrEnd) NewStr[j++] = *StrStart; NewStr[j] = 0; *((char **) SetUp[i].VarData) = NewStr; } else PrintConfigError(ERR_STRING_EXPECTED, LineCount); return; } PrintConfigError(ERR_NOT_EXISTS, LineCount); } /***************************************************************************** * Routine to print fatal configuration file error, and die. * *****************************************************************************/ static void PrintConfigError(int ErrorNum, int LineCount) { fprintf(stderr, "Config. file error [%s line %d]: ", ConfigPath, LineCount); switch (ErrorNum) { case ERR_ONLY_NAME: fprintf(stderr, "Only Name found.\n"); break; case ERR_BOOL_EXPECTED: fprintf(stderr, "Boolean type expected.\n"); break; case ERR_INT_EXPECTED: fprintf(stderr, "Integer type expected.\n"); break; case ERR_REAL_EXPECTED: fprintf(stderr, "Real type expected.\n"); break; case ERR_STRING_EXPECTED: fprintf(stderr, "String (within \") type expected.\n"); break; case ERR_NOT_EXISTS: fprintf(stderr, "No such set up option.\n"); break; } exit('c'); } /***************************************************************************** * Routine to search for a file and open it according to attribute at all * * directories defined by PATH environment variable and current dir. * *****************************************************************************/ static FILE *FindFile(char *FileName) { FILE *f; ConfigPath = searchpath(FileName); if ((f = fopen(ConfigPath, "rt")) != NULL) return f; fprintf(stderr, "Warning: No config. file (%s) found.\n", FileName); return NULL; } #ifdef DEBUG /***************************************************************************** * Simple test routine. use it with cnfgtest.bat which rename the program * * name so that this module will recognize the appropriate configuration file * * The arguments below assume double or non MSDOS system!. * *****************************************************************************/ void main(int argc, char **argv) { static int Test1, Test2, Test3, Test4; static double Test5, Test6; static char *Test7, *Test8; ConfigStruct SetUp[] = { { "TestOne", (VoidPtr) &Test1, SU_BOOLEAN_TYPE }, { "TestTwo", (VoidPtr) &Test2, SU_BOOLEAN_TYPE }, { "Test333", (VoidPtr) &Test3, SU_INTEGER_TYPE }, { "Testing4", (VoidPtr) &Test4, SU_INTEGER_TYPE }, { "TestReal5", (VoidPtr) &Test5, SU_REAL_TYPE }, { "TestReal6", (VoidPtr) &Test6, SU_REAL_TYPE }, { "String7", (VoidPtr) &Test7, SU_STRING_TYPE }, { "String8", (VoidPtr) &Test8, SU_STRING_TYPE } }; Test1 = Test2 = Test3 = Test4 = 9999; Test5 = Test6 = 0.9999; Test7 = Test8 = NULL; printf("Before:\nTest1 = %d, Test2 = %d, Test3 = %d, Test4 = %d\n" "Test5 = %lf, Test6 = %lf\nTest7 = \"%s\"\nTest8 = \"%s\"\n", Test1, Test2, Test3, Test4, Test5, Test6, Test7, Test8); Config(*argv, SetUp, 8); /* Do it! */ printf("After:\nTest1 = %d, Test2 = %d, Test3 = %d, Test4 = %d\n" "Test5 = %lf, Test6 = %lf\nTest7 = \"%s\"\nTest8 = \"%s\"\n", Test1, Test2, Test3, Test4, Test5, Test6, Test7, Test8); printf("\nConfigPrint prints:\n"); ConfigPrint(SetUp, 8); } #endif /* DEBUG */