/* -*- 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 * Copyright (c) 2002, Bill Janssen * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #if !defined(WIN32) #include /* for lseek, etc. */ #else #include #endif #include #include #include #include #include /* for fstat() */ #include /* for strndup() */ #include /* for errno */ #include /* for O_RDONLY */ #include /* for assert() */ #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 = NULL; static HashTable* GetOrCreateSegment ( char* name ) { HashTable* target; if (SectionsTable == NULL) SectionsTable = _plkr_NewHashTable (23); if ((target = (HashTable*)_plkr_FindInTable (SectionsTable, name)) == NULL) { target = _plkr_NewHashTable (53); _plkr_AddToTable (SectionsTable, name, target); } return target; } static int ReadConfigFile ( char* filename ) { HashTable* current_segment = NULL; 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 == NULL) { _plkr_message ("Can't open config file %s", filename); return 0; } current_segment = GetOrCreateSegment ("default"); current_option = NULL; status = 1; /* optimistic */ line_number = 0; while (1) { ptr = fgets (linebuf, sizeof (linebuf) - 1, fp); if (ptr == NULL) 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]) != NULL) || (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)) == NULL) { /* 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 = NULL; } else if ((linebuf[0] == ' ' || linebuf[0] == '\t') && current_option != NULL) { /* 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) != NULL) 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 ( char* dir, char* name ) { char* filename; if (dir == NULL || name == NULL) 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 () { char *config_dir = STRINGIFY (PLUCKER_CONFIG_DIR); char *system_config_file_name = STRINGIFY (SYS_CONFIG_FILE_NAME); char *user_config_filename = STRINGIFY (USER_CONFIG_FILE_NAME); char *home = getenv ("HOME"); TryReadConfigFile (config_dir, system_config_file_name); if (home != NULL) TryReadConfigFile (home, user_config_filename); } char* plkr_GetConfigString ( char* section_name, char* option_name, char* default_value ) { char* value = NULL; HashTable* section; if (SectionsTable == NULL) InitializeConfigInfo (); if (SectionsTable == NULL) return default_value; if (section_name != NULL) { if ((section = (HashTable *) _plkr_FindInTable (SectionsTable, section_name)) != NULL) value = (char *) _plkr_FindInTable (section, option_name); } if (value == NULL && ((section_name == NULL) || (strcmp (section_name, "default") != 0))) { if ((section = (HashTable *) _plkr_FindInTable (SectionsTable, STRINGIFY (OS_SECTION_NAME))) != NULL) value = (char *) _plkr_FindInTable (section, option_name); } if (value == NULL && ((section_name == NULL) || (strcmp (section_name, "default") != 0))) { if ((section = (HashTable *) _plkr_FindInTable (SectionsTable, "default")) != NULL) value = (char *) _plkr_FindInTable (section, option_name); } return ((value == NULL) ? default_value : value); } long int plkr_GetConfigInt ( char* section_name, char* option_name, long int default_value ) { char* svalue = plkr_GetConfigString (section_name, option_name, NULL); char* endptr; long int value; if (svalue == NULL) 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 ( char* section_name, char* option_name, double default_value ) { char* svalue = plkr_GetConfigString (section_name, option_name, NULL); char* endptr; double value; if (svalue == NULL) 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 ( char* section_name, char* option_name, int default_value ) { char* svalue = plkr_GetConfigString (section_name, option_name, NULL); if (svalue == NULL) 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; } }