Confetti - simple and quick configuration of your project

    If you write a project a little more than average, then as a rule you are faced with settings and configuration. There are quite a few C / C ++ solutions, I want to tell you about another rather simple and beautiful solution from the Mail @ Ru Company, which I used in my project

    . I myself used different config parsers, in recent projects I used re2c (the config was similar to nginx config). In re2c there is even a little bit to do with sweets - is code generation:
    no it is not necessary to code configuration files and structures, all of you will do Mage Confetty.

    Unfortunately, no documentation whatsoever, otherwise this article would not have been. To those interested, we ask ...


    Install the source
    c GitHub github.com/mailru/confetti
    The basic requirement is to install YACC.

    The example folder has a usage example. Using the example and building the config is intuitive. The whole point is the sequential implementation of several steps: If you look at an example, it will be clear how to implement it in the project. The following are the implementation steps for my project.
    // 1. генерация файла конфигурации из шаблона example.cfgtmpl:
    ../confetti -i example.cfgtmpl -n my_product -f my_product.cfg

    // 2. генерация h и с файлов структур конфигурации и их компиляция:
    ../confetti -i example.cfgtmpl -n my_product -h my_product_cfg.h
    ../confetti -i example.cfgtmpl -n my_product -c my_product_cfg.c
    gcc -Wall -g -O0 -Werror -std=gnu99 -I. -c my_product_cfg.c

    // 2. генерация и компиляция парсера:
    ../confetti -i example.cfgtmpl -H prscfg.h
    ../confetti -i example.cfgtmpl -p prscfg.c
    gcc -Wall -g -O0 -Werror -std=gnu99 -I. -c prscfg.c

    // 4. компиляция и сборка примера
    gcc -Wall -g -O0 -Werror -std=gnu99 -I. -c example.c
    gcc -o example example.o my_product_cfg.o prscfg.o




    1. created a folder in the sources of his project

    cd config.src

    2. rewrote the executable file

    cp confetty / usr / local / bin

    3) fixed the make file

    in relation to my project: Please note, I added the install target, which copies the generated files to the sources of my project.
    CONFETTI=/usr/local/bin/confetti
    NAME=tarantool_proxy
    CFG=tarantool_proxy.cfgtmpl

    test_OBJS=tarantool_proxy_cfg.o tnt_config.o prscfg.o

    all: $(NAME).cfg test

    .SUFFIXES: .o.c

    .c.o:
    $(CC) $(CFLAGS) $(INCLUDE) -c $<

    test: $(test_OBJS)
    $(CC) -o $@ $(test_OBJS) $(LIB)

    tarantool_proxy: $(test_OBJS)
    $(CC) -o $@ $(test_OBJS) $(LIB)

    $(NAME).cfg: $(CFG)
    $(CONFETTI) -i $< -n $(NAME) -f $(NAME).cfg
    $(CONFETTI) -i $< -n $(NAME) -h $(NAME)_cfg.h
    $(CONFETTI) -i $< -n $(NAME) -c $(NAME)_cfg.c

    prscfg.c: $(CFG)
    $(CONFETTI) -i $< -p $@

    prscfg.h: $(CFG)
    $(CONFETTI) -i $< -H $@

    prscfg.c: prscfg.h $(NAME)_cfg.h

    $(NAME)_cfg.c: prscfg.h $(NAME)_cfg.h

    clean:
    rm -f $(NAME).cfg $(NAME)_cfg.c $(NAME)_cfg.h
    rm -f prscfg.c prscfg.h
    rm -f test
    rm *.o

    install:
    cp $(NAME).def.cfg ../cfg/$(NAME).cfg
    cp tarantool_proxy_cfg.o ..
    cp prscfg.o ..
    cp *.h ..



    3) created a template configuration file

    from example.cfgtmpl
    in the% {} block replaced the file name with the name that should be in the tarantool_proxy_cfg.h project:
    % {
    #include 
    #include 
     
    void out_warning (ConfettyError r, char * format, ...);
    %}: 
     

    4. created my own configuration

    and checked it: Added the missing part of the tarantool_proxy.cfgtmpl config as applied to his:
    confetti -i tarantool_proxy.cfgtmpl -n tarantool_proxy -f tarantool_proxy.cfg


    pid = "/usr/local/var/tarantool_proxy.pid"
    log = "/usr/local/var/log/tarantool_proxy.log"
     
    daemon = 1
     
    pool_size = 4096 
     
    # count of threads
    threads = 4
     
    #listen
    host = "localhost"
    port = 33013
     
    # server connections
    server = [
     
    hostname = "localhost"
    port = 33013
    namespace = [
      key = NULL, required
    ]
    ]
     
    namespace = [
    type = NULL, required
    ]
     

    5. after generating the configuration file

    tarantool_proxy.cfg copied it to the default configuration file: tarantool_proxy.def.cfg and filled it with the necessary data (some of them):

    server [0] .hostname = "host2"
    server [0] .port = 33013
     
    server [1] .hostname = "host1"
    server [1] .port = 33023
     
     
    namespace [1] .type = "str"
    namespace [0] .type = "int"
     
     
    server [0] .namespace [0] .key = "345"
    server [0] .namespace [1] .key = "abc"
     
    server [1] .namespace [0] .key = "xyz "
    server [1] .namespace [1] .key =" 345 "


    The values ​​specified in the template file are used by default.
    Further, I used this file as a double, since the tarantool_proxy.cfg file is constantly overwritten by confetti

    6. created an example file tester based on example.c.


    7. do make until everything goes well

    it will be amazing if it works the first time :)

    We get : As for the “DIRECT” block, this is testing direct access:./test
    ==========Accepted: 11; Skipped: 0===========
    pid => '/usr/local/var/tarantool_proxy.pid'
    log => '/usr/local/var/log/tarantool_proxy.log'
    daemon => '1'
    pool_size => '4096'
    threads => '4'
    host => 'localhost'
    port => '33013'
    server[0].hostname => 'localhost'
    server[0].port => '33013'
    server[0].namespace[0].key => '345'
    server[0].namespace[1].key => 'abc'
    server[1].hostname => 'tfn24'
    server[1].port => '33023'
    server[1].namespace[0].key => 'xyz'
    server[1].namespace[1].key => '345'
    namespace[0].type => 'int'
    namespace[1].type => 'str'
    ==========DIRECT=========
    pid=/usr/local/var/tarantool_proxy.pid
    daemon=1
    keys
    ==========Destroy=========


    printf ("========== DIRECT ========= \ n");
    printf ("pid =% s \ n", cfg.pid);
    printf ("daemon =% d \ n", cfg.daemon);
     

    or access to array elements:
    tarantool_proxy_namespace ** it = cfg.namespace;
    while (* it! = NULL) {
    printf ("namespace type =% s \ n", (* it) -> type);
    ++ it;
    }
     

    So what now remains:

    1. Make make install, which will rewrite all the necessary files into the directory of your project.
      The config.src directory remains the test site.
    2. In your own project, include #include {name} _cfg.h where {name} is the name that you selected when generating the config file (in my project tarantool_proxy)
    3. Declare the source configuration and assign default values
      tarantool_proxy cfg;
      char * key, * value;
      fill_default_tarantool_proxy (& cfg);
       

    4. Declare the configuration file and read it:
      int nAccepted, nSkipped;
      FILE * fh = fopen (filename, "r");
       
      if (! fh) {
      fprintf (stderr, "Could not open file% s \ n", argv [1]);
      return 1;
      }
       
      useStdout = 1;
      parse_cfg_file_tarantool_proxy (& cfg, fh, 1, & nAccepted, & nSkipped);
      printf ("========== Accepted:% d; Skipped:% d =========== \ n", nAccepted, nSkipped);
      fclose (fh);
       


      If we use arrays, then we declare iterators:
      tarantool_proxy_iterator_t * i;
      i = tarantool_proxy_iterator_init ();
       
      while ((key = tarantool_proxy_iterator_next (i, & cfg, & value))! = NULL) {
      if (value) {
      printf ("% s => '% s' \ n", key, value);
      free (value);
      } else {
      printf ("% s => (null) \ n", key);
      }
      }
       



    Or we use “direct” access to data structures, as mentioned above.
    That's all, reconfiguring the project (changing the structure of the config) now takes no more than 5 minutes.

    I hope that this will save a lot of time for someone.
    Thanks to the author Teodor Sigaev

    Also popular now: