config file beolvasás c-ben

Fórumok

Tudtok ajánlani valami egyszerű megoldást, hogy hogyan tudnék legy egyszerübben beolvasni egy config filet, ami beállítja a program futási paramétereit.
olyansmire gondolok ami feltölti a változókat értékekkel, mint pl bash-ben a ". config.sh"

köszi

Hozzászólások

Ha könnyen konfigurálható valamit akarsz, akkor pl. használj egy XML-parsert, vagy Lua-t.

nem kell ide semmilyen lib. mindeki megvan baszva ezzel :)
Gratulálok.

Szánalmas ez a hozzáálás. Ugyebár csakis OpenBSD-ben lehet jó kódot találni.

(http://www.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/ntpd/parse.y
Parser-t pedig ott is csak az ntpd-ben... :))

Na mindegy, ez van.

Azért ha megnézed a forrást, láthatod, hogy ezt a parsert is a yacc generálja.

Azt sem értem, miért baj, ha uberhaxor libhez kellene linkelni, esetleg még talán jobb is lehet...

ps: tudom, h a yacc LALR(1)... csak azért ne keverjük már a fogalmakat... ebben a stílusban...

szvsz félreértettél (vagy én bennetek :)): én nem a konkrét példára írtam a külső könyvtárat, hanem általánosságban: előfordulhat, hogy sokat nyerhetsz vele.
Ha csak egyszerű változó=érték párost kell beolvasni, akkor trivi a parser.

(bár ha megnézed a nagyokat, láthatod, hogy a yacc még egyszerű esetben is kikerülhetetlen. :))

A félreértés emberi dolog :-). Láttam én már olyan embert, aki ilyen problémára könyvtárat használt. Persze aztán ilyenkor csak mosolyogni tudok, amikor az ilyen kódot mindenféle optimalizáló flagekkel fordítják. Általánosságban persze hogy jó dolog, én is használom :)

Ebben tokeletesen igaza van, thuglife-nak... bison/yacc es legalabb valami erdekeset is tanulsz... Ha meg glib-ezel (GTK+), akkor annak is van Lexical pasrser-e...

Zsiraf

p.s.: amugy meg kb ennyi, ha nem akarod tulvarialni:


fscanf(cf, "%32[A-Za-z]", nev);
fscanf(cf, "%*[ \t]%c%*[ \t]", &chr);
if (chr != '=') {
  error();
}

switch(config_type(nev)) {
case INT:
  fscanf(cf, "%i%c", &var_i, &chr);
  ...
  break;
case STR:
  fscanf(cf, "%s%c", var_s, &chr);
  ...
  break;
...
}
if(chr != '\n') {
  error();
}

;-) de nyugodtan kiserletezz libxml2-vel ;-)

C vagy C++?

Ha c, akkor a bison/yacc jó választás lehet.

Ha C++, akkor a Boost Spirit-je jó választás lehet.
Persze nem árt, ha nem vagy kezdő c++-ban....

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

Nagyon köszi a segítséget... Tutin megtudtam oldani.

De lenne itt még valami.

lenne egy string pl; 00,123,HHU,,0181,,,,22, ......
A pontosvesszők között lévő részt akarom kihalászni változókba. Egész jól megy sscanf-el, de azon mezőkkel nem tudok mit kezdeni, aminek nincs értéke (;; közötti rész).
Ezzel próbálkoztam:
sscanf(data,"%[0-9]%*[,]%[0-9]%*[,]%[A-Z]%*[,]%[0-9]%*[,]%[0-9]%*[,]....",v1,v2,v3,v4,v5...);
A sorrend az adott.
Olyasmire lenne szükségem mint az "awk -F, ...."

Valami egyéb ötlet?

Nekem nem egészen világos amit írtál, mert a példádban nincs egyetlen ; sem...
Tehát akkor mi működik és mi nem?
Mi lehet a bemenet?
Ez az sscanf most működik?

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o


#include <stdio.h>
#include <string.h>

int main(int argc, char **argv)
{
  char *next;

  if (argc <= 1)
    return printf("Arg kellene...\n");

  while ((next = strsep(&argv[1], ",")))
    {
      printf("Token: '%s'\n", next);
    }
  return 0;
}

fules@chaos:~$ ./tok 'egy,ketto,,   negy   , ot'
Token: 'egy'
Token: 'ketto'
Token: ''
Token: '   negy   '
Token: ' ot'

Ha nincs strsep, akkor ír magának egyet a polgár:

char	*strsep(char **src, const char *separator)
{
	const char *sp;
	char	*tok;
	char	*begin;

	if (!*src || !**src)
		return NULL;

	begin = tok = *src;
	while (*begin) {
		for (sp = separator; *sp; sp++) {
			if (*sp == *begin) {
				*begin++ = 0;
				*src = begin;
				return (tok);
			}
		}
		begin++;
	}
	*miben = NULL;
	return (tok);
}

Ahogy mondja, kolléga, csak nálam vmiért nem jött be a hup az imént :(.


#include <stdio.h>

const char *strchr(const char *s, int c)
{
  if (!s)
    return NULL;

  while (*s && (*s != c))
    s++;

  return *s ? s : NULL;
}


char *strsep(char **s, const char *delim)
{
  char *q;

  if (!s || !*s || !delim || !*delim)
    return NULL;

  q = *s;
  while (**s && !strchr(delim, **s))
    (*s)++;

  if (**s)
    *((*s)++) = '\0';
  else
    *s = NULL;

  return q;
}

int main(int argc, char **argv)
{
  char *next;

  if (argc <= 1)
    return printf("Arg kellene...\n");

  while ((next = strsep(&argv[1], ",")))
    printf("Token: '%s'\n", next);

  return 0;
}

Az eredeti is olyan, hogy átírja a bemenetet?

Egyébként ha már magánk kell írni, akkor ez ágyúval verébre szerintem. Adott feladatra egyszerűbben is meg lehet oldani...

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

Át. Mind az strsep, mind az strtok. De sajnos kell is nekik, különben lehetne malloc()-kal foglalgatni meg felszabadítgatni, ráadásul menet közben, és a régi oskola szerint a rendszer/program egy stabil, kezelhető állapotot akkor hagyjon el, ha minden erőforrás a kezében van, amivel elér a köv. stabil, kezelhető állapotba, így nem lesznek olyan hibák, amikkel nem tudunk mit kezdeni. És, ha már nosztalgiázok, a malloc() igencsak drága műveletnek számít, persze nem az xmlNewDocNode()-hoz képest :).

Amágy inkább érzem ágyúval verébre lövésnek a külső lib-re való függést, ezt inkább nevezném a gatyamadzag méretre vágásának :).

Világos...

Bár nekem szinpatikusabb megoldás lett volna egy "char *dst" argumentum mint pl strncpy-nál.
Igaz akkor meg strnsep, meg strntok kellett volna.
Ekkor nem is kell malloc, csak str(n)cpy.
Na sebaj, ez van, ezt kell szeretni. :)

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

Ilyen esetben, ket mod van:

1. atalakitod a kikopott file-t pl. sed-el olyan formara, ami "szigoru" es akkor problema nelkul tudsz egy sscanf-el dolgozni.
technikailag akar ugy is lehet, hogy a feldologozo program elott van egy script, ami csinal egy temp file-t a config-bol, s arra hivja meg a programodat (wrapper)

2. kenytelen vagy szetszedni a scanf-t, mivel itt nem tudsz olyan hivatkozast adni, mint regex-nel, hogy ha nincs akkor is jo... ;-)
Tehat a elemi lepesekre kell szedni. Ha string-bol dolgozol akkor %n-t kell hasznalni...


if(sscanf(data,"%[0-9]%*[,]%n%1c", v1,n,c) != 2)
{
  error();
}
if (c == ',')
{
  a_kovetkezo_ures(-:-)
}
else if(sscanf(data += n ,"%[0-9]%*[,]%n%1c", v1,n,c) != 2)
{
  error();
}
if (c == ',')
{
  a_kovetkezo_ures(-:-)
}
...

Persze mindezt szet lehet szedni rutinokra...

Zsiraf

Ha már szétszedjük, szedjük szét rendesen. :)


#include <string.h>

int main ()
{
  char data[]="00,123,HHU,,0181";
  unsigned int i=0,j=0;
  char temp[10];

  while (data[ i ])
  {
    if (data[ i ]==',')
    {
       strncpy(temp,data+j,i-j);
       temp[i-j]=0;
       j=i+1;
			
       // Csinalj temppel amit akarsz

    }
    ++i;
  }
  return 0;
}

Tudom, mutatókkal C-sebb lenne, de nem akartam senkit lefárasztani...

"...handing C++ to the average programmer seems roughly comparable to handing a loaded .45 to a chimpanzee."
-- Ted Ts'o

Tudnám javasolni a környezeti változókat, mint olyat :).
Ha nem fáj, hogy a programod config file-ja egyben indító script is (mint pl. az init scriptek némelyike), akkor:


VAR0="izebigyo"
VAR1="hozearmando"

/usr/local/bin/progineve

Valamint a progiban:


#include <stdlib.h>
#include <stdio.h>

int main(void)
{
  char *p;

  p = getenv("VAR0");
  printf("VAR0 = '%s'\n", p ? p : "null");
  p = getenv("VAR1");
  printf("VAR1 = '%s'\n", p ? p : "null");
  p = getenv("PATH");
  printf("PATH = '%s'\n", p ? p : "null");
  p = getenv("USER");
  printf("USER = '%s'\n", p ? p : "null");
  return 0;
}

A kulcsmozzanat: man getenv

sscanf helyett akanlom a strchr es meg par str fuggveny hasznalatat, mert akkor tuti azt dolgozod fel amit akarsz nem pedig valamit visszakapsz alapon muxik. Ezt csak azert irom, mert eloszor en is sscanf-el probalkoztam ilyenre, de szivtam is vele. Amugy tgt-ben van meg jo config feldolgozo.