📄 config.c
字号:
/* This file is part of GNUnet. (C) 2006, 2007 Christian Grothoff (and other contributing authors) GNUnet 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, or (at your option) any later version. GNUnet 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 GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*//** * @file src/util/config/config.c * @brief configuration management * * @author Christian Grothoff */#include "platform.h"#include "gnunet_util.h"/** * @brief configuration entry */typedef struct GNUNET_GC_Entry{ /** * key for this entry */ char *key; /** * current, commited value */ char *val; /** * non-null during uncommited update */ char *dirty_val;} GNUNET_GC_Entry;/** * @brief configuration section */typedef struct GNUNET_GC_Section{ /** * name of the section */ char *name; /** * number of entries in section */ unsigned int size; /** * entries in the section */ GNUNET_GC_Entry *entries;} GNUNET_GC_Section;/** * @brief GNUNET_GC_ChangeListener and context */typedef struct GNUNET_GC_Listener{ /** * Callback. */ GNUNET_GC_ChangeListener listener; /** * Context for callback. */ void *ctx;} GNUNET_GC_Listener;/** * @brief configuration data */typedef struct GNUNET_GC_Configuration{ /** * Lock to access the data. */ struct GNUNET_Mutex *lock; /** * Context for logging errors, maybe NULL. */ struct GNUNET_GE_Context *ectx; /** * Modification indication since last save * 0 if clean, 1 if dirty, -1 on error (i.e. last save failed) */ int dirty; /** * How many sections do we have? */ unsigned int ssize; /** * Array with "ssize" entries. */ GNUNET_GC_Section *sections; /** * How many listeners do we have? */ unsigned int lsize; /** * Array with "lsize" entries. */ GNUNET_GC_Listener *listeners;} GNUNET_GC_Configuration;voidGNUNET_GC_free (struct GNUNET_GC_Configuration *cfg){ GNUNET_GC_Section *sec; GNUNET_GC_Entry *e; int i; int j; for (i = 0; i < cfg->ssize; i++) { sec = &cfg->sections[i]; for (j = 0; j < sec->size; j++) { e = &sec->entries[j]; GNUNET_free (e->key); GNUNET_free_non_null (e->val); GNUNET_GE_ASSERT (cfg->ectx, e->dirty_val == NULL); } GNUNET_array_grow (sec->entries, sec->size, 0); GNUNET_free (sec->name); } GNUNET_array_grow (cfg->sections, cfg->ssize, 0); GNUNET_GE_ASSERT (cfg->ectx, cfg->listeners == 0); GNUNET_mutex_destroy (cfg->lock); GNUNET_free (cfg);}voidGNUNET_GC_set_error_context (struct GNUNET_GC_Configuration *cfg, struct GNUNET_GE_Context *ectx){ cfg->ectx = ectx;}intGNUNET_GC_parse_configuration (struct GNUNET_GC_Configuration *cfg, const char *filename){ int dirty; char line[256]; char tag[64]; char value[192]; FILE *fp; int nr; int i; int emptyline; int ret; char *section; char *fn; fn = GNUNET_expand_file_name (NULL, filename); GNUNET_mutex_lock (cfg->lock); dirty = cfg->dirty; /* back up value! */ if (NULL == (fp = FOPEN (fn, "r"))) { GNUNET_GE_LOG_STRERROR_FILE (cfg->ectx, GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_IMMEDIATE | GNUNET_GE_BULK | GNUNET_GE_REQUEST, "fopen", fn); GNUNET_mutex_unlock (cfg->lock); GNUNET_free (fn); return -1; } GNUNET_free (fn); ret = 0; section = GNUNET_strdup (""); memset (line, 0, 256); nr = 0; while (NULL != fgets (line, 255, fp)) { nr++; for (i = 0; i < 255; i++) if (line[i] == '\t') line[i] = ' '; if (line[0] == '\n' || line[0] == '#' || line[0] == '%' || line[0] == '\r') continue; emptyline = 1; for (i = 0; (i < 255 && line[i] != 0); i++) if (line[i] != ' ' && line[i] != '\n' && line[i] != '\r') emptyline = 0; if (emptyline == 1) continue; /* remove tailing whitespace */ for (i = strlen (line) - 1; (i >= 0) && (isspace (line[i])); i--) line[i] = '\0'; if (1 == sscanf (line, "@INLINE@ %191[^\n]", value)) { /* @INLINE@ value */ char *expanded = GNUNET_expand_file_name (cfg->ectx, value); if (0 != GNUNET_GC_parse_configuration (cfg, expanded)) ret = -1; /* failed to parse included config */ } else if (1 == sscanf (line, "[%99[^]]]", value)) { /* [value] */ GNUNET_free (section); section = GNUNET_strdup (value); } else if (2 == sscanf (line, " %63[^= ] = %191[^\n]", tag, value)) { /* tag = value */ /* Strip LF */ i = strlen (value) - 1; while ((i >= 0) && (isspace (value[i]))) value[i--] = '\0'; /* remove quotes */ i = 0; if (value[0] == '"') { i = 1; while ((value[i] != '\0') && (value[i] != '"')) i++; if (value[i] == '"') { value[i] = '\0'; i = 1; } else i = 0; } /* first check if we have this value already; this could happen if the value was changed using a command-line option; only set it if we do not have a value already... */ if ((GNUNET_NO == GNUNET_GC_have_configuration_value (cfg, section, tag)) && (0 != GNUNET_GC_set_configuration_value_string (cfg, cfg->ectx, section, tag, &value[i]))) ret = -1; /* could not set value */ } else if (1 == sscanf (line, " %63[^= ] =[^\n]", tag)) { /* tag = */ /* first check if we have this value already; this could happen if the value was changed using a command-line option; only set it if we do not have a value already... */ if ((GNUNET_NO == GNUNET_GC_have_configuration_value (cfg, section, tag)) && (0 != GNUNET_GC_set_configuration_value_string (cfg, cfg->ectx, section, tag, ""))) ret = -1; /* could not set value */ } else { /* parse error */ GNUNET_GE_LOG (cfg->ectx, GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_IMMEDIATE | GNUNET_GE_BULK, _ ("Syntax error in configuration file `%s' at line %d.\n"), filename, nr); ret = -1; break; } } if (0 != fclose (fp)) { GNUNET_GE_LOG_STRERROR_FILE (cfg->ectx, GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_IMMEDIATE | GNUNET_GE_BULK | GNUNET_GE_REQUEST, "fclose", filename); ret = -1; } /* restore dirty flag - anything we set in the meantime came from disk */ cfg->dirty = dirty; GNUNET_mutex_unlock (cfg->lock); GNUNET_free (section); return ret;}intGNUNET_GC_test_dirty (struct GNUNET_GC_Configuration *cfg){ return cfg->dirty;}intGNUNET_GC_write_configuration (struct GNUNET_GC_Configuration *data, const char *filename){ GNUNET_GC_Section *sec; GNUNET_GC_Entry *e; int i; int j; FILE *fp; int error; int ret; char *fn; char *val; char *pos; fn = GNUNET_expand_file_name (NULL, filename); GNUNET_disk_directory_create_for_file (NULL, fn); if (NULL == (fp = FOPEN (fn, "w"))) { GNUNET_GE_LOG_STRERROR_FILE (data->ectx, GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_IMMEDIATE, "fopen", fn); GNUNET_free (fn); return -1; } GNUNET_free (fn); error = 0; ret = 0; GNUNET_mutex_lock (data->lock); for (i = 0; i < data->ssize; i++) { sec = &data->sections[i]; if (0 > fprintf (fp, "[%s]\n", sec->name)) { error = 1; break; } for (j = 0; j < sec->size; j++) { e = &sec->entries[j]; GNUNET_GE_ASSERT (data->ectx, e->dirty_val == NULL); if (e->val != NULL) { val = GNUNET_malloc (strlen (e->val) * 2 + 1); strcpy (val, e->val); while (NULL != (pos = strstr (val, "\n"))) { memmove (&pos[2], &pos[1], strlen (&pos[1])); pos[0] = '\\'; pos[1] = 'n'; } if (0 > fprintf (fp, "%s = %s\n", e->key, val)) { error = 1; GNUNET_free (val); break; } GNUNET_free (val); } } if (error != 0) break; if (0 > fprintf (fp, "\n")) { error = 1; break; } } if (error != 0) GNUNET_GE_LOG_STRERROR_FILE (data->ectx, GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_IMMEDIATE | GNUNET_GE_BULK | GNUNET_GE_REQUEST, "fprintf", filename); if (0 != fclose (fp)) { GNUNET_GE_LOG_STRERROR_FILE (data->ectx, GNUNET_GE_ERROR | GNUNET_GE_USER | GNUNET_GE_ADMIN | GNUNET_GE_IMMEDIATE | GNUNET_GE_BULK | GNUNET_GE_REQUEST, "fclose", filename); error = 1; } if (error == 0) { ret = 0; data->dirty = 0; /* last write succeeded */ } else { ret = -1; data->dirty = -1; /* last write failed */ } GNUNET_mutex_unlock (data->lock); return ret;}/** * Call only with lock held! */static GNUNET_GC_Section *findSection (GNUNET_GC_Configuration * data, const char *section){ int i; for (i = data->ssize - 1; i >= 0; i--) if (0 == strcmp (section, data->sections[i].name)) return &data->sections[i]; return NULL;}/** * Call only with lock held! */static GNUNET_GC_Entry *findEntry (GNUNET_GC_Configuration * data, const char *section, const char *key){ int i; GNUNET_GC_Section *sec; sec = findSection (data, section); if (sec == NULL) return NULL; for (i = sec->size - 1; i >= 0; i--) if (0 == strcmp (key, sec->entries[i].key)) return &sec->entries[i]; return NULL;}intGNUNET_GC_set_configuration_value_string (struct GNUNET_GC_Configuration *data, struct GNUNET_GE_Context *ectx, const char *section, const char *option, const char *value){ GNUNET_GC_Section *sec; GNUNET_GC_Section nsec; GNUNET_GC_Entry *e; GNUNET_GC_Entry ne; int ret; int i; GNUNET_mutex_lock (data->lock); e = findEntry (data, section, option); if (e == NULL) { sec = findSection (data, section); if (sec == NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -