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;
}





