/***************************************************************************** * 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. * ****************************************************************************** * (C) Gershon Elber, Technion, Israel Institute of Technology * ****************************************************************************** * Written by: Gershon Elber Ver 0.2, Jan. 1989 * *****************************************************************************/ #include #include #include "irit_sm.h" #include "misc_loc.h" #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_DATA char *ConfigPath; static void UpdateVariable(char *Line, IritConfigStruct *SetUp, int NumVar, int LineCount); static void PrintConfigError(int ErrorNum, int LineCount); static FILE *FindFile(char *PrgmName, char *FileName); /***************************************************************************** * DESCRIPTION: M * Routine to print the current configuration data structure contents. M * * * PARAMETERS: M * SetUp: Configuration data based. M * NumVar: Number of entries on configuration data base. M * * * RETURN VALUE: M * void M * * * KEYWORDS: M * IritConfigPrint, configuration, cfg files M *****************************************************************************/ void IritConfigPrint(IritConfigStruct *SetUp, int NumVar) { int i; char *p; fprintf(stderr, IRIT_EXP_STR("\nCurrent defaults:\n\n")); for (i = 0; i < NumVar; i++) { char VarName[LINE_LEN]; if (SetUp[i].SomeInfo != NULL && strlen(SetUp[i].SomeInfo) > 0) sprintf(VarName, "%s [%s]", SetUp[i].VarName, SetUp[i].SomeInfo); else sprintf(VarName, SetUp[i].VarName); switch (SetUp[i].VarType) { case IC_BOOLEAN_TYPE: if (* ((int *) SetUp[i].VarData)) fprintf(stderr, IRIT_EXP_STR("\t%-20s = TRUE\n"), VarName); else fprintf(stderr, IRIT_EXP_STR("\t%-20s = FALSE\n"), VarName); break; case IC_INTEGER_TYPE: fprintf(stderr, IRIT_EXP_STR("\t%-20s = %d\n"), VarName, *((int *) SetUp[i].VarData)); break; case IC_REAL_TYPE: fprintf(stderr, IRIT_EXP_STR("\t%-20s = %g\n"), VarName, *((RealType *) SetUp[i].VarData)); break; case IC_STRING_TYPE: p = *((char **) SetUp[i].VarData); fprintf(stderr, IRIT_EXP_STR("\t%-20s = \"%s\"\n"), VarName, p == NULL ? "" : p); break; } } } /***************************************************************************** * DESCRIPTION: M * Main routine of configuration file handling. M * Gets the program name, PrgmName, and the configuration data base that M * defines the acceptable variables, Setup, with Numvarentries. M * * * PARAMETERS: M * PrgmName: Name of program that uses this data base. M * SetUp: Configuration data based. M * NumVar: Number of entries on configuration data base. M * * * RETURN VALUE: M * void M * * * KEYWORDS: M * IritConfig, configuration, cfg files M *****************************************************************************/ void IritConfig(char *PrgmName, IritConfigStruct *SetUp, int NumVar) { int i, LineCount = 0; char CfgName[PATH_NAME_LEN], Line[LINE_LEN_LONG], *Cptr; FILE *f; i = (int) 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(PrgmName, 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); } /***************************************************************************** * DESCRIPTION: * * Routine to interpret the input Line and update the appropriate variable * * in SetUp data structure. NumVar holds number of entries in SetUp Table. * * * * PARAMETERS: * * Line: Single line from a configuration file to interpret. * * SetUp: Configuration data based. * * NumVar: Number of entries on configuration data base. * * LineCount: Line number. * * * * RETURN VALUE: * * void * *****************************************************************************/ static void UpdateVariable(char *Line, IritConfigStruct *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 IC_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 IC_INTEGER_TYPE: if (sscanf(VarData, "%d", (int *) SetUp[i].VarData) != 1) PrintConfigError(ERR_INT_EXPECTED, LineCount); return; case IC_REAL_TYPE: #ifdef IRIT_DOUBLE if (sscanf(VarData, "%lf", &Dummy) != 1) { #else if (sscanf(VarData, "%f", &Dummy) != 1) { #endif /* IRIT_DOUBLE */ PrintConfigError(ERR_REAL_EXPECTED, LineCount); return; } *((RealType *) SetUp[i].VarData) = Dummy; return; case IC_STRING_TYPE: if ((StrStart = strchr(VarData, '"')) != NULL && (StrEnd = strrchr(VarData, '"')) != NULL && StrEnd != StrStart) { NewStr = IritMalloc(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); } /***************************************************************************** * DESCRIPTION: * * Routine to print fatal configuration file error, and die. * * * * PARAMETERS: * * ErrorNum: Error number. * * LineCount: Line where error had occured, in configuration file. * * * * RETURN VALUE: * * void * *****************************************************************************/ static void PrintConfigError(int ErrorNum, int LineCount) { fprintf(stderr, IRIT_EXP_STR("Config. file error [%s line %d]: "), ConfigPath, LineCount); switch (ErrorNum) { case ERR_ONLY_NAME: fprintf(stderr, IRIT_EXP_STR("Only Name found.\n")); break; case ERR_BOOL_EXPECTED: fprintf(stderr, IRIT_EXP_STR("Boolean type expected.\n")); break; case ERR_INT_EXPECTED: fprintf(stderr, IRIT_EXP_STR("Integer type expected.\n")); break; case ERR_REAL_EXPECTED: fprintf(stderr, IRIT_EXP_STR("Real type expected.\n")); break; case ERR_STRING_EXPECTED: fprintf(stderr, IRIT_EXP_STR("String (within \") type expected.\n")); break; case ERR_NOT_EXISTS: fprintf(stderr, IRIT_EXP_STR("No such set up option.\n")); break; } MISC_FATAL_ERROR(MISC_ERR_UNKNOWN_CONFIG); } /***************************************************************************** * DESCRIPTION: * * Routine to search for a file and open it according to attribute at all * * directories defined by PATH environment variable and current dir. * * * * PARAMETERS: * * PrgmName: Name of program that uses the configuration file. * * FileName: Name of configuration file. * * * * RETURN VALUE: * * FILE *: Open file is found, NULL otherwise * *****************************************************************************/ static FILE *FindFile(char *PrgmName, char *FileName) { FILE *f; ConfigPath = searchpath(FileName); #if defined(AMIGA) && !defined(__SASC) if ((f = fopen(ConfigPath, "r")) != NULL) #else if ((f = fopen(ConfigPath, "rt")) != NULL) #endif /* defined(AMIGA) && !defined(__SASC) */ return f; fprintf(stderr, IRIT_EXP_STR("%s: Warning: No config. file (%s) found.\n"), PrgmName, FileName); return NULL; } #ifdef DEBUG_MAIN_CONFIG /***************************************************************************** * DESCRIPTION: * * Simple test routine. * *****************************************************************************/ void main(int argc, char **argv) { STATIC_DATA int Test1, Test2, Test3, Test4; STATIC_DATA double Test5, Test6; STATIC_DATA char *Test7, *Test8; IritConfigStruct SetUp[] = { { "TestOne", (VoidPtr) &Test1, IC_BOOLEAN_TYPE }, { "TestTwo", (VoidPtr) &Test2, IC_BOOLEAN_TYPE }, { "Test333", (VoidPtr) &Test3, IC_INTEGER_TYPE }, { "Testing4", (VoidPtr) &Test4, IC_INTEGER_TYPE }, { "TestReal5", (VoidPtr) &Test5, IC_REAL_TYPE }, { "TestReal6", (VoidPtr) &Test6, IC_REAL_TYPE }, { "String7", (VoidPtr) &Test7, IC_STRING_TYPE }, { "String8", (VoidPtr) &Test8, IC_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_MAIN_CONFIG */