Forum Programmation.c Lire facilement un fichier de configuration

Posté par  .
Étiquettes : aucune
0
16
août
2005
Bonjour,

Je voudrais savoir comment lire le plus facilement possible un fichier de configuration du type variable=valeur...
J'essayes de développer (tant bien que mal :-) pour un thinclient, je veux donc éviter d'utiliser des librairies externes à glibc et à ceux qui sont déjà utilisées (je ne sais pas s'il y en a déjà qui peuvent servir à ca dans la liste) :


ld-2.1.3.so libglib-1.2.so.0 libnsl.so.1 libutil.so.1 libXi.so.6.0
ld-linux.so.2 libglib-1.2.so.0.0.10 libnss_dns-2.1.3.so libvgagl.so libXm.so.3
lib5250.so.0 libglib.so libnss_files-2.1.3.so libvgagl.so.1 libXm.so.3.0.2
lib5250.so.0.0.0 libGL.so.1 libpam.so.0 libvgagl.so.1.4.3 libXmu.so.6
libaudiofile.so.0 libGL.so.1.2 libpam.so.0.72 libvga.so libXmu.so.6.2
libaudiofile.so.0.0.2 libgmodule-1.2.so.0 libpng12.so.0 libvga.so.1 libXmuu.so.1
libc-2.1.3.so libgmodule-1.2.so.0.0.10 libpng12.so.0.1.2.4 libvga.so.1.4.3 libXmuu.so.1.0
libcrypt-2.1.3.so libgmodule.so libproc.so.2.0 libwrap.so.0 libXpm.so.4
libcrypto.so.0 libgtk-1.2.so.0 libproc.so.2.0.7 libwrap.so.0.7.6 libXpm.so.4.11
libcrypto.so.0.9.6 libgtk-1.2.so.0.9.1 libpthread-2.1.3.so libwraster.so.2 libXp.so.6
libcrypt.so.1 libgtk.so libpthread.so.0 libwraster.so.2.2.0 libXp.so.6.2
libc.so.6 libICE.so.6 libqt-mt.so libwvcrypto.so libXrandr.so.2
libcups.so libICE.so.6.3 libqt-mt.so.3 libwvcrypto.so.3.7 libXrandr.so.2.0
libcups.so.2 libImlib.so.1 libqt-mt.so.3.3 libwvstreams.so libXrender.so
libdl-2.1.3.so libiw.so.27 libqt-mt.so.3.3.2 libwvstreams.so.3.7 libXrender.so.1
libdl.so.2 libjpeg.so.62 libresolv-2.1.3.so libwvutils.so libXrender.so.1.2.2
libesd.so.0 libjpeg.so.62.0.0 libresolv.so.2 libwvutils.so.3.7 libXRes.so.1
libesd.so.0.2.23 libltdl.so.3 libslang.so.1 libX11.so.6 libXRes.so.1.0
libexpat.so.0 libltdl.so.3.1.0 libslang.so.1.4.5 libX11.so.6.2 libXt.so.6
libexpat.so.0.4.0 libm-2.1.3.so libSM.so.6 libXaw.so.6 libXt.so.6.0
libfontconfig.so.1 libMagick.so.6 libSM.so.6.0 libXaw.so.6.1 libXtst.so.6
libfontconfig.so.1.0.4 libMagick.so.6.2.3 libssl.so.0 libXaw.so.7 libXtst.so.6.1
libfontenc.so.1 libm.so.6 libssl.so.0.9.6 libXext.so.6 libXxf86vm.so.1
libfontenc.so.1.0 libncurses.so.5 libstdc++-libc6.1-1.so.3 libXext.so.6.4 libXxf86vm.so.1.0
libfreetype.so.6 libncurses.so.5.2 libstdc++-libc6.1-2.so.3 libXft.so.2 libz.so.1
libfreetype.so.6.3.6 libnewt.so.0.50 libstdc++-libc6.2-2.so.3 libXft.so.2.1.2 libz.so.1.1.3
libgdk-1.2.so.0 libnewt.so.0.50.34 libtiff.so.3 libXinerama.so.1
libgdk-1.2.so.0.9.1 libNoVersion.so.1 libungif.so.3 libXinerama.so.1.0
libgdk.so libnsl-2.1.3.so libutil-2.1.3.so libXi.so.6
  • # pub éhontée

    Posté par  (site web personnel) . Évalué à 4.

    En ayant marre de refaire à chaque programme du code pour lire un fichier de config, J'ai développé un parser minimaliste réutilisable pour ce genre de cas. Il est fait pour être intégré comme un module dans le programme et non comme une bibliothèque.

    Il n'a pas besoin de bibliothèque autre que la libc.

    <http://perso.ens-lyon.fr/nicolas.bernard/projects/confloader/index.(...) >
    (nb: l'archive contient un exemple en plus de la doc doxygen).
    • [^] # Re: pub éhontée

      Posté par  . Évalué à 1.

      Merci pour ce programme, j'ai en revenche du mal à le faire fonctionner.

      Lors de la compilation, j'ai eu une erreur, ou plutot un avertissement :
      pavlovix:/prog_TS/confloader-0.1# make
      gcc -Wall -pedantic -ansi -O3 -c confloader.c -o confloader.o
      confloader.c:179:22: Warnung: Verwendung von C99 hexadezimaler Gleitkommakonstante
      confloader.c:179:41: Warnung: Verwendung von C99 hexadezimaler Gleitkommakonstante

      Je ne sais pas si c'est normal ?

      Deuxièmement, étant nouveau dans la programmation en c pour linux, je ne sais pas trop comment intégrer confloader dans mon code, j'ai fait comme indiqué dans la doc, j'ai crée un sous repertoire, maintenant comment faire au niveau de la compilation ?

      J'imagine que je dois compiler mon programme avec confloader
      gcc moprog.c confloader.c -o monprog.o ??

      Mais qu'est ce que je dois faire du confloader.h ?
      Désolé pour cette question qui doit être stupide, mais j'ai encore du mal à comprendre l'utilité et le conctionnement des headers, tout comme les casts... sujet pas abordé dans mon livre :(
      • [^] # Re: pub éhontée

        Posté par  (site web personnel) . Évalué à 2.

        Les warnings ne sont a priori pas graves, du moins tant que tu gardes gcc (il y a des constantes d'un type introduit dans la norme C99, et comme le "-ansi" lui dit que le programme est en C89, il rale.).

        compilation: l'idée est de compiler d'abord confloader en tant que module, puis d'inclure celui-ci à la phase d'édition des liens.

        dans ton makefile (celui de ton programme, pas celui de confloader), tu peux donc avoir:

        monprog: monprog.c confloader.o
        gcc monprog.c confloader.o -o monprog

        confloader.o:
        make -C confloader
        mv confloader/confloader.o .

        Le confloader.h doit être inclu dans tous les fichiers à partir desquels tu veux utiliser une valeur définie dans ton fichier de configuration:
        #include "confloader/confloader.h"
        • [^] # Re: pub éhontée

          Posté par  . Évalué à 1.

          J'ai essayé, mais j'ai une erreur de syntaxe dans le makefile justement là ou il y a la ligne "make -C confloader" Voilà l'erreur : "Makefile:24: *** missing separator."
          CC=gcc
          CFLAGS=-Wall -ansi
          LDFLAGS=-Wall -ansi
          EXEC=tsinventory
          
          all: $(EXEC)
          
          tsinventory: getenv.o getipaddress.o getmac.o confloader.o main.o
                  $(CC) -o $@ $^ $(LDFLAGS)
          
          getenv.o: gentenv.c
                  $(CC) -o $@ -c $< $(CFLAGS)
          
          main.o: main.c
                  $(CC) -o $@ -c $< $(CFLAGS)
          
          getipaddress.o : getipaddress.c
                  $(CC) -o $@ -c $< $(CFLAGS)
          
          getmac.o : getmac.c
                  $(CC) -o $@ -c $< $(CFLAGS)
          
          confloader.o:
          make -C /confloader
          mv confloader/confloader.o
          
          • [^] # Re: pub éhontée

            Posté par  (site web personnel) . Évalué à 2.

            Il faut des tabulations comme pour les autres cibles dans le makefile (elles ont sauté dans mon commentaire précédent, en mettre là où je met "<TAB>"):

            confloader.o:
            <TAB>make -C /confloader
            <TAB>mv confloader/confloader.o
            • [^] # Désolé

              Posté par  . Évalué à 1.

              J'ai encore un problème :
              confloader.o(.text+0x91): In function `confparse':
              : undefined reference to `conf'
              confloader.o(.text+0xb3): In function `confparse':
              : undefined reference to `conf'
              confloader.o(.text+0xc3): In function `confparse':
              : undefined reference to `conf'
              confloader.o(.text+0xd4): In function `confparse':
              : undefined reference to `conf'
              confloader.o(.text+0x13b): In function `getconf':
              : undefined reference to `conf'
              confloader.o(.text+0x152): more undefined references to `conf' follow
              collect2: ld returned 1 exit status
              
              • [^] # Re: Désolé

                Posté par  (site web personnel) . Évalué à 2.

                C'est probablement parce que tu n'as pas défini de tableau
                option conf[] = ...
                pour indiquer quelles options sont autorisées comme indiqué dans la doc.
                Ce tableau est nécessaire pour que confloader sache ce qu'il doit attendre comme nom d'option et leur type dans le fichier de configuration que ton programme va charger...
                • [^] # Re: Désolé

                  Posté par  . Évalué à 1.

                  J'ai essayé en fait sans utiliser la fonction dans une autre fonction, j'ai simplement compiler mes fichiers et celui de confloader comme tu m'as indiqué et obtenu l'erreur plus haut...

                  J'ai ensuite essayé d'ajouté le tableau dans ma fonction main, comme dans la doc et recompilé, même erreur !
                  • [^] # Re: Désolé

                    Posté par  (site web personnel) . Évalué à 2.

                    Le tableau ne doit pas être défini dans main, mais en tant que variable globale!
                    • [^] # Re: Désolé

                      Posté par  . Évalué à 1.

                      La compilation à marché ! ouf !
                      Pourrais-tu me donner un bout de code ou les fonctions sont utilisées ? Ca manque sur le site...

                      Merci pour ta patience, c'est mon tout premier programme, et j'ai encore beaucoup de choses qui m'échappent en c ;)
                      • [^] # Re: Désolé

                        Posté par  (site web personnel) . Évalué à 2.

                        Pas de problème, on a tous commencé un jour ;-)

                        Reprenons donc:
                        - tu as une variable global conf[] qui défini quelles variables pourront se trouver dans ton fichier de configuration, ainsi que leur type.

                        - à un endroit dans ton programme, tu lis le fichier de configuration en faisant confparse("test.conf", stderr), ou test.conf est le fichier de configuration de ton programme, et stderr indique que si des erreurs se produisent (variables inconnues, fichier non trouvé, etc) elles sont affichée sur la sortie d'erreur standard. Cette fonction renvoie -1 en cas d'erreur, le nombre de variables lues dans le fichier si tout va bien.

                        - ensuite, tu peux accéder aux valeurs lues via la fonction getconf, qui renvoie un valeur de type "option", c'est à dire une structure. Le plus simple est de faire du "pseudo-objet" et d'accéder à la valeur d'une option opt de type typ par getconf("opt").value.typ, sachant que typ doit valoir:
                        yn si l'option est booléenne (type YESNO indiqué dans conf[]);
                        i dans le cas d'un entier (INTOPT);
                        f dans le cas d'un flottant (FLOATOPT);
                        str dans le cas d'une chaine de caractères (STRINGOPT).

                        Par exemple, si dans ton tableau conf[] tu as une ligne
                        {"Debug", YESNO, 1, {0}}
                        alors dans ton programme tu peux avoir:

                        if (getconf("Debug").value.yn) {
                        /* faire qqch si "Debug = yes" est défini dans
                        le fichier de configuration. */
                        }

                        Je reconnais que la doc pourrait être plus explicite... je vais voir ca ;-)

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.