All pastes #420473 Raw Edit

Untitled

public text 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);
}