📄 inifile.c
字号:
/* * Copyright 1999-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//*************************************************************************** * Description: DSAPI plugin for Lotus Domino * * Author: Andy Armstrong <andy@tagish.com> * * Date: 20010603 * * Version: $Revision: 1.4 $ * ***************************************************************************/#include "config.h"#include "inifile.h"#include <ctype.h>#include <stdlib.h>#include <stdio.h>#include <string.h>/* We have one of these for each ini file line. Once we've read the * file and parsed it we'll have an array in key order containing one * of these for each configuration item in file. */typedef struct{ const char *key; const char *value;} inifile_key;static char *file; /* the text of the ini file */static inifile_key *keys; /* an array of keys, one per item */static size_t klen; /* length of the key array *//* Text that will prefix all of our error messages */#define ERRPFX "INIFILE: "/* Various error messages that we can return */ERRTYPE inifile_outofmemory = ERRPFX "Out of memory";ERRTYPE inifile_filenotfound = ERRPFX "File not found";ERRTYPE inifile_readerror = ERRPFX "Error reading file";#define SYNFMT ERRPFX "File %s, line %d: %s"/* Case insensitive string comparison, works like strcmp() */static int inifile__stricmp(const char *s1, const char *s2){ while (*s1 && tolower(*s1) == tolower(*s2)) s1++, s2++; return tolower(*s1) - tolower(*s2);}/* Compare keys, suitable for passing to qsort() */static int inifile__cmp(const void *k1, const void *k2){ const inifile_key *kk1 = (const inifile_key *)k1; const inifile_key *kk2 = (const inifile_key *)k2; return inifile__stricmp(kk1->key, kk2->key);}/* Return a new syntax error message. */static ERRTYPE inifile__syntax(jk_pool_t *p, const char *file, int line, const char *msg){ static const char synfmt[] = SYNFMT; size_t len = sizeof(synfmt) + strlen(msg) + strlen(file) + 10 /* fudge for line number */ ; char *buf = jk_pool_alloc(p, len); sprintf(buf, synfmt, file, line, msg); return buf;}/* Various macros to tidy up the parsing code *//* Characters that are OK in the keyname */#define KEYCHR(c) \ (isalnum(c) || (c) == '.' || (c) == '_')/* Skip whitespace */#define SKIPSPC() \ while (*fp == '\t' || *fp == ' ') fp++/* Skip to the end of the current line */#define SKIPLN() \ while (*fp != '\0' && *fp != '\r' && *fp != '\n') fp++/* Move from the end of the current line to the start of the next, learning what the * newline character is and counting lines */#define NEXTLN() \ do { while (*fp == '\r' || *fp == '\n') { if (nlc == -1) nlc = *fp; if (*fp == nlc) ln++; fp++; } } while (0)/* Build the index. Called when the inifile is loaded by inifile_load() */static ERRTYPE inifile__index(jk_pool_t *p, const char *name){ int pass; int ln = 1; int nlc = -1; /* Make two passes over the data. First time we're just counting * the lines that contain values so we can allocate the index, second * time we build the index. */ for (pass = 0; pass < 2; pass++) { char *fp = file; char *ks = NULL, *ke; /* key start, end */ char *vs = NULL, *ve; /* value start, end */ klen = 0; while (*fp != '\0') { SKIPSPC(); /* turn a comment into an empty line by moving to the next \r|\n */ if (*fp == '#' || *fp == ';') SKIPLN(); if (*fp != '\0' && *fp != '\r' && *fp != '\n') { ks = fp; /* start of key */ while (KEYCHR(*fp)) fp++; ke = fp; /* end of key */ SKIPSPC(); if (*fp != '=') return inifile__syntax(p, name, ln, "Missing '=' or illegal character in key"); fp++; /* past the = */ SKIPSPC(); vs = fp; SKIPLN(); ve = fp; /* back up over any trailing space */ while (ve > vs && (ve[-1] == ' ' || ve[-1] == '\t')) ve--; NEXTLN(); /* move forwards *before* we trash the eol characters */ if (NULL != keys) { /* second pass? if so stash a pointer */ *ke = '\0'; *ve = '\0'; keys[klen].key = ks; keys[klen].value = vs; } klen++; } else { NEXTLN(); } } if (NULL == keys && (keys = jk_pool_alloc(p, sizeof(inifile_key) * klen), NULL == keys)) return inifile_outofmemory; } /* got the index now, sort it so we can search it quickly */ qsort(keys, klen, sizeof(inifile_key), inifile__cmp); return ERRNONE;}/* Read an INI file from disk */ERRTYPE inifile_read(jk_pool_t *p, const char *name){ FILE *fl; size_t flen; int ok; if (fl = fopen(name, "rb"), NULL == fl) return inifile_filenotfound; fseek(fl, 0L, SEEK_END); flen = (size_t) ftell(fl); fseek(fl, 0L, SEEK_SET); /* allocate one extra byte for trailing \0 */ if (file = jk_pool_alloc(p, flen + 1), NULL == file) { fclose(fl); return inifile_outofmemory; } ok = (fread(file, flen, 1, fl) == 1); fclose(fl); if (!ok) return inifile_readerror; file[flen] = '\0'; /* terminate it to simplify parsing */ return inifile__index(p, name);}/* Find the value associated with the given key returning it or NULL * if no match is found. Key name matching is case insensitive. */const char *inifile_lookup(const char *key){ int lo, mid, hi, cmp; if (NULL == keys) return NULL; for (lo = 0, hi = klen - 1; lo <= hi;) { mid = (lo + hi) / 2; cmp = inifile__stricmp(key, keys[mid].key); if (cmp < 0) /* key in array is greater */ hi = mid - 1; else if (cmp > 0) lo = mid + 1; else return keys[mid].value; } return NULL;}#ifdef TESTstatic jk_pool_t pool;extern void jk_dump_pool(jk_pool_t *p, FILE * f); /* not declared in header */int main(void){ ERRTYPE e; unsigned k; int rc = 0; jk_open_pool(&pool, NULL, 0); e = inifile_read(&pool, "ok.ini"); if (e == ERRNONE) { printf("%u keys in ok.ini\n", klen); for (k = 0; k < klen; k++) { const char *val = inifile_lookup(keys[k].key); printf("Key: \"%s\", value: \"%s\"\n", keys[k].key, val); } } else { printf("Error reading ok.ini: %s\n", e); rc = 1; } e = inifile_read(&pool, "bad.ini"); if (e == ERRNONE) { printf("%u keys in bad.ini\n", klen); for (k = 0; k < klen; k++) { const char *val = inifile_lookup(keys[k].key); printf("Key: \"%s\", value: \"%s\"\n", keys[k].key, val); } rc = 1; /* should be a syntax error */ } else { printf ("Error reading bad.ini: %s (which is OK: that's what we expected)\n", e); } jk_dump_pool(&pool, stdout); jk_close_pool(&pool); return rc;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -