All pastes #420474 Raw Edit

Someone

public c v1 · immutable
·published 2007-04-02 04:40 UTC
rendered paste body
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include "main.h"#include "debug.h"#include "util.h"#include "tconfig.h"/* static sets the initial unchangeable structure */struct tconfig_block *file_to_tconfig(struct tconfig_block *old, const char *filename){  FILE   *cfile;  char   *fbuf   = NULL;  char   *eip    = NULL;  struct tconfig_block *block  = NULL;  struct tconfig_block *head   = NULL;  struct tconfig_block *search = NULL;  struct tconfig_block *tmp    = NULL;  size_t  size   = 0;  size_t  i      = 0;  size_t  count  = 0;  /* For debug purposes */  int line       = 1;    /* No memory allocated at this point, we don't need    * to die nicely   */  if ((cfile = fopen(filename,"r")) == NULL)  {    fprintf(stderr,"Could not open configuration file: %s\n",filename);    exit(EXIT_FAILURE);  }  fbuf = tmalloc0(BUFFER_SIZE);  /* Read the entire file into memory */  for(i=0;(count = fread(&fbuf[i],1,1024,cfile)) == 1024;i+=1024)  {    if ((fbuf = realloc(fbuf,i+1024+1024)) == NULL)    {      troll_debug(LOG_FATAL,"Could not allocate memory for config file, barfing.\n");      exit(EXIT_FAILURE);    }  }    /* If NOT the end-of-file, we must have had an error of some sort, barf and die */  if (!feof(cfile))  {    fprintf(stderr, "An error occurred while reading the config file\n");    exit(EXIT_FAILURE);  }   /* Terminate it with a NULL */  fbuf[i+count] = '\0';  fclose(cfile);  if (old == NULL)  {    block = tmalloc(sizeof(struct tconfig_block));    block->parent = NULL;    block->child  = NULL;    block->prev   = NULL;    block->next   = NULL;    block->key    = NULL;    block->value  = NULL;    head = block;  } else {    block = old;    /* Go to top left node */    while (block->parent != NULL || block->prev != NULL)      block = (block->parent != NULL) ? block->parent : block->next;    head = block;  }      eip = fbuf;  while(*eip)  {    switch (*eip)    {      case '{':        if (block->child != NULL)        {          block = block->child;          break;        }        block->child = tmalloc(sizeof(struct tconfig_block));        block->child->parent = block;        block                = block->child;        block->child         = NULL;        block->prev          = NULL;        block->next          = NULL;        block->key           = NULL;        block->value         = NULL;        break;            /* The very left element in tree should have the parent */      case '}':        /* Rewind the list the very left */        while (block->prev != NULL)          block = block->prev;               if (block->parent == NULL)        {          fprintf(stderr, "Mismatched } around line: %d\n",line);          exit(EXIT_FAILURE);        }          block              = block->parent;        break;      /* Ugly comment parsing routines */      case '/':        if (*(eip+1) != '*' && *(eip+1) != '/')        {          fprintf(stderr,"Stray / on line: %d\n",line);          exit(EXIT_FAILURE);        }        /* If comment takes C form */        if (*(eip+1) == '*')        {          /* Skip over / and * */          eip+=2;          /* Go until terminating -> */          while (*eip != '\0')           {            if (*(eip+1) == '\0')            {              fprintf(stderr,"Reached end of file while looking for */\n");              exit(EXIT_FAILURE);            }            if (*eip == '*' && *(eip+1) == '/')            {              /* loop increases eip, so only add 1 */              eip++;              break; /* Found end of comment */            }             if (*eip == '\r' && *(eip+1) == '\n')            {              eip++;              line++;            }            else if (*eip == '\n')            {              line++;            }            else if (*eip == '\r')            {              line++;            }            eip++;          }          if (eip == '\0')          {            return head;          }           }        else /* // comment, go until \r\n, \n, or \r */        {          eip+=2; /* Skip over // */                   while (*eip != '\0')          {            if (*eip == '\r')            {              /* This just means the file is over, not an error */              if (*(eip+1) == '\0')                return head;              if (*(eip+1) != '\n')              {                eip++;                line++;                break;              }              else              {                line++;                break;              }            }            else if (*eip == '\n')            {              line++;              break;            }            eip++;            }          if (*eip == '\0')            return head;                        }        break;      case '\r':        if (*(eip+1) == '\n')        {          eip++;          line++;        }        else          line++;        if (eip == '\0')          return head;        break;      case '\n':        line++;                  break;      case '\t':        break;      case ' ':        break;      default:        tmp        = tmalloc(sizeof(struct tconfig_block));        /* Do a wasteful scan so I don't have to deal with realloc */        if (*eip == '"')        {          eip++; /* Skip the first " */          for (i=0;*(eip+i) != '\0' && *(eip+i) != '\n' && *(eip+i) != '\r' &&                   *(eip+i) != '"';i++);          if (*(eip+i) != '"')          {            fprintf(stderr, "Unmatched \" on line %d\n",line);            exit(EXIT_FAILURE);          }        }        else        {           for (i=0;*(eip+i) != '\0' && *(eip+i) != ' ' && *(eip+i) != '\t';i++);                      if (*(eip+i) != ' ' && *(eip+i) != '\t')          {            fprintf(stderr, "Unmatched key on line %d\n",line);            exit(EXIT_FAILURE);          }        }        size = i;          tmp->key = tmalloc0(size+1);        for (i=0;i<size;i++)        {          *(tmp->key+i) = *(eip++);        }           /* Skip over trailing " if exists, this could be a problem if key is next to value */        if (*eip == '"')          eip++;        /* Skip over whitespace, print error if EOF or there's a newline reached before text */        while(*eip == '\t' || *eip == ' ' || *eip == '\r' || *eip == '\n' || *eip == '\0')        {          if (*eip == '\0')          {            fprintf(stderr, "Reached end of file looking for %s's value on line %d\n",block->key,line);            exit(EXIT_FAILURE);          }          if (*eip == '\r' || *eip == '\n')          {            fprintf(stderr, "Reached end of line looking for %s's value on line %d\n",block->key,line);            exit(EXIT_FAILURE);          }              eip++;        }        /* Now to scan the value */        /* Do a wasteful scan so I don't have to deal with realloc */        if (*eip == '"')        {          eip++; /* Skip the first " */          for (i=0;*(eip+i) != '\0' && *(eip+i) != '\n' && *(eip+i) != '\r' &&                   *(eip+i) != '"';i++);          if (*(eip+i) != '"')          {            fprintf(stderr, "Unmatched \" on line %d\n",line);            exit(EXIT_FAILURE);          }        }        else        {          for (i=0;*(eip+i) != '\0' && *(eip+i) != ' ' && *(eip+i) != '\t' &&                   *(eip+i) != '\r' && *(eip+i) != '\n';i++);          if (*(eip+i) != ' ' && *(eip+i) != '\t' && *(eip+i) != '\r' && *(eip+i) != '\n')          {            fprintf(stderr, "Unmatched key on line %d\n",line);            exit(EXIT_FAILURE);          }        }        size = i;        tmp->value = tmalloc0(size+1);        for (i=0;i<size;i++)        {          *(tmp->value+i) = *(eip++);        }        tmp->value[size] = '\0';         /* Now that we've got all the values, we check for dupes         * to link more than one tconfig file. It might make more         */        /* Rewind list */        search = block;        while (search->prev != NULL)          search = search->prev;        while (search != NULL)        {          if (search->key != NULL && search->value != NULL)            if (!strcmp(search->key,tmp->key) && !strcmp(search->value,tmp->value))            {              free(tmp->key);              free(tmp->value);              free(tmp);              tmp = NULL;              block = search;              break;            }           block  = search;          search = search->next;        }        if (tmp != NULL)        {          if (block->key == NULL && block->value == NULL)          {            block->key   = tmp->key;            block->value = tmp->value;             /* Keeping above memory */            free(tmp);                      }           else          {            /* Make a new block */            block->next = tmp;            tmp->prev   = block;            tmp->next   = NULL;            tmp->parent = NULL;            tmp->child  = NULL;            block       = block->next;          }        }        break;              }       eip++; /* While loop increase */  }  return head;}void free_tconfig_r(struct tconfig_block *tcfg){  if (tcfg->child)    free_tconfig_r(tcfg->child);  if (tcfg->next)    free_tconfig_r(tcfg->next);  if (tcfg->key != NULL)    free(tcfg->key);    if (tcfg->value != NULL)    free(tcfg->value);  free(tcfg);}  void free_tconfig(struct tconfig_block *tcfg){  struct tconfig_block *tmp;  if (tcfg == NULL)    return;  tmp = tcfg;  /* Rewind to the top left, it should be there already */  while (tmp->prev != NULL && tmp->parent != NULL)    tmp = (tmp->parent) ? tmp->parent : tmp->prev;   free_tconfig_r(tcfg);   return; }static void tconfig_r_depth_first_write(int depth, FILE *out, struct tconfig_block *tmp){  int i;  if (tmp == NULL)    return;  if (tmp->child != NULL)  {    for(i=0;i<(depth*2);i++)      fputc(' ',out);    fprintf(out,"\"%s\"\t\"%s\"\n",tmp->key,tmp->value);       for(i=0;i<(depth*2);i++)      fputc(' ',out);    fprintf(out,"{\n");    tmp = tmp->child;    depth++;  }  else if (tmp->next != NULL)  {    for(i=0;i<(depth*2);i++)      fputc(' ',out);    fprintf(out,"\"%s\"\t\"%s\"\n",tmp->key,tmp->value);    tmp = tmp->next;  }  else  {    for(i=0;i<(depth*2);i++)      fputc(' ',out);    fprintf(out,"\"%s\"\t\"%s\"\n",tmp->key,tmp->value);    if (depth > 0)    {      while (tmp)      {        if (tmp->next == NULL)        {          if (depth == 0)            return;          while (tmp->parent == NULL)          {            tmp = tmp->prev;          }           tmp = tmp->parent;          depth--;          for(i=0;i<(depth*2);i++)            fputc(' ',out);                    fprintf(out,"}\n\n");        }         else        {          tmp = tmp->next;          break;        }      }    }     else      return;           }  tconfig_r_depth_first_write(depth,out,tmp);}/* write a tconfig block back out */void tconfig_to_file(struct tconfig_block *tcfg, char *filename){  FILE *out;  struct tconfig_block *tmp = tcfg;  struct tconfig_block *search;  int indent;  if (tmp == NULL)  {    troll_debug(LOG_WARN,"tconfig_to_file() passed a NULL tconfig block.");    return;  }  if ((out = fopen(filename,"w")) == NULL)  {    troll_debug(LOG_ERROR,"Could not open %s for writing.",filename);    return;  }   tconfig_r_depth_first_write(0,out,tmp);  fclose(out);}