⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 inifile.c

📁 精通tomcat书籍原代码,希望大家共同学习
💻 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: 299830 $                                           *
 ***************************************************************************/

#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 TEST

static 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 + -