Sophie

Sophie

distrib > Mandriva > 2008.1 > x86_64 > by-pkgid > 57a94fd8eb9a4a6b0138af61a0f7b529 > files > 19

dotconf-examples-1.0.13-2mdv2008.1.x86_64.rpm


/* You need at least dot.conf 1.0.9 to compile and run this example !! */



#include <stdio.h>      /* fprintf(), stderr       */
#include <stdlib.h>     /* realloc()               */
#include <string.h>     /* strcmp()                */
/* this example does not work for WIN32 */

#ifndef WIN32
#include <dlfcn.h>      /* dlopen(), dlerror(), dlclose() */
#include <unistd.h>
#endif

#include <libpool.h>
#include <dotconf.h>

struct config_context {
   long                 current_context;
   char                 current_end_token[1024];

   pool_t *             pool;
};

struct ptr_list {
   int      n_entries;
   void **  entries;
};

static DOTCONF_CB(section_open);
static DOTCONF_CB(section_close);
static DOTCONF_CB(common_option);
static DOTCONF_CB(addmodule_option);

/*
// the last field is used to specify the context needed for
// each option. These will be checked at runtime by our contextchecker
//
*/
static const configoption_t options[] = {
   { "AddModule",       ARG_LIST,   addmodule_option, NULL, 0  },
   { "ToggleOption",    ARG_TOGGLE, common_option,    NULL, 0  },
   LAST_OPTION
};

/*
// The pointer list of dynamic options.
// This is necessary to be able to free it up later.
//
*/
struct ptr_list         memory_junk          ;

#define MAX_MODULES       10
static void *handles[MAX_MODULES];  /* handles of dynamically loaded modules */


const char *context_checker(command_t *cmd, unsigned long option_context) {
   struct config_context *context = cmd->context;

   if (context->current_context != option_context) {
      return pool_strcat(
               context->pool, "Option '", cmd->name, "' not allowed in <",
               (strlen(context->current_end_token)>2) ? context->current_end_token + 2 : "global>",
               " context", NULL);
   }

   return NULL;
}

FUNC_ERRORHANDLER(error_handler) {
   fprintf(
      stderr, "%s:%ld:[error] %s\n",
      configfile->filename, configfile->line, msg);

   /* continue reading the configfile ; return 1 stop after first error found */
   return 0;
}


int main(
   int                     argc,
   char *                  argv[]
)  {
   configfile_t *          configfile;
   struct config_context   context;

   if (argc < 2) {
      fprintf(stderr, "Usage : %s <configfile>\n", argv[0]);
      exit(1);
   }
   context.current_end_token[0]  =  '\0';
   context.current_context       =  0;
   context.pool                  =  pool_new(NULL);

   memory_junk.n_entries         =  0;
   memory_junk.entries           =  0;

   memset(handles, 0, sizeof(handles));

   configfile = dotconf_create(
                  argv[1], options, (void *)&context,
                  CASE_INSENSITIVE | DUPLICATE_OPTION_NAMES);
   if (!configfile) {
      fprintf(stderr, "Error opening configuration file\n");
      exit(1);
   }
   configfile->errorhandler   = (dotconf_errorhandler_t) error_handler;
   configfile->contextchecker = (dotconf_contextchecker_t) context_checker;

   if (dotconf_command_loop(configfile) == 0) {
      fprintf(stderr, "Error reading configuration file\n");
      exit(1);
   }

   dotconf_cleanup(configfile);
   pool_free(context.pool);

   /* clean up the possible memjunk which needed to stay in memory */
   if (memory_junk.n_entries) {
      int idx;
      for (idx = 0 ; idx < memory_junk.n_entries ; idx++) {
         free(memory_junk.entries[idx]);
      }
   }
   free(memory_junk.entries);

   return 0;
}


DOTCONF_CB(section_open) {
   struct config_context * context           = (struct config_context *)ctx;
   const char *            old_end_token     = context->current_end_token;
   int                     prev_context      = context->current_context;
   const char *            err               = 0;

   context->current_context = (long)cmd->option->info;
   sprintf(context->current_end_token, "</%s", cmd->name+1);

   while (!cmd->configfile->eof) {
      err = dotconf_command_loop_until_error(cmd->configfile);
      if (!err) {
         err = pool_strcat(context->pool, "</", cmd->name+1, " is missing", NULL);
         break;
      }

      if (err == context->current_end_token) {
         break;
      }
      dotconf_warning(cmd->configfile, DCLOG_ERR, 0, err);
   }

   sprintf(context->current_end_token, "%s", old_end_token);
   context->current_context = prev_context;

   if (err != context->current_end_token) {
      return err;
   }

   return NULL;
}

DOTCONF_CB(section_close) {
   struct config_context * context           = (struct config_context *)ctx;

   if (!context->current_end_token) {
      return pool_strcat(
         context->pool, cmd->name, " without matching <",
         cmd->name + 2, " section", NULL);
   }

   if (strcmp(context->current_end_token, cmd->name) != 0) {
      return pool_strcat(
         context->pool, "Expected '", context->current_end_token,
         "' but saw ", cmd->name, NULL);
   }

   return context->current_end_token;
}


DOTCONF_CB(common_option) {
   fprintf(stderr, "common_option : Option %s called  Not doing anything with it...\n", cmd->name);
   return NULL;
}

/*
// We expect  option     name  filename
//      e.g.  AddModule first ./plugins/decision-test.so
//
// So in the list :
//  0 -> name
//  1 -> so_filename
*/
DOTCONF_CB(addmodule_option) {
   struct config_context * context                 =  (struct config_context *)ctx;
   configoption_t *        module_options          ;
   const char *            error                   =  0;
   int                     handle_idx              =  -1;
   char                    filename[FILENAME_MAX]  =  "";
   void *                  shared_object           =  0;

   fprintf(stderr, "addmodule_option : Option %s called\n", cmd->name);
   if (cmd->arg_count < 2) {
      return pool_strcat(
               context->pool, "Not enough parameters to option ",
               cmd->name, " expected 2", NULL);
   }

   // load the damn thing
   for (handle_idx = 0; handle_idx < MAX_MODULES ; handle_idx++) {
      if (handles[handle_idx] == 0) {
         snprintf(filename, 128, "./%s.so", cmd->data.list[1]);
         if (access(filename, R_OK) == 0) /* if file access is permitted */
         {
            /* load library */
            handles[handle_idx] = dlopen(filename, RTLD_LAZY);
            if (!handles[handle_idx]) {
               fprintf(stderr, "Error opening library: %s\n", dlerror());
               return "Error opening library";
            }
            shared_object = handles[handle_idx];
            break;
         } else {
            return pool_strcat(context->pool, "Can't open file ", filename, NULL);
         }
      }
   }
   if (handle_idx == MAX_MODULES) {
      return "Out of handle space. Not loading module\n";
   }

   // get the options
   module_options = dlsym(shared_object, "options");
   error = dlerror();
   if (error) {
      fprintf(
         stderr,
         "addmodule_option() : Error finding the options variable in %s p=%p (%s)\n",
         cmd->data.list[1], shared_object, error);
      dlclose(shared_object);
      handles[handle_idx] = 0;
      return NULL;
   }


   /*
   // Scope the options of this module to a <NAME></NAME> block where NAME is
   // the name that was specified in the configfile.
   //
   // The context field holds a unique identifier so we can verify in our
   // contextchecker that this option belongs to the right scope.
   //
   */
   {
      char *            begin_context_tag    =  (char *)malloc(strlen(cmd->data.list[1]) + 2 + 1);
      char *            end_context_tag      =  (char *)malloc(strlen(cmd->data.list[1]) + 3 + 1);
      configoption_t *  scope_options        =  0;
      int               opt_idx              =  -1;

      scope_options = (configoption_t *)malloc(3*sizeof(configoption_t));
      if (!scope_options || !begin_context_tag || !end_context_tag) {
         return "Error allocating memory";
      }
      sprintf(begin_context_tag, "<%s>", cmd->data.list[0]);
      sprintf(end_context_tag, "</%s>", cmd->data.list[0]);

      // create our two extra options (scope begin/end) and a NULL option to close
      // the list
      scope_options[0].name      =  begin_context_tag;
      scope_options[0].type      =  ARG_NONE;
      scope_options[0].callback  =  section_open;
      scope_options[0].info      =  shared_object;
      scope_options[0].context   =  CTX_ALL;

      scope_options[1].name      =  end_context_tag;
      scope_options[1].type      =  ARG_NONE;
      scope_options[1].callback  =  section_close;
      scope_options[1].info      =  NULL;
      scope_options[1].context   =  (long)shared_object;

      scope_options[2].name      =  "";
      scope_options[2].type      =  0;
      scope_options[2].callback  =  NULL;
      scope_options[2].info      =  NULL;
      scope_options[2].context   =  0;

      /* Set the context field of all options from the module to the identifier */
      for (opt_idx = 0 ; strlen(module_options[opt_idx].name) ; opt_idx++) {
         module_options[opt_idx].context = (long)shared_object;
      }

      memory_junk.entries = realloc(
                              memory_junk.entries,
                              (memory_junk.n_entries + 3) * sizeof(void *));
      memory_junk.entries[memory_junk.n_entries++] = begin_context_tag;
      memory_junk.entries[memory_junk.n_entries++] = end_context_tag;
      memory_junk.entries[memory_junk.n_entries++] = scope_options;

      dotconf_register_options(cmd->configfile, scope_options);
      dotconf_register_options(cmd->configfile, module_options);
   }

   fprintf(
      stderr, "Successfully loaded module %s (%s)\n",
      cmd->data.list[1], cmd->data.list[1]);

   return NULL;
}