From 0cc9b20c15460213e488bf5e70963b941482f628 Mon Sep 17 00:00:00 2001 From: William Harrington Date: Tue, 14 Jan 2025 16:06:02 -0600 Subject: Add source. --- sdk/other/config.c | 437 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 437 insertions(+) create mode 100644 sdk/other/config.c (limited to 'sdk/other/config.c') diff --git a/sdk/other/config.c b/sdk/other/config.c new file mode 100644 index 0000000..e274b85 --- /dev/null +++ b/sdk/other/config.c @@ -0,0 +1,437 @@ +/* + * Routines to access and parse standard text config files. + * $Id: config.c 1.2 Wed, 19 Mar 1997 12:44:53 -0500 dyfet $ + * Copyright (c) 1997 by Tycho Softworks. + * For conditions of distribution and use see product license. + * + * Abstract: + * These routines are used to open and parse human readable '.conf' + * files, such as those which may be stored in the /etc directory. + * The .conf file is parsed as a sectioned text file, with the name + * for each logical section appearing in []'s. Entries within each + * section are typically in the format 'keyword = value', though + * there are exceptions for multi-line fixed size lists, in + * the form 'keyword = { list }', and repeated lines. Comments may + * also appear within .conf files. + * + * Functions: + * sys_config() - find and open a /etc or /etc/prior .conf file. + * open_config() - open any text file as a config file. + * read_config() - read a keyword = value pair from current section. + * seek_config() - seek a named [] section within the config file. + * get_config() - tests current input for a specified keyword. + * usr_config() - user specific resource config file. + */ + +#include +#include +#include +#include +#include + +/* + * When searching for 'system' .conf files, which are normally held in + * /etc, also search in /etc/prior. This is used so that a human + * readable .conf file can momentarily be moved into '/etc/prior' and + * still be usable while a GUI system management program is in the middle + * building a new .conf file. + */ + +#ifndef CFGPATH +#define CFGPATH "/etc:/etc/prior" +#endif + +/* + * Maximum working space for single or multi-line input records being + * parsed. + */ + +#ifndef LBUF +#define LBUF 1024 +#endif + +#ifndef SUFFIX +#define SUFFIX ".conf" +#endif + +/* + * Open a system .conf file, as found in the system config directories. + * + * Abstract: + * This function finds a .conf file in either the /etc or /etc/prior + * directory. /etc/prior is searched if the current .conf file is + * not found (in /etc), as may happen if it is in the middle of + * being re-built by a management application. This provides an + * initial function which may be used to open most .conf files. + * + * Paramaters: + * cfg_name - 'base' filename of system .conf file to open. + * + * Returns: + * pointer to active CONFIG object for specified filename. + * + * Exceptions: + * If the file is not found, a NULL pointer is returned. + */ + +CONFIG *sys_config(const char *cfg_name) +{ + char cfgname[PATH_MAX + 1]; + + strcpy(cfgname, cfg_name); + strcat(cfgname, SUFFIX); + return open_config(search(CFGPATH, cfgname)); +} + +/* + * Open any specified filename as a .conf file. + * + * Abstract: + * This function opens the specified file as a 'config' file for use + * in config file parsing routines. Any filename may be specified + * and opened as a config file with this routine. + * + * Paramaters: + * config_name - full pathname of a .conf file to open. + * + * Returns: + * pointer to a newly allocated CONFIG parsing object for the + * specified filename. + * + * Exceptions: + * If the file is not found, a NULL pointer is returned. + */ + + +CONFIG *open_config(const char *config_name) +{ + CONFIG *new; + char *env; + + if(NULL == (new = (CONFIG *)malloc(sizeof(CONFIG) + LBUF))) + return NULL; + + if(NULL == (new->cfg_fp = fopen(config_name, "r"))) + { + free(new); + return NULL; + } + new->cfg_flag = FALSE; + return new; +} + +/* + * Close an open config file and destroy the CONFIG parser object. + */ + +void close_config(CONFIG *cfg) +{ + if(!cfg) + return; + + fclose(cfg->cfg_fp); + free(cfg); +} + +/* Read a line of ASCII text input from an open config file. + * + * Abstract: + * This routine extracts a line of input from an open config file. + * The input line extracted and returned is a "keyword = value" line + * found within the current [] section. If the end of the current + * [] section has been reached, then no further input is returned. + * + * Lines which contain comments are automatically skipped. Comments + * include those lines which begin with a '#' or ';' character. + * Empty lines are also automatically skipped. + * + * Special {} subsections may also be used to specify language + * variant .conf values. When these subsection identifiers are found + * and the current language found in the ENV (LANG=) does not match + * the language for the specified {} section, the entire {} section + * is skipped. + * + * The input line retreived automatically has lead and trailing + * whitespaces removed. + * + * Paramaters: + * cfg - a 'config' parser object. + * + * Returns: + * ASCII text for 'keyword = value' item from config file. + * + * Exceptions: + * A NULL is returned when the current [] section has been completed, + * when at the end of the file, or if any error occurs while reading. + */ + +char *read_config(CONFIG *cfg) +{ + char *p, *q; + int skip = 0; + + if(!cfg) + return NULL; + + if(!cfg->cfg_flag) + return NULL; + + for(;;) + { + fgets(cfg->cfg_lbuf, LBUF - 1, cfg->cfg_fp); + if(feof(cfg->cfg_fp) || cfg->cfg_lbuf[0] == '[' || ferror(cfg->cfg_fp)) + { + cfg->cfg_flag = FALSE; + return NULL; + } + p = strtrim(cfg->cfg_lbuf, __SPACES); + + if(*p == '{') + { + skip = 1; + p = strtok(p, "{}| \t"); + while(p) + { + if(!stricmp(p, "all")) + skip = 0; + if(!stricmp(p, language())) + skip = 0; + p = strtok(NULL, "{}| \t"); + } + continue; + } + + if(!*p || *p == '!' || *p == '#' || *p == ';' || skip) + continue; + + return p; + } +} + +/* + * Seek a named [] section within the .conf file to begin input. + * + * Abstract: + * The named section is found within the .conf file. Once + * found, all read_config() input will be returned from the + * specified [] section. Section names are case insensitive. + * + * Paramaters: + * cfg - config object pointer. + * seek_name - name of config [] section to find. + * + * Returns: + * TRUE if the section name is found in the .conf file , FALSE if + * not. + * + * Exceptions: + * If a NULL cfg or seek_name is passed, the search always fails. + * If a file error is found, the search always fails. The maximum + * size of a [] section name that is tested is 22 characters. + */ + +bool seek_config(CONFIG *cfg, const char *seek_name) +{ + char group[25]; + int len; + + if(!cfg || !seek_name) + return FALSE; + + cfg->cfg_flag = FALSE; /* mark as outside old [] section */ + + len = strlen(seek_name); + if (len > 22) + len = 22; + + memset(group, 0, sizeof(group)); + + if(*seek_name != '[') + strcpy(group, "["); + + strncat(group, seek_name, len); + + if(*seek_name != '[' && strlen(seek_name) < 23) + strcat(group, "]"); + + fseek(cfg->cfg_fp, 0l, SEEK_SET); + len = strlen(group); + for(;;) + { + fgets(cfg->cfg_lbuf, LBUF - 1, cfg->cfg_fp); + if(feof(cfg->cfg_fp) || ferror(cfg->cfg_fp)) + return FALSE; + + if(!strnicmp(group, cfg->cfg_lbuf, len)) + { + cfg->cfg_flag = TRUE; + return TRUE; + } + } +} + +/* + * Parse and test a keyword value pair from current config input. + * + * Abstract: + * This routine is commonly used to search the current input line + * that is returned by read_config() for a specified keyword. The + * current input line is assumed to be in the form 'keyword = value'. + * lead and trailing spaces around the '=' are ignored, as is keyword + * case. White spaces within a keyword are also ignored. + * + * Assuming the keyword requested is found in the current input line, + * the 'value' string is returned. If the keyword being tested is + * a multi-line keyword = { list }, then all lines for the value are + * scanned and loaded into the config line buffer. If the special + * '+' entry is found in the config file, then the keyword is assumed + * to be a continuation of the last one found. + * + * A value is normally stripped of all lead and trailing spaces. If + * these need to be preserved, then the value may be put in single + * or double quotes. + * + * Since get_config() only looks at the current input line buffered + * by read_config(), a test for every possible keyword the application + * may need should be performed after each successful read_config() + * for a given [] section. + * + * Paramaters: + * cfg - config object pointer. + * keyword - keyword to test for. + * + * Returns: + * Value string if keyword is found in current input line, else NULL. + * + * Exceptions: + * If a NULL pointer or keyword is used, a NULL value is returned. + */ + +char *get_config(CONFIG *cfg, const char *keyword) +{ + char *cbuf; + char *out, *p; + int pos = 0; + bool found = FALSE; + + if(!cfg || !keyword) + return NULL; + + cbuf = cfg->cfg_lbuf; + + if(*cbuf == '+') /* alternate multi-line syntax */ + { + if(!stricmp(cfg->cfg_test, keyword)) + return strltrim(++cbuf, __SPACES); + else + return NULL; + } + + while((pos < 33) && *cbuf && (*cbuf != '=')) + { + if((*cbuf != ' ') && (*cbuf != '_') && (*cbuf != '\t')) + cfg->cfg_test[pos++] = *(cbuf++); + else + ++cbuf; + } + cfg->cfg_test[pos] = 0; + out = p = strltrim(++cbuf, __SPACES); + switch(*p) + { + case '{': + cbuf = p; + while(!found) + { + while(*(++p)) + { + if(*p == '}') + { + found = TRUE; + *p = 0; + } + else + *(cbuf++) = *p; + } + + if(!found) + { + p = cbuf; + fgets(p, LBUF - 1 + (int)(cfg->cfg_lbuf - p), cfg->cfg_fp); + if(feof(cfg->cfg_fp) || *p == '[') + { + cfg->cfg_flag = FALSE; + *p = 0; + break; + } + *(cbuf++) = '\n'; + p = strtrim(p, __SPACES); + } + } + *cbuf = 0; + out = strltrim(++out, __SPACES); + break; + case '\'': + case '\"': + while(*(++p)) + { + if(*p == *out) + { + *p = 0; + break; + } + } + out = strltrim(++out, __SPACES); + break; + } + if(!stricmp(cfg->cfg_test, keyword)) + return out; + else + return NULL; +} + +/* + * Find config file in user's home directory. + * + * Abstract: + * In addition to searching for a master config file in /etc, many + * applications may support an optional user specific 'rc' or config + * file in the user's own home directory, which, if found, may + * override global defaults. This ability is easily supported with + * the usr_config() service, which looks for a named .config file + * in the user's home. + * + * Paramaters: + * Filename of '.config' file to look for in a user's home directory, + * without the leading '.'. + * + * Returns: + * Config object pointer if file is found in user's home, otherwise + * a NULL pointer. + * + * Exceptions: + * A NULL filename will result in a NULL object being returned. + */ + +CONFIG *usr_config(const char *name) +{ + char path[NAME_MAX + 1]; + + if(!name) + return NULL; + + strcpy(path, homedir()); + fncat(path, "."); + strcat(path, name); + return open_config(path); +} + + + + + + + + + + + -- cgit v1.2.3-54-g00ecf