You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
342 lines
11 KiB
342 lines
11 KiB
/* -*- mode: c; indent-tabs-mode: nil; -*- |
|
$Id: config.c,v 1.3 2003/12/28 20:59:21 chrish Exp $ |
|
|
|
config -- read and parse the Plucker config files |
|
SPDX-FileCopyrightText: 2002 Bill Janssen |
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later |
|
|
|
*/ |
|
|
|
#if !defined(WIN32) |
|
#include <unistd.h> /* for lseek, etc. */ |
|
#else |
|
#include <io.h> |
|
#endif |
|
#include <ctype.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
|
|
#include <assert.h> /* for assert() */ |
|
#include <errno.h> /* for errno */ |
|
#include <fcntl.h> /* for O_RDONLY */ |
|
#include <string.h> /* for strndup() */ |
|
#include <sys/stat.h> /* for fstat() */ |
|
#include <sys/types.h> |
|
|
|
#include "unpluck.h" |
|
#include "unpluckint.h" |
|
|
|
#define STRINGIFY(s) STRINGIFY2(s) |
|
#define STRINGIFY2(s) #s |
|
|
|
#define MAX_LINE_SIZE 1023 |
|
|
|
#define COMMENT_CHARS "#;" |
|
#define SEGMENT_LEAD_CHAR '[' |
|
#define SEGMENT_END_CHAR ']' |
|
#define OPTION_SEPARATOR_CHARS "=:" |
|
|
|
HashTable *SectionsTable = nullptr; |
|
|
|
static HashTable *GetOrCreateSegment(const char *name) |
|
{ |
|
HashTable *target; |
|
|
|
if (SectionsTable == nullptr) { |
|
SectionsTable = _plkr_NewHashTable(23); |
|
} |
|
|
|
if ((target = (HashTable *)_plkr_FindInTable(SectionsTable, name)) == nullptr) { |
|
target = _plkr_NewHashTable(53); |
|
_plkr_AddToTable(SectionsTable, name, target); |
|
} |
|
|
|
return target; |
|
} |
|
|
|
static int ReadConfigFile(const char *filename) |
|
{ |
|
HashTable *current_segment = nullptr; |
|
FILE *fp = fopen(filename, "r"); |
|
char *ptr; |
|
char *str_end; |
|
char *str_begin; |
|
char *charptr; |
|
char *current_option; |
|
char *option_value; |
|
char linebuf[MAX_LINE_SIZE + 1]; |
|
int linelen; |
|
int len2; |
|
int buf_index; |
|
int status; |
|
int line_number; |
|
|
|
if (fp == nullptr) { |
|
_plkr_message("Can't open config file %s", filename); |
|
return 0; |
|
} |
|
|
|
current_segment = GetOrCreateSegment("default"); |
|
current_option = nullptr; |
|
|
|
status = 1; /* optimistic */ |
|
line_number = 0; |
|
|
|
while (true) { |
|
ptr = fgets(linebuf, sizeof(linebuf) - 1, fp); |
|
if (ptr == nullptr) { |
|
break; |
|
} |
|
|
|
line_number += 1; |
|
linebuf[strlen(linebuf) - 1] = 0; /* strip newline */ |
|
if (linebuf[strlen(linebuf) - 1] == '\r') { |
|
linebuf[strlen(linebuf) - 1] = 0; /* strip carriage return */ |
|
} |
|
|
|
/* fprintf (stderr, "%s:%d: line is '%s'\n", filename, line_number, linebuf); */ |
|
|
|
linelen = strlen(linebuf); |
|
for (buf_index = 0; linebuf[buf_index] != 0; buf_index++) { |
|
if (!isspace(linebuf[buf_index])) { |
|
break; |
|
} |
|
} |
|
|
|
if (linebuf[buf_index] == 0) { |
|
/* blank line */ |
|
continue; |
|
} |
|
|
|
if ((strchr(COMMENT_CHARS, linebuf[0]) != nullptr) || (strncmp(linebuf, "rem", 3) == 0) || (strncmp(linebuf, "REM", 3) == 0)) { |
|
/* comment */ |
|
continue; |
|
} |
|
|
|
/* At this point we have a valid thing */ |
|
|
|
if (linebuf[buf_index] == SEGMENT_LEAD_CHAR) { |
|
if ((str_end = strchr(linebuf + buf_index + 1, SEGMENT_END_CHAR)) == nullptr) { |
|
/* invalid segment line */ |
|
_plkr_message("%s:%d: Invalid segment line '%s'", filename, line_number, linebuf); |
|
goto error_exit; |
|
} |
|
str_begin = linebuf + buf_index + 1; |
|
for (charptr = str_begin; charptr < str_end; charptr++) { |
|
*charptr = tolower(*charptr); |
|
} |
|
*str_end = 0; |
|
current_segment = GetOrCreateSegment(str_begin); |
|
/* fprintf (stderr, "Current segment is now %p (%s)\n", current_segment, str_begin); */ |
|
if (current_option) { |
|
free(current_option); |
|
} |
|
current_option = nullptr; |
|
|
|
} else if ((linebuf[0] == ' ' || linebuf[0] == '\t') && current_option != nullptr) { |
|
/* continuation line */ |
|
str_begin = (char *)_plkr_RemoveFromTable(current_segment, current_option); |
|
for (str_end = linebuf + strlen(linebuf) - 1; str_end > linebuf && isspace(*str_end); str_end--) { |
|
; |
|
} |
|
charptr = (char *)malloc(strlen(str_begin) + (str_end - (linebuf + buf_index)) + 2); |
|
strcpy(charptr, str_begin); |
|
len2 = strlen(charptr); |
|
charptr[len2] = '\n'; |
|
strncpy(charptr + len2 + 1, linebuf + buf_index, str_end - (linebuf + buf_index)); |
|
charptr[len2 + (str_end - (linebuf + buf_index)) + 1] = '\0'; |
|
_plkr_AddToTable(current_segment, current_option, charptr); |
|
free(str_begin); |
|
|
|
} else if ((int)strcspn(linebuf, OPTION_SEPARATOR_CHARS) < linelen) { |
|
/* possible option line */ |
|
|
|
for (str_begin = linebuf + buf_index, ptr = str_begin; isalnum(*ptr) || (*ptr == '.') || (*ptr == '_') || (*ptr == '-'); ptr++) { |
|
; |
|
} |
|
if (ptr == str_begin) { |
|
_plkr_message("%s:%d: Invalid option line '%s'", filename, line_number, linebuf); |
|
goto error_exit; |
|
} |
|
|
|
for (charptr = str_begin; charptr < ptr; charptr++) { |
|
*charptr = tolower(*charptr); |
|
} |
|
str_end = ptr; |
|
|
|
while (isspace(*ptr) && (*ptr != '\0')) { |
|
ptr++; |
|
} |
|
|
|
if (strchr(OPTION_SEPARATOR_CHARS, *ptr) != nullptr) { |
|
ptr++; |
|
} else { |
|
_plkr_message("%s:%d: Invalid option line '%s'", filename, line_number, linebuf); |
|
goto error_exit; |
|
} |
|
|
|
while (isspace(*ptr) && (*ptr != '\0')) { |
|
ptr++; |
|
} |
|
|
|
if (*ptr == 0) { |
|
_plkr_message("%s:%d: Invalid option line '%s'", filename, line_number, linebuf); |
|
goto error_exit; |
|
} |
|
|
|
if (current_option) { |
|
free(current_option); |
|
} |
|
current_option = _plkr_strndup(str_begin, str_end - str_begin); |
|
|
|
option_value = _plkr_strndup(ptr, strlen(ptr)); |
|
|
|
ptr = (char *)_plkr_RemoveFromTable(current_segment, current_option); |
|
if (ptr) { |
|
free(ptr); |
|
} |
|
_plkr_AddToTable(current_segment, current_option, option_value); |
|
/* fprintf (stderr, "Added value '%s' for option '%p:%s'\n", option_value, current_segment, current_option); */ |
|
|
|
} else { |
|
_plkr_message("%s:%d: Bad line '%s'", filename, line_number, linebuf); |
|
goto error_exit; |
|
} |
|
} |
|
|
|
good_exit: |
|
|
|
if (current_option) { |
|
free(current_option); |
|
} |
|
fclose(fp); |
|
return status; |
|
|
|
error_exit: |
|
status = 0; |
|
goto good_exit; |
|
} |
|
|
|
static void TryReadConfigFile(const char *dir, const char *name) |
|
{ |
|
char *filename; |
|
|
|
if (dir == nullptr || name == nullptr) { |
|
return; |
|
} |
|
|
|
filename = (char *)malloc(strlen(dir) + strlen(name) + 2); |
|
strcpy(filename, dir); |
|
strcpy(filename + strlen(filename), STRINGIFY(FILE_SEPARATOR_CHAR_S)); |
|
strcpy(filename + strlen(filename), name); |
|
if (!ReadConfigFile(filename)) { |
|
_plkr_message("Error reading config file %s", filename); |
|
} |
|
free(filename); |
|
} |
|
|
|
static void InitializeConfigInfo() |
|
{ |
|
const char *config_dir = STRINGIFY(PLUCKER_CONFIG_DIR); |
|
const char *system_config_file_name = STRINGIFY(SYS_CONFIG_FILE_NAME); |
|
const char *user_config_filename = STRINGIFY(USER_CONFIG_FILE_NAME); |
|
char *home = getenv("HOME"); // clazy:exclude=raw-environment-function |
|
|
|
TryReadConfigFile(config_dir, system_config_file_name); |
|
if (home != nullptr) { |
|
TryReadConfigFile(home, user_config_filename); |
|
} |
|
} |
|
|
|
char *plkr_GetConfigString(const char *section_name, const char *option_name, char *default_value) |
|
{ |
|
char *value = nullptr; |
|
HashTable *section; |
|
|
|
if (SectionsTable == nullptr) { |
|
InitializeConfigInfo(); |
|
} |
|
|
|
if (SectionsTable == nullptr) { |
|
return default_value; |
|
} |
|
|
|
if (section_name != nullptr) { |
|
if ((section = (HashTable *)_plkr_FindInTable(SectionsTable, section_name)) != nullptr) { |
|
value = (char *)_plkr_FindInTable(section, option_name); |
|
} |
|
} |
|
if (value == nullptr && ((section_name == nullptr) || (strcmp(section_name, "default") != 0))) { |
|
if ((section = (HashTable *)_plkr_FindInTable(SectionsTable, STRINGIFY(OS_SECTION_NAME))) != nullptr) { |
|
value = (char *)_plkr_FindInTable(section, option_name); |
|
} |
|
} |
|
if (value == nullptr && ((section_name == nullptr) || (strcmp(section_name, "default") != 0))) { |
|
if ((section = (HashTable *)_plkr_FindInTable(SectionsTable, "default")) != nullptr) { |
|
value = (char *)_plkr_FindInTable(section, option_name); |
|
} |
|
} |
|
|
|
return ((value == nullptr) ? default_value : value); |
|
} |
|
|
|
long int plkr_GetConfigInt(const char *section_name, const char *option_name, long int default_value) |
|
{ |
|
char *svalue = plkr_GetConfigString(section_name, option_name, nullptr); |
|
char *endptr; |
|
long int value; |
|
|
|
if (svalue == nullptr) { |
|
return default_value; |
|
} |
|
|
|
value = strtol(svalue, &endptr, 0); |
|
if (*endptr != 0) { |
|
_plkr_message("Bad int value string '%s' for option %s:%s", svalue, (section_name ? section_name : "default"), option_name); |
|
return default_value; |
|
} else { |
|
return value; |
|
} |
|
} |
|
|
|
double plkr_GetConfigFloat(const char *section_name, const char *option_name, double default_value) |
|
{ |
|
char *svalue = plkr_GetConfigString(section_name, option_name, nullptr); |
|
char *endptr; |
|
double value; |
|
|
|
if (svalue == nullptr) { |
|
return default_value; |
|
} |
|
|
|
value = strtod(svalue, &endptr); |
|
if (*endptr != 0) { |
|
_plkr_message("Bad float value string '%s' for option %s:%s", svalue, (section_name ? section_name : "default"), option_name); |
|
return default_value; |
|
} else { |
|
return value; |
|
} |
|
} |
|
|
|
int plkr_GetConfigBoolean(const char *section_name, const char *option_name, int default_value) |
|
{ |
|
char *svalue = plkr_GetConfigString(section_name, option_name, nullptr); |
|
|
|
if (svalue == nullptr) { |
|
return default_value; |
|
} |
|
|
|
if ((strcmp(svalue, "1") == 0) || (strcmp(svalue, "true") == 0) || (strcmp(svalue, "TRUE") == 0) || (strcmp(svalue, "on") == 0) || (strcmp(svalue, "ON") == 0) || (strcmp(svalue, "t") == 0) || (strcmp(svalue, "T") == 0) || |
|
(strcmp(svalue, "True") == 0)) { |
|
return 1; |
|
|
|
} else if ((strcmp(svalue, "0") == 0) || (strcmp(svalue, "false") == 0) || (strcmp(svalue, "FALSE") == 0) || (strcmp(svalue, "off") == 0) || (strcmp(svalue, "OFF") == 0) || (strcmp(svalue, "F") == 0) || (strcmp(svalue, "f") == 0) || |
|
(strcmp(svalue, "False") == 0)) { |
|
return 0; |
|
|
|
} else { |
|
_plkr_message("Bad boolean value string '%s' for option %s:%s", svalue, (section_name ? section_name : "default"), option_name); |
|
return default_value; |
|
} |
|
}
|
|
|