Logo Search packages:      
Sourcecode: mswatch version File versions  Download package

rcparser.cc

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "lib/util.h"
#include "parser_types.h"
#include "rcparser.h"

/* TODO:
 * - It seems this file would benefit from the parser types using
 *   dynamic dispatch. An attempt that did not work out better is at
 *   '/branches/oo_parser_types/'.
 */

//#define RCPARSER_DEBUG 1

static void print_str_list(const struct str_list* sl)
{
      if (!sl)
            return;
      print_str_list(sl->prev);
      printf("%s ", sl->str);
}

static void print_rc_store_setting(const struct rc_store_setting* rcss)
{
      if (!rcss)
            return;
      print_rc_store_setting(rcss->prev);
      printf("\t");
      switch (rcss->type)
      {
            case RCSS_NAME:
                  printf("name %s\n", rcss->name); break;
            case RCSS_WATCH:
                  printf("watch "); print_str_list(rcss->watch); printf("\n"); break;
            default:
                  printf("unknown rc store setting type %d\n", rcss->type);
      }
}

static void print_rc_setting(const struct rc_setting* rc)
{
      if (!rc)
            return;
      print_rc_setting(rc->prev);
      switch (rc->type)
      {
            case RCS_BASEDELAY:
                  printf("base_delay %d\n", rc->base_delay); break;
            case RCS_INTERDELAY:
                  printf("inter_delay %d\n", rc->inter_delay); break;
            case RCS_INTERDELAY_LIST:
                  printf("inter_delay_list %d", rc->inter_delay_list.delay);
                  print_str_list(rc->inter_delay_list.mailboxes);
                  printf("\n");
                  break;
            case RCS_MAXDELAY:
                  printf("max_delay %d\n", rc->max_delay); break;
            case RCS_SYNC:
                  printf("sync "); print_str_list(rc->sync); printf("\n"); break;
            case RCS_MAILBOXPREFIX:
                  printf("mailbox_prefix %s %s\n", rc->mailbox_prefix[0], rc->mailbox_prefix[1]); break;
            case RCS_SS:
                  printf("store\n{\n");
                  print_rc_store_setting(rc->store_setting);
                  printf("}\n");
                  break;
            default:
                  printf("unknown rc setting type %d\n", rc->type);
      }
}


static void free_str_list(struct str_list* sl)
{
      if (!sl)
            return;
      free_str_list(sl->prev);
      free(sl->str);
      free(sl);
}

static void free_rc_store_setting(struct rc_store_setting* rcss)
{
      if (!rcss)
            return;
      free_rc_store_setting(rcss->prev);
      switch (rcss->type)
      {
            case RCSS_NAME:
                  free(rcss->name); break;
            case RCSS_WATCH:
                  free_str_list(rcss->watch); break;
            default:
                  assert(0);
      }
      free(rcss);
}

static void free_rc_setting(struct rc_setting* rc)
{
      if (!rc)
            return;
      free_rc_setting(rc->prev);
      switch (rc->type)
      {
            case RCS_BASEDELAY:
            case RCS_INTERDELAY:
            case RCS_MAXDELAY:
                  break;
            case RCS_INTERDELAY_LIST:
                  free_str_list(rc->inter_delay_list.mailboxes);
                  break;
            case RCS_SYNC:
                  free_str_list(rc->sync); break;
            case RCS_MAILBOXPREFIX:
                  free(rc->mailbox_prefix[0]);
                  free(rc->mailbox_prefix[1]);
                  break;
            case RCS_SS:
                  free_rc_store_setting(rc->store_setting); break;
            default:
                  assert(0);
      }
      free(rc);
}


static void error_missing_rc_store_field(int type)
{
      fprintf(stderr, "Configuration file is missing store field ");
      switch (type)
      {
            case RCSS_NAME: fprintf(stderr, "name"); break;
            case RCSS_WATCH: fprintf(stderr, "watch"); break;
            default: assert(0);
      }
      fprintf(stderr, "\n");
      exit(1);
}

static void error_missing_rc_field(int type)
{
      fprintf(stderr, "Configuration file is missing field ");
      switch (type)
      {
            case RCS_BASEDELAY: fprintf(stderr, "base_delay"); break;
            case RCS_INTERDELAY: fprintf(stderr, "inter_delay"); break;
            case RCS_MAXDELAY: fprintf(stderr, "max_delay"); break;
            case RCS_SYNC: fprintf(stderr, "sync"); break;
            case RCS_MAILBOXPREFIX: fprintf(stderr, "mailbox_prefix"); break;
            case RCS_SS: fprintf(stderr, "store"); break;
            default: assert(0);
      }
      fprintf(stderr, "\n");
      exit(1);
}


static char** str_list_to_array(const struct str_list* sl)
{
      unsigned len = 0;
      const struct str_list* it = sl;
      char** strarray;
      unsigned i;

      while (it)
      {
            len++;
            it = it->prev;
      }

      strarray = (char**) malloc((len + 1) * sizeof(*strarray));
      die_if(!strarray, "malloc");

      it = sl;
      strarray[len] = NULL;
      for (i = 1; i <= len; i++, it = it->prev)
            strarray[len - i] = strdup(it->str);

      return strarray;
}

int rc_store_to_config(const struct rc_store_setting* rcss, mailstore_config* config)
{
      if (!rcss)
            return 0;

      int prev_types = rc_store_to_config(rcss->prev, config);
      if (prev_types & rcss->type)
      {
            fprintf(stderr, "Multiple store entries of the same type\n");
            exit(1);
      }

      switch (rcss->type)
      {
            case RCSS_NAME:
                  config->name = strdup(rcss->name); break;
            case RCSS_WATCH:
                  config->watch_bin = str_list_to_array(rcss->watch); break;
            default:
                  printf("unknown rc store setting type %d\n", rcss->type);
      }
      return prev_types | rcss->type;
}

static int rc_to_config(const struct rc_setting* rc, mswatch_config* config)
{
      if (!rc)
            return 0;

      int prev_types = rc_to_config(rc->prev, config);
      if (prev_types & rc->type && rc->type != RCS_SS && rc->type != RCS_INTERDELAY_LIST)
      {
            fprintf(stderr, "More than one entry of the same type. Error on:\n");
            const_cast<struct rc_setting*>(rc)->prev = NULL;
            print_rc_setting(rc);
            exit(1);
      }

      switch (rc->type)
      {
            case RCS_BASEDELAY:
                  config->base_delay = rc->base_delay; break;
            case RCS_INTERDELAY:
                  config->default_inter_delay = rc->inter_delay; break;
            case RCS_INTERDELAY_LIST:
                  for (struct str_list* sl = rc->inter_delay_list.mailboxes; sl; sl = sl->prev)
                        config->inter_delays[sl->str] = rc->inter_delay_list.delay;
                  break;
            case RCS_MAXDELAY:
                  config->max_delay = rc->max_delay; break;
            case RCS_SYNC:
                  if (config->sync_bin)
                  {
                        for (char** eltp = config->sync_bin; *eltp; eltp++)
                              free(*eltp);
                        free(config->sync_bin);
                        config->sync_bin_len = 0;
                  }
                  config->sync_bin = str_list_to_array(rc->sync);
                  for (char** eltp = config->sync_bin; *eltp; eltp++)
                        config->sync_bin_len++;
                  break;
            case RCS_MAILBOXPREFIX:
                  config->mailbox_prefix[0] = strdup(rc->mailbox_prefix[0]);
                  config->mailbox_prefix[1] = strdup(rc->mailbox_prefix[1]);
                  break;
            case RCS_SS:
            {
                  mailstore_config* store;
                  if (!config->store[0].name)
                        store = &config->store[0];
                  else if (!config->store[1].name)
                        store = &config->store[1];
                  else
                  {
                        fprintf(stderr, "More than two store entries. Error on:\n");
                        rc->store_setting->prev = NULL;
                        print_rc_store_setting(rc->store_setting);
                        exit(1);
                  }

                  int set_types = rc_store_to_config(rc->store_setting, store);

                  if (!(set_types & RCSS_NAME))
                        error_missing_rc_store_field(RCSS_NAME);
                  else if (!(set_types & RCSS_WATCH))
                        error_missing_rc_store_field(RCSS_WATCH);
                  break;
            }
            default:
                  printf("unknown rc setting type %d\n", rc->type);
      }
      return prev_types | rc->type;
}


// parser.y symbols
__BEGIN_DECLS
extern int yyparse(void);
extern FILE* yyin;
extern struct rc_setting* parsed_rc_setting;
__END_DECLS

int parse_config(FILE* configfile, mswatch_config* config)
{
      yyin = configfile;
      int r = yyparse();
      if (r < 0)
      {
            fprintf(stderr, "%s(): yyparse() = %d\n", __FUNCTION__, r);
            return -1;
      }
      assert(feof(yyin));

#ifdef RCPARSER_DEBUG
      printf("%s:\n", __FUNCTION__);
      if (parsed_rc_setting)
            print_rc_setting(parsed_rc_setting);
      else
            printf("empty configuration\n");
#endif

      int set_types = rc_to_config(parsed_rc_setting, config);

      if (!(set_types & RCS_SYNC))
            error_missing_rc_field(RCS_SYNC);
      else if ((!config->store[0].name && !config->store[1].name))
      {
            fprintf(stderr, "Configuration file has no stores\n");
            exit(1);
      }
      else if ((!config->store[0].name || !config->store[1].name))
      {
            fprintf(stderr, "Configuration file has only one store (%s); two are required\n", config->store[0].name ? config->store[0].name : config->store[1].name);
            exit(1);
      }

      if (config->base_delay > config->default_inter_delay)
      {
            fprintf(stderr, "Configuration error: base_delay (%ld) > default inter_delay (%ld)\n", config->base_delay, config->default_inter_delay);
            exit(1);
      }

      for (map<string, time_t>::const_iterator it = config->inter_delays.begin(); it != config->inter_delays.end(); ++it)
      {
            if (config->base_delay > it->second)
            {
                  fprintf(stderr, "Configuration error: base_delay (%ld) > inter_delay for mailbox \"%s\" (%ld)\n", config->base_delay, it->first.c_str(), it->second);
                  exit(1);
            }
      }

      free_rc_setting(parsed_rc_setting);
      parsed_rc_setting = NULL;

      return 0;
}

Generated by  Doxygen 1.6.0   Back to index