Parsowanie plików konfiguracyjnych

    -- Sebastian Pawlak, 2005.


Przedstawione funkcje umożliwiają dokonywanie operacji na prostych plikach konfiguracyjnych.


Kod źródłowy pliku "confParser.h":

/* confParser.h: biblioteka funkcji pozwalajacych odczytac i modyfikowac
 *               pliki konfiguracyjne.
 *
 * Sebastian Pawlak, 2005.
 */

#ifndef _CONF_PARSER_H_
#define _CONF_PARSER_H_

/* dopuszczalne parametry pliku konfiguracyjnego */
enum {
    MAX_LINE = 255,    /* max. rozmiar wiersza */
    MAX_IDENT = 32,    /* max. dlugosc identyfikatora */
    MAX_VAL = 64       /* max. dlugosc wartosci */
};

typedef struct ident {
    char *ident;       /* nazwa identyfikatora w pliku konfiguracyjnym */
    char type;         /* typ zmiennej: s - char[], i - int */
    void *var;         /* wskaznik na zmienna, do ktorej przypisac/skopiowac */
} ident;

int parseConf(const char *fileName, const ident idns[]);
int exchangeConf(const char *fileName, const char *ident, const char *val);

#endif

Kod źródłowy pliku "confParser.c":

/* confParser.c: biblioteka funkcji pozwalajacych odczytac i modyfikowac
 *               pliki konfiguracyjne.
 *               Plik konfiguracyjny moze miec postac, jak na przykladzie:
 *
 *               # komentarz
 *               zmiennaLiczbowa 10   # komentarz
 *
 *               zmiennaTekstowa "cogito ergo sum"
 *
 * Sebastian Pawlak, 2005.
 */

#include <stdio.h>
#include <unistd.h>     /* dla close() */
#include <string.h>     /* dla strcmp(), strcpy() */
#include <stdlib.h>     /* dla strtol() */
#include <fcntl.h>      /* O_RDONLY */
#include "confParser.h"


/* parseConf: odczytuje z pliku dane konfiguracyjne i przypisuje
 *            wartosci odpowiednim zmiennym. 
 *            Wiersz pliku ma stanowic pare: identyfikator wartosc
 *            Identyfikator musi byc oddzielony od wartosci conajmniej jednym
 *            bialym znakiem.
 *            Poszczegolne pary musza byc w kolejnych wierszach.
 *            Komentarz rozpoczyna sie znakiem # i konczy wraz z koncem
 *            wiersza.
 *            Max. dlugosc wiersza = MAX_LINE
 *            Max. dlugosc identyfikatora = MAX_IDENT
 *            Max. dlugosc wartosci = MAX_VAL
 */
int parseConf(const char *fileName, const ident idns[])
{
    int i;
    FILE *f;
    char *p, *q;
    char s[MAX_LINE + 1], t[16], ident[MAX_IDENT + 1], val[MAX_VAL];

    if ((f = fopen(fileName, "r")) == NULL)
        return -1;

    /* tworzy string postaci: %16s %64s */
    sprintf(t, "%%%ds %%%ds", MAX_IDENT, MAX_VAL);

    while (fgets(s, MAX_LINE, f) != NULL) {  /* kolejny wiersz */

        /* jesli nie odczytano dwoch tokenow lub mamy komentarz ... */
        if ((sscanf(s, t, ident, val) != 2) || (ident[0] == '#') ||
            (val[0] == '#'))
            continue;

        /* jesli wartosc ujeta jest w cudzyslowy */
        if ((val[0] == '\"') &&
            ((p = strchr(s, '\"')) != NULL) &&    /* pierwszy cudzyslow */
            ((q = strchr(p + 1, '\"')) != NULL)) {        /* zamykajacy */

            strncpy(val, p + 1, q - p - 1);
            val[q - p - 1] = '\0';
        }


        /* przypisywanie zmiennym wartosci odczytanych z pliku */
        for (i = 0; idns[i].ident != NULL; i++)
            if (!strcmp(idns[i].ident, ident))
                switch (idns[i].type) {
                    case 's':  /* string */
                        strcpy(idns[i].var, val);
                        break;
                    case 'i':  /* integer */
                        *((int *)idns[i].var) = strtol(val, NULL, 10);
                        break;
                    default:
                        fprintf(stderr, "Bledny typ parametru!\n");
                        fclose(f);
                        return -1;
                        break;
                }
    }

    fclose(f);

    return 0;
}


/* exchangeConf: modyfikuje wartosc dla podanego identyfikatora w pliku
 *               konfiguracyjnym.
 *               Wczytuje plik do pamieci, modyfikuje wartosc, zapisuje plik.
 *               Wartosc moze miec dlugosc wieksza/mniejsza niz dlugosc
 *               poprzedniej wartosci.
 */
int exchangeConf(const char *fileName, const char *ident, const char *val)
{
    long int i = 0, siz;
    int f, j = 0, isComment = 0, isIdent = 0;
    unsigned char *buf = NULL, c, *p = NULL;

    if ((f = open(fileName, O_RDONLY, 0)) == -1)
        return -1;

    if ((siz = lseek(f, 0, 2)) == -1)     /* rozmiar pliku -- lseek na koniec */
        return -2;

    if (lseek(f, 0, 0) == -1)             /* spowrotem na poczatek pliku */
        return -3;

    if ((buf = (unsigned char *)malloc(siz + 1)) == NULL)  /* pamiec */
        return -4;

    if ((siz = read(f, buf, siz)) == -1)  /* wczytywanie pliku */
        return -5;

    buf[siz] = '\0';

    close(f);

    if ((f = open(fileName, O_WRONLY | O_TRUNC, 0)) == -1)
        return -6;

    while (i < siz) {

        c = buf[i++];                  /* znak z bufora */

        if (c == '#')                  /* komentarz */
            isComment = 1;

        else if (c == '\n')            /* koniec komentarza (nowy wiersz) */
            isComment = 0, isIdent = 0, j = 0;

        else if (isComment == 0) {

            if (isIdent == 0) {        /* nie-identyfikator */

                if (c == ident[j]) {   /* kolejny znak sie zgadza */
                    j++;

                    if (j == strlen(ident)) {  /* caly ident sie zgadza */
                        j = 0;

                        /* jesli nastepny znak po 'c' to bialy znak */
                        if ((buf[i] == ' ') || (buf[i] == '\t'))
                            isIdent = 1;
                    }

                } else
                    j = 0;

            } else {                  /* isIdent == 1   identyfikator */

                if ((c != ' ') && (c != '\t')) {    /* poczatek wartosci */

                    write(f, val, strlen(val));     /* zapis nowej wartosci */

                    /* ominiecie starej wartosci w buforze */
                    if ((p = strpbrk(&buf[i], " \n\t")) != NULL)
                        i += p - &buf[i];
                    else
                        i = siz;

                    isIdent = 0;
                    continue;
                }
            }
        }

        write(f, &c, 1);  /* zapis znaku do pliku */
    }

    close(f);

    return 0;
}

Kod źródłowy pliku "main.c":

#include <stdio.h>
#include "confParser.h"

int main(void)
{
    int zmienna = 0, cogito = 0;
    char ergo[MAX_VAL + 1] = "";

    const ident parametry[] = { { "zmienna", 'i', &zmienna },
                                { "cogito",  'i', &cogito },
                                { "ergo",    's', ergo    },
                                { NULL } }; 

    /* odczyt parametrow z pliku konfiguracyjnego "plik.conf" */
    if (parseConf("plik.conf", parametry) != 0) {
        fprintf(stderr, "Blad odczytu konfiguracji z pliku!\n");
        exit(-1);
    }

    fprintf(stdout, "zmienna: %d\n",  zmienna);
    fprintf(stdout, "cogito:  %d\n",  cogito);
    fprintf(stdout, "ergo: \"%s\"\n", ergo);

    return 0;
}
w3cw3c
automatyka przemysłowa