aboutsummaryrefslogtreecommitdiffstats
path: root/sdk/other/config.c
diff options
context:
space:
mode:
authorWilliam Harrington <kb0iic@berzerkula.org>2025-01-14 16:06:02 -0600
committerWilliam Harrington <kb0iic@berzerkula.org>2025-01-14 16:06:02 -0600
commit0cc9b20c15460213e488bf5e70963b941482f628 (patch)
treebb0143245583ec846630f39bfa2258dba640ccd7 /sdk/other/config.c
parent0e084ade5069756d487b5c948c48b777e37c00c9 (diff)
Add source.
Diffstat (limited to 'sdk/other/config.c')
-rw-r--r--sdk/other/config.c437
1 files changed, 437 insertions, 0 deletions
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 <other/config.h>
+#include <other/strcvt.h>
+#include <other/string.h>
+#include <other/env.h>
+#include <std/process.h>
+
+/*
+ * 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);
+}
+
+
+
+
+
+
+
+
+
+
+