All pastes #2124696 Raw Edit

Error line 109

public text v1 · immutable
#2124696 ·published 2012-03-05 22:26 UTC
rendered paste body
/*
Copyright (C) 2005-2007 Nach ( http://nsrt.edgeemu.com )

Config file handler creator by Nach (C) 2005-2007
*/

#include <algorithm>
#include <cstring>
#include <errno.h>
#include <fstream>
#include <iostream>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>

#include <zlib.h>

using namespace std;

#include "global.h"
#include "parsegen.h"
#include "string.h"

#define CONFIG_COMMENT ( config_comment ? config_comment : "" )
#define LINE_LENGTH 2048*4

/*
Compiler with it's helper functions
*/

#define var_type_is_char(var_type)  !strcmp( var_type + strlen(var_type) - strlen("char"), "char" )
#define var_type_is_short(var_type) !strcmp( var_type + strlen(var_type) - strlen("short"), "short" )
#define var_type_is_int(var_type)   !strcmp( var_type + strlen(var_type) - strlen("int"), "int" )

Location current_location;

char line[LINE_LENGTH];

string cflags;
string family_name = "cfg";
string gcc = "gcc";

nstack ifs;
set<string> defines, dependancies;
vector<string> memsets;

/**/

void Location::error( const char *str )
{
 cerr << "Error: parse problem occured at " << line_number << ":" << column_number << ". " << str << "." << endl;
}

nstack::nstack( void )
{
}

nstack::~nstack( void )
{
}

bool nstack::top( void )
{
 return( data.back() );
}

bool nstack::all_true( void )
{
 vector<bool>::iterator i = data.begin();

 for ( ; i != data.end(); i++ )
{

  if (!*i)
{
   return(false);
}

}

 return(true);
}

bool nstack::empty( void )
{
 return( data.empty() );
}

size_t nstack::size( void )
{
 return( data.size() );
}

void nstack::pop( void )
{
 data.pop_back();
}

void nstack::push( bool data )
{
 this->data.push_back(data);
}


variable::ctype GetCType(const char *str)
{
 ctype i = NT;

 for ( ; i < LT; i++)
{

  if ( !strcmp( info[i].CTypeSpace, str ) )
{
   break;
}

}

 i %= LT;

 if ( i == NT )
{
  cerr << "Invalid C type \"" << str << "\" when parsing line " << current_location.line_number << "." << endl;
}

 return(i);
}

bool variable::config_data_element::operator==(const string& name) const
{
 return( this->name == name );
}


bool variable::ConfigData::duplicate_name( string &name )
{

 if ( find(data_array.begin(), data_array.end(), name) != data_array.end() )
{
  cerr << "Duplicate definition of \"" << name << "\" found on line " << current_location.line_number << "." << endl;
  return(true);
}

 return(false);
}

void variable::ConfigData::add_comment( string comment )
{
 config_data_element new_element = { "", none, NT, 0, "", comment };
 data_array.push_back(new_element);
}

void variable::ConfigData::add_var_single( string &name, ctype type, string dependancy, string comment = "" )
{

 if ( !duplicate_name(name) )
{
  config_data_element new_element = { name, single, type, 0, dependancy, comment };
  data_array.push_back(new_element);
}

}

void variable::ConfigData::add_var_single( string &name, const char *type, string dependancy, string comment = "" )
{
 add_var_single( name, GetCType(type), dependancy, comment );
}

void variable::ConfigData::add_var_quoted( string &name, string dependancy, string comment = "" )
{

 if ( !duplicate_name(name) )
{
  config_data_element new_element = { name, quoted, NT, 0, dependancy, comment };
  data_array.push_back(new_element);
}

}

void variable::ConfigData::add_var_mult( string &name, ctype type, size_t length, string dependancy, string comment = "" )
{

 if ( !duplicate_name(name) )
{
  config_data_element new_element = { name, mult, type, length, dependancy, comment };
  data_array.push_back(new_element);
}

}

void variable::ConfigData::add_var_mult( string &name, const char *type, size_t length, string dependancy, string comment = "" )
{
 add_var_mult(name, GetCType(type), length, dependancy, comment);
}

void variable::ConfigData::add_var_packed( string &name, size_t length, string dependancy, string comment = "" )
{

 if ( !duplicate_name(name) )
{
  config_data_element new_element = { name, mult_packed, NT, length, dependancy, comment };
  data_array.push_back(new_element);
}

}

void variable::ConfigData::add_var_ptr( string &name, ctype type, size_t length, string dependancy, string comment = "" )
{

 if ( !duplicate_name(name) )
{
  config_data_element new_element = { name, ptr, type, length, dependancy, comment };
  data_array.push_back(new_element);
}

}

void variable::ConfigData::add_var_ptr( string &name, const char *type, size_t length, string dependancy, string comment = "" )
{
 add_var_ptr(name, GetCType(type), length, dependancy, comment);
}


bool variable::ConfigData::ctype_mult_used( ctype type )
{
 config_data_array::iterator i = data_array.begin();

 for ( ; i != data_array.end(); i++ )
{

  if ( ( i->format == mult ) && ( i->type == type ) )
{
   return(true);
}

}

 return(false);
}

bool variable::ConfigData::ctype_ptr_used( ctype type )
{
 config_data_array::iterator i = data_array.begin();

 for ( ; i != data_array.end(); i++ )
{

  if ( ( i->format == ptr ) && ( i->type == type ) )
{
   return(true);
}

}

 return(false);
}

bool variable::ConfigData::packed_used( void )
{
 config_data_array::iterator i = data_array.begin();

 for ( ; i != data_array.end(); i++ )
{

  if ( i->format == mult_packed )
{
   return(true);
}

}

 return(false);
}

bool variable::ConfigData::quoted_used( void )
{
 config_data_array::iterator i = data_array.begin();

 for ( ; i != data_array.end(); i++ )
{

  if ( i->format == quoted )
{
   return(true);
}

}

 return(false);
}

bool variable::ConfigData::unsigned_used( void )
{
 config_data_array::iterator i = data_array.begin();

 for ( ; i != data_array.end(); i++ )
{

  if ( !info[i->type].Signed )
{
   return(true);
}

}

 return(false);
}

variable::ConfigData::config_data_array::iterator begin( void )
{
 return( data_array.begin() );
}

variable::ConfigData::config_data_array::iterator end( void )
{
 return( data_array.end() );
}


const char *convert_asm_type( const char *str, bool unsigned_var = true )
{
 const char *var_type = 0;

 if ( !strcasecmp(str, "dd") )
{
  var_type = "unsigned int";
}
 else if ( !strcasecmp(str, "dw") )
{
  var_type = "unsigned short";
}
 else if ( !strcasecmp(str, "db") )
{
  var_type = "unsigned char";
}
 else if ( !strcasecmp(str, "sd") )
{
  var_type = "int";
}
 else if ( !strcasecmp(str, "sw") )
{
  var_type = "short";
}
 else if ( !strcasecmp(str, "sb") )
{
  var_type = "char";
}
 else
{
  current_location.error( "Not a valid type" );
}

 if ( var_type && !strncmp(var_type, "unsigned ", strlen("unsigned ") ) && !unsigned_var )
{
  var_type += strlen("unsigned ");
}

 return(var_type);
}

void output_parser_start( ostream &c_stream, string &cheader_file )
{
 c_stream << "/*\n"
          << "Config file handler generated by Nach's Config file handler creator.\n"
          << "*/\n"
          << "\n"
          << "#include <stdio.h>\n"
          << "#include <stdlib.h>\n"
          << "#include <ctype.h>\n"
          << "#include <string.h>\n";

 if ( defines.find("PSR_COMPRESSED") != defines.end() )
{
  c_stream << "#include <zlib.h>\n";
}

 if ( cheader_file.length() )
{
  c_stream << "#include \"" << cheader_file << "\"\n";
}

 c_stream << "\n"
          << "\n"
          << "#define LINE_LENGTH " << LINE_LENGTH << "\n"
          << "static char line[LINE_LENGTH];\n"
          << "\n";

 if ( variable::config_data.quoted_used() || variable::config_data.packed_used() )
{
  c_stream << "\n"
           << "static char *encode_string(const char *str)\n"
           << "{\n"
           << "  size_t i = 0;\n"
           << "  line[i++] = '\\\"';\n"
           << "  while (*str)\n"
           << "  {\n"
           << "    if ((*str == '\\\\') ||\n"
           << "        (*str == '\\\"') ||\n"
           << "        (*str == '\\\'') ||\n"
           << "        (*str == '\\n') ||\n"
           << "        (*str == '\\t'))\n"
             << "    {\n"
             << "      line[i++] = '\\\\';\n"
             << "    }\n"
             << "    line[i++] = *str++;\n"
             << "  }\n"
             << "  line[i++] = '\\\"';\n"
             << "  line[i] = 0;\n"
             << "  return(line);\n"
             << "}\n"
             << "\n"
             << "static char *decode_string(char *str)\n"
             << "{\n"
             << "  size_t str_len = strlen(str), i = 0;\n"
             << "  char *dest = str;\n"
             << "\n"
             << "  if ((str_len > 1) && (*str == '\\\"') && (str[str_len-1] == '\\\"'))\n"
             << "  {\n"
             << "    memmove(str, str+1, str_len-2);\n"
             << "    str[str_len-2] = 0;\n"
             << "\n"
             << "    while (*str)\n"
             << "    {\n"
             << "      if (*str == '\\\\')\n"
             << "      {\n"
             << "        str++;\n"
             << "      }\n"
             << "      dest[i++] = *str++;\n"
             << "    }\n"
             << "  }\n"
             << "  dest[i] = 0;\n"
             << "  return(dest);\n"
             << "}\n";
}

 c_stream << "\n"
          << "static char *find_next_match(char *str, char match_char)\n"
          << "{\n"
          << "  char *pos = 0;\n"
          << "\n"
           << "  while (*str)\n"
           << "  {\n"
           << "    if (*str == match_char)\n"
           << "    {\n"
           << "      pos = str;\n"
           << "      break;\n"
           << "    }\n"
           << "    if (*str == '\\\\')\n"
           << "    {\n"
           << "      if (str[1])\n"
           << "      {\n"
           << "        str++;\n"
           << "      }\n"
           << "      else\n"
           << "      {\n"
           << "        break;\n"
           << "      }\n"
           << "    }\n"
           << "    str++;\n"
           << "  }\n"
           << "  return(pos);\n"
           << "}\n"
           << "\n"
           << "static char *find_str(char *str, char *match_str)\n"
           << "{\n"
           << "  char *pos = 0;\n"
           << "\n"
           << "  while (*str)\n"
           << "  {\n"
           << "    if (strchr(match_str, *str))\n"
           << "    {\n"
           << "      pos = str;\n"
           << "      break;\n"
           << "    }\n"
           << "    if ((*str == '\\\"') || (*str == '\\\''))\n"
           << "    {\n"
           << "      char *match_pos = 0;\n"
           << "      if ((match_pos = find_next_match(str+1, *str)))\n"
           << "      {\n"
           << "        str = match_pos;\n"
           << "      }\n"
           << "    }\n"
           << "    str++;\n"
           << "  }\n"
           << "  return(pos);\n"
           << "}\n"
           << "\n";

 if (variable::config_data.unsigned_used())
{
  c_stream << "\n"
           << "static int atoui(const char *nptr)\n"
           << "{\n"
           << "  return(strtoul(nptr, 0, 10));\n"
           << "}\n";
}

 c_stream << "\n";
}

void output_cheader_start( ostream &cheader_stream )
{
 cheader_stream << "/*\n"
                << "Config file handler header generated by Nach's Config file handler creator.\n"
                << "*/\n"
                << "\n"
                << "#ifdef __cplusplus\n"
                << "  extern \"C\" {\n"
                << "#endif\n"
                << "\n"
                << "unsigned char read_" << family_name << "_vars(const char *);\n"
                << "unsigned char write_" << family_name << "_vars(const char *);\n";

 if ( defines.find("PSR_COMPRESSED") != defines.end() )
{
  cheader_stream << "unsigned char read_" << family_name << "_vars_compressed(const char *);\n"
                 << "unsigned char write_" << family_name << "_vars_compressed(const char *);\n";
}

 if ( defines.find("PSR_MEMCPY") != defines.end() )
{
  cheader_stream << "void read_" << family_name << "_vars_memory(unsigned char *);\n"
                 << "void write_" << family_name << "_vars_memory(unsigned char *);\n"
                 << "unsigned int size_" << family_name << "_vars_memory();\n";
}

 cheader_stream << "\n";
}

void output_cheader_end( ostream &cheader_stream )
{
 cheader_stream << "\n"
                << "#ifdef __cplusplus\n"
                << "             }\n"
                << "#endif\n"
                << "\n";
}


void output_extsym_dependancies( ostream &c_stream )
{
 set<string>::iterator i = dependancies.begin();

 c_stream << "\n";

 for ( ; i != dependancies.end(); i++ )
{
  c_stream << "extern unsigned char " << *i << ";\n";
}

}

void output_init_var( ostream &c_stream )
{
 vector<string>::iterator i = memsets.begin();

 c_stream << "\n"
          << "static unsigned char psr_init_done = 0;\n"
          << "static void init_" << family_name << "_vars()\n"
          << "{\n"
          << "  if (!psr_init_done)\n"
          << "  {\n"
          << "    psr_init_done = 1;\n"
          << "\n";

 for ( ; i != memsets.end(); i++ )
{
  c_stream << "    " << *i << "\n";
}

 c_stream << "  }\n"
          << "}\n";
}

void output_packed_write( ostream &c_stream )
{

 if ( variable::config_data.packed_used() )
{
  c_stream << "\n"
           << "static char *base94_encode(size_t size)\n"
           << "{\n"
           << "  unsigned int i;\n"
           << "  static char buffer[] = { 0, 0, 0, 0, 0, 0};\n"
           << "  for (i = 0; i < 5; i++)\n"
             << "  {\n"
             << "    buffer[i] = ' ' + (char)(size % 94);\n"
             << "    size /= 94;\n"
             << "  }\n"
             << "  return(buffer);\n"
             << "}\n"
             << "\n"
             << "static char *char_array_pack(const char *str, size_t len)\n"
             << "{\n"
             << "  char packed[LINE_LENGTH];\n"
             << "  char *p = packed;\n"
             << "  while (len)\n"
             << "  {\n"
             << "    if (*str)\n"
             << "    {\n"
             << "      size_t length = strlen(str);\n"
             << "      strcpy(p, encode_string(str));\n"
             << "      str += length;\n"
             << "      len -= length;\n"
             << "      p += strlen(p);\n"
             << "    }\n"
             << "    else\n"
             << "    {\n"
             << "      size_t i = 0;\n"
             << "      while (!*str && len)\n"
             << "      {\n"
             << "        i++;\n"
             << "        str++;\n"
             << "        len--;\n"
             << "      }\n"
             << "\n"
             << "      sprintf(p, \"0%s\", encode_string(base94_encode(i)));\n"
             << "      p += strlen(p);\n"
             << "    }\n"
             << "    *p++ = '\\\\';\n"
             << "  }\n"
             << "  p[-1] = 0;\n"
             << "  strcpy(line, packed);"
             << "  return(line);\n"
             << "}\n";
}

}

void output_array_write( ostream &c_stream, variable::ctype type )
{

 if ( variable::config_data.ctype_mult_used(type) || variable::config_data.ctype_ptr_used(type) )
{
  c_stream << "\n"
           << "static void write_" << variable::info[type].CTypeUnderscore << "_array(int (*outf)(void *, const char *, ...), void *fp, const char *var_name, " << variable::info[type].CTypeSpace << " *var, size_t size, const char *comment)\n"
           << "{\n"
           << "  size_t i;\n"
           << "  outf(fp, \"%s=%" << variable::info[type].FormatChar << "\", var_name, (int)*var);\n"
             << "  for (i = 1; i < size; i++)\n"
             << "  {\n"
             << "    outf(fp, \",%" << variable::info[type].FormatChar << "\", (int)(var[i]));\n"
             << "  }\n"
             << "  if (comment)\n"
             << "  {\n"
             << "    outf(fp, \" ;%s\", comment);\n"
             << "  }\n"
             << "  outf(fp, \"\\n\");\n"
             << "}\n";
}

}

void output_write_var( ostream &c_stream )
{
 variable::config_data_array::iterator i = variable::config_data.begin();

 output_packed_write(c_stream);
 output_array_write(c_stream, variable::UC);
 output_array_write(c_stream, variable::US);
 output_array_write(c_stream, variable::UD);
 output_array_write(c_stream, variable::SC);
 output_array_write(c_stream, variable::SS);
 output_array_write(c_stream, variable::SD);
 c_stream << "\n"
          << "static void write_" << family_name << "_vars_internal(void *fp, int (*outf)(void *, const char *, ...))\n"
          << "{\n";

 for ( ; i != variable::config_data.end(); i++ )
{
  string dependancy_prefix, dependancy_suffix;

  if ( i->dependancy != "" )
{
   dependancy_prefix = string("if (") + string(i->dependancy, 0, i->dependancy.length()-1) + string(") { ");
   dependancy_suffix = " }";
}

  if ( i->format == variable::none )
{

   if ( i->comment != "" )
{
    c_stream << "  outf(fp, \";%s\\n\", " << encode_string(i->comment) << ");\n";
}
   else
{
    c_stream << "  outf(fp, \"\\n\");\n";
}

}
  else if ( ( i->format == variable::mult ) || ( i->format == variable::ptr ) )
{
   c_stream << "  " << dependancy_prefix << "write_" << variable::info[i->type].CTypeUnderscore
            << "_array(outf, fp, \"" << i->dependancy << i->name << "\", " << i->name << ", " << i->length << ", " << ((i->comment != "") ? encode_string(i->comment) : "0") << ");" << dependancy_suffix << "\n";
}
  else
{
   string config_comment = (i->comment != "") ? (string(" ;") + encode_string(i->comment, false)) : "";

   c_stream << "  " << dependancy_prefix << "outf(fp, \"" << i->dependancy << i->name << "=";

   if ( i->format == variable::single )
{
    c_stream << "%" << variable::info[i->type].FormatChar << config_comment << "\\n\", " << i->name;
}
   else if ( i->format == variable::quoted )
{
    c_stream << "%s" << config_comment << "\\n\", encode_string(" << i->name << ")";
}
   else if ( i->format == variable::mult_packed )
{
    c_stream << "%s" << config_comment << "\\n\", char_array_pack((char *)" << i->name << ", " << i->length << ")";
}

   c_stream << ");" << dependancy_suffix << "\n";
}

}

 if ( defines.find("PSR_HASH") != defines.end() )
{
  c_stream << "  outf(fp, \"\\n\\n\\n;Do not modify the following, for internal use only.\\n\");\n"
           << "  outf(fp, \"PSR_HASH" << "=%u\\n\", PSR_HASH);\n";
}

 c_stream << "}\n"
          << "\n"
          << "unsigned char write_" << family_name << "_vars(const char *file)\n"
          << "{\n"
          << "  FILE *fp = 0;\n"
          << "\n";

 if ( defines.find("PSR_EXTERN") == defines.end() )
{
  c_stream << "  init_" << family_name << "_vars();\n"
           << "\n";
}

 c_stream << "  if ((fp = fopen(file, \"w\")))\n"
          << "  {\n"
          << "    write_" << family_name << "_vars_internal(fp, (int (*)(void *, const char *, ...))fprintf);\n"
          << "    fclose(fp);\n"
          << "\n"
          << "    return(1);\n"
          << "  }\n"
          << "  return(0);\n"
          << "}\n";

 if ( defines.find("PSR_COMPRESSED") != defines.end() )
{
  c_stream << "\n"
           << "unsigned char write_" << family_name << "_vars_compressed(const char *file)\n"
           << "{\n"
           << "  gzFile gzfp;\n"
           << "\n";

  if ( defines.find("PSR_EXTERN") == defines.end() )
{
   c_stream << "  init_" << family_name << "_vars();\n"
            << "\n";
}

  c_stream << "  if ((gzfp = gzopen(file, \"wb9\")))\n"
           << "  {\n"
           << "    write_" << family_name << "_vars_internal(gzfp, gzprintf);\n"
           << "    gzclose(gzfp);\n"
           << "\n"
           << "    return(1);\n"
           << "  }\n"
           << "\n"
           << "  return(0);\n"
           << "}\n";
}

 if ( defines.find("PSR_MEMCPY") != defines.end() )
{
  c_stream << "\n"
           << "static unsigned int " << family_name << "_vars_memory(unsigned char *buffer, void *(*cpy)(void *, void *, size_t))\n"
           << "{\n"
           << "  unsigned char *p = buffer;\n";

  for ( i = variable::config_data.begin(); i != variable::config_data.end(); i++ )
{
   string dependancy_prefix, dependancy_suffix;

   if (i->dependancy != "")
{
    dependancy_prefix = string("if (") + string(i->dependancy, 0, i->dependancy.length()-1) + string(") { ");
    dependancy_suffix = " }";
}

   if ( i->format == variable::ptr )
{
    c_stream << "  " << dependancy_prefix << "cpy(p, " << i->name << ", sizeof(" <<variable::info[i->type].CTypeSpace << ")*" << i->length << "); p += sizeof(" << variable::info[i->type].CTypeSpace << ")*" << i->length << ";" << dependancy_suffix << "\n";
}
   else if ( i->format != variable::none )
{
    c_stream << "  " << dependancy_prefix << "cpy(p, " << ((i->format == variable::single) ? "&" : "") << i->name << ", sizeof(" << i->name << ")); p += sizeof(" << i->name << ");" << dependancy_suffix << "\n";
}

}

  c_stream << "  return(p-buffer);\n"
           << "}\n"
           << "\n"
           << "static void *cpynull(void *l, void *r, size_t len){ return(0); }\n"
           << "\n"
           << "unsigned int size_" << family_name << "_vars_memory()\n"
           << "{\n"
           << "  return(" << family_name << "_vars_memory(0, cpynull));\n"
           << "}\n"
           << "\n"
           << "void write_" << family_name << "_vars_memory(unsigned char *buffer)\n"
           << "{\n"
           << "  " << family_name << "_vars_memory(buffer, (void *(*)(void *, void *, size_t))memcpy);\n"
           << "}\n";
}

}

void output_packed_read( ostream &c_stream )
{

 if ( variable::config_data.packed_used() )
{
  c_stream << "\n"
           << "static size_t base94_decode(const char *buffer)\n"
           << "{\n"
           << "  size_t size = 0;\n"
           << "  int i;\n"
           << "  for (i = 4; i >= 0; i--)\n"
           << "  {\n"
             << "    size *= 94;\n"
             << "    size += (size_t)(buffer[i]-' ');\n"
             << "  }\n"
             << "  return(size);\n"
             << "}\n"
             << "\n"
             << "static char *get_token(char *str, char *delim)\n"
             << "{\n"
             << "  static char *pos = 0;\n"
             << "  char *token = 0;\n"
             << "\n"
             << "  if (str) //Start a new string?\n"
             << "  {\n"
             << "    pos = str;\n"
             << "  }\n"
             << "\n"
             << "  if (pos)\n"
             << "  {\n"
             << "    //Skip delimiters\n"
             << "    while (*pos && strchr(delim, *pos))\n"
             << "    {\n"
             << "      pos++;\n"
             << "    }\n"
             << "    if (*pos)\n"
             << "    {\n"
             << "      token = pos;\n"
             << "\n"
             << "      //Skip non-delimiters\n"
             << "      while (*pos && !strchr(delim, *pos))\n"
             << "      {\n"
             << "        //Skip quoted characters\n"
             << "        if ((*pos == '\\\"') || (*pos == '\\''))\n"
             << "        {\n"
             << "          char *match_pos = 0;\n"
             << "          if ((match_pos = find_next_match(pos+1, *pos)))\n"
             << "          {\n"
             << "            pos = match_pos;\n"
             << "          }\n"
             << "        }\n"
             << "        pos++;\n"
             << "      }\n"
             << "      if (*pos)\n"
             << "      {\n"
             << "        *pos++ = '\\0';\n"
             << "      }\n"
             << "    }\n"
             << "  }\n"
             << "  return(token);\n"
             << "}\n"
             << "\n"
             << "static char *char_array_unpack(char *str)\n"
             << "{\n"
             << "  char packed[LINE_LENGTH];\n"
             << "  char *p = packed, *token;\n"
             << "  size_t len = 0;\n"
             << "  memset(packed, 0, sizeof(packed));\n"
             << "  for (token = get_token(str, \"\\\\\"); token; token = get_token(0, \"\\\\\"))\n"
             << "  {\n"
             << "    if (*token == '0')\n"
             << "    {\n"
             << "      size_t i = base94_decode(decode_string(token+1));\n"
             << "      len += i;\n"
             << "      if (len > sizeof(packed)) { break; }\n"
             << "      memset(p, 0, i);\n"
             << "      p += i;\n"
             << "    }\n"
             << "    else\n"
             << "    {\n"
             << "      char *decoded = decode_string(token);\n"
             << "      size_t decoded_length = strlen(decoded);\n"
             << "      len += decoded_length;\n"
             << "      if (len > sizeof(packed))\n"
             << "      {\n"
             << "        memcpy(p, decoded, sizeof(packed)-(len-decoded_length));\n"
             << "        break;\n"
             << "      }\n"
             << "      memcpy(p, decoded, decoded_length);\n"
             << "      p += decoded_length;\n"
             << "    }\n"
             << "  }\n"
             << "  memcpy(line, packed, sizeof(packed));"
             << "  return(line);\n"
             << "}\n";
}

}

void output_array_read( ostream &c_stream, variable::ctype type )
{

 if ( variable::config_data.ctype_mult_used(type) || variable::config_data.ctype_ptr_used(type) )
{
  c_stream << "\n"
           << "static void read_" << variable::info[type].CTypeUnderscore << "_array(char *line, " << variable::info[type].CTypeSpace << " *var, size_t size)\n"
           << "{\n"
           << "  size_t i;\n"
           << "  char *token;\n"
           << "  *var = (" << variable::info[type].CTypeSpace << ")" << (variable::info[type].Signed ? "atoi" : "atoui") << "(strtok(line, \", \\t\\r\\n\"));\n"
           << "  for (i = 1; (i < size) && (token = strtok(0, \", \\t\\r\\n\")); i++)\n"
           << "  {\n"
           << "    var[i] = (" << variable::info[type].CTypeSpace << ")" << (variable::info[type].Signed ? "atoi" : "atoui") << "(token);\n"
           << "  }\n"
           << "}\n";
}

}

void output_read_var(ostream& c_stream)
{
 set<string>::iterator i = dependancies.begin();
 variable::config_data_array::iterator i = variable::config_data.begin();

 output_packed_read(c_stream);
 output_array_read(c_stream, variable::UC);
 output_array_read(c_stream, variable::US);
 output_array_read(c_stream, variable::UD);
 output_array_read(c_stream, variable::SC);
 output_array_read(c_stream, variable::SS);
 output_array_read(c_stream, variable::SD);

 c_stream << "\n"
          << "static void read_" << family_name << "_vars_internal(void *fp, char *(*fin)(char *, int, void *), int (*fend)(void *))\n"
          << "{\n"
          << "  while (!fend(fp))\n"
          << "  {\n"
          << "    char *p, *var, *value;\n"
          << "\n"
          << "    fin(line, LINE_LENGTH, fp);\n"
          << "    if ((p = find_str(line, \";\"))) { *p = 0; }\n"
          << "    if ((p = strchr(line, '=')))\n"
          << "    {\n"
          << "      *p = 0;\n"
          << "      var = line;\n"
          << "      value = p+1;\n"
          << "      while (isspace(*var)) { var++; }\n"
          << "      while (isspace(*value)) { value++; }\n"
          << "      if ((p = find_str(var, \" \\t\\r\\n\"))) { *p = 0; }\n"
          << "      if ((p = find_str(value, \" \\t\\r\\n\"))) { *p = 0; }\n"
          << "      if (!*var || !*value) { continue; }\n";

 if ( dependancies.size() )
{
  c_stream << "      if ((p = strchr(var, ':')))\n"
           << "      {\n"
           << "        if (!strlen(p+1)) { continue; }\n"
           << "        if (!strncmp(var, \"" << *i << ":\", (p-var)+1)) { if (!" << *i << ") { continue; } }\n";

  for ( i++; i != dependancies.end(); i++ )
{
   c_stream << "        else if (!strncmp(var, \"" << *i << ":\", (p-var)+1)) { if (!" << *i << ") { continue; } }\n";
}

  c_stream << "        else { continue; }\n"
           << "      }\n";
}

 c_stream << "    }\n"
          << "    else\n"
          << "    {\n"
          << "      continue;\n"
          << "    }\n"
          << "\n";

 for ( ; i != variable::config_data.end(); i++ )
{

  if ( i->format != variable::none )
{
   c_stream << "    if (!strcmp(var, \"" << i->dependancy << i->name << "\")) { ";

   if ( i->format == variable::single )
{
    c_stream << i->name << " = (" << variable::info[i->type].CTypeSpace << ")" << (variable::info[i->type].Signed ? "atoi" : "atoui") << "(value);";
}
   else if ( ( i->format == variable::mult ) || ( i->format == variable::ptr ) )
{
    c_stream << "read_" << variable::info[i->type].CTypeUnderscore
             << "_array(value, " << i->name << ", " << i->length << ");";
}
   else if ( i->format == variable::quoted )
{
    c_stream << "*" << i->name << " = 0; "
             << "strncat(" << i->name << ", decode_string(value), sizeof(" << i->name << ")-1);";
}
   else if ( i->format == variable::mult_packed )
{
    c_stream << "memcpy(" << i->name << ", char_array_unpack(value), " << i->length << ");";
}

   c_stream << " continue; }\n";
}

}

 if ( defines.find("PSR_HASH") != defines.end() )
{
  c_stream << "    if (!strcmp(var, \"PSR_HASH\"))\n"
           << "    {\n"
           << "       if ((unsigned int)atoui(value) == PSR_HASH)\n"
           << "       {\n"
           << "         psr_init_done = 2;\n"
           << "         continue;\n"
           << "       }\n"
           << "       break;\n"
           << "    }\n";
}

 c_stream << "  }\n";

 if ( defines.find("PSR_HASH") != defines.end() )
{
  c_stream << "  if (psr_init_done == 2)\n"
           << "  {\n"
           << "    psr_init_done = 1;\n"
           << "  }\n"
           << "  else\n"
           << "  {\n"
           << "    psr_init_done = 0;\n"
           << "    init_" << family_name << "_vars();\n"
           << "  }\n";
}

 c_stream << "}\n"
          << "\n"
          << "unsigned char read_" << family_name << "_vars(const char *file)\n"
          << "{\n"
          << "  FILE *fp = 0;\n"
          << "\n";

 if ( defines.find("PSR_EXTERN") == defines.end() )
{
  c_stream << "  init_" << family_name << "_vars();\n"
           << "\n";
}

 c_stream << "  if ((fp = fopen(file, \"r\")))\n"
          << "  {\n"
          << "    read_" << family_name << "_vars_internal(fp, (char *(*)(char *, int, void *))fgets, (int (*)(void *))feof);\n"
          << "    fclose(fp);\n";

 if ( defines.find("PSR_NOUPDATE") == defines.end() )
{
  c_stream << "    write_" << family_name << "_vars(file);\n";
}

 c_stream << "    return(1);\n"
          << "  }\n"
          << "\n";

 if ( defines.find("PSR_NOUPDATE") == defines.end() )
{
  c_stream << "  write_" << family_name << "_vars(file);\n";
}

 c_stream << "  return(0);\n"
          << "}\n";

 if ( defines.find("PSR_COMPRESSED") != defines.end() )
{
  c_stream << "\n"
           << "static char *gzgets_fix(char *buf, int len, void *file)\n"
           << "{\n"
           << "  return(gzgets(file, buf, len));\n"
           << "}\n"
           << "\n"
           << "unsigned char read_" << family_name << "_vars_compressed(const char *file)\n"
           << "{\n"
           << "  gzFile gzfp;\n"
           << "\n";

  if ( defines.find("PSR_EXTERN") == defines.end() )
{
   c_stream << "  init_" << family_name << "_vars();\n"
            << "\n";
}

  c_stream << "  if ((gzfp = gzopen(file, \"rb\")))\n"
           << "  {\n"
           << "    read_" << family_name << "_vars_internal(gzfp, gzgets_fix, gzeof);\n"
           << "    gzclose(gzfp);\n";

  if ( defines.find("PSR_NOUPDATE") == defines.end() )
{
   c_stream << "    write_" << family_name << "_vars_compressed(file);\n";
}

  c_stream << "    return(1);\n"
           << "  }\n"
           << "\n";

  if ( defines.find("PSR_NOUPDATE") == defines.end() )
{
   c_stream << "  write_" << family_name << "_vars_compressed(file);\n";
}

  c_stream << "  return(0);\n"
           << "}\n";
}

 if ( defines.find("PSR_MEMCPY") != defines.end() )
{
  c_stream << "\n"
           << "static void *cpyright(void *src, void *dest, size_t len)\n"
           << "{\n"
           << "  memcpy(dest, src, len);\n"
           << "  return(0);\n"
           << "}\n"
           << "\n"
           << "void read_" << family_name << "_vars_memory(unsigned char *buffer)\n"
           << "{\n"
           << "  " << family_name << "_vars_memory(buffer, cpyright);\n"
           << "}\n";
}

}

void handle_directive( const char *instruction, const char *label )
{

 if ( !strcasecmp(instruction, "define") )
{

  if (label)
{
   defines.insert(label);
}
  else
{
   current_location.error("Could not get define label");
}

}
 else if ( !strcasecmp(instruction, "undef") )
{

  if (label)
{
   defines.erase(label);
}
  else
{
   current_location.error("Could not get undefine label");
}

}
 else if ( !strcasecmp(instruction, "ifdef") )
{

  if (label)
{

   if ( defines.find(label) != defines.end() )
{
    ifs.push(true);
}
   else
{
    ifs.push(false);
}

}
  else
{
   current_location.error( "Could not get ifdef label" );
}

}
 else if ( !strcasecmp(instruction, "ifndef") )
{

  if (label)
{

   if ( defines.find(label) == defines.end() )
{
    ifs.push(true);
}
   else
{
    ifs.push(false);
}

}
  else
{
   current_location.error( "Could not get ifndef label" );
}

}
 else if ( !strcasecmp(instruction, "else") )
{

  if (label)
{
   current_location.error( "Processor directive else does not accept labels" );
}
  else
{

   if ( ifs.empty() )
{
    current_location.error( "Processor directive else without ifdef" );
}
   else
{
    bool process = !ifs.top();
    ifs.pop();
    ifs.push(process);
}

}

}
 else if ( !strcasecmp(instruction, "elifdef") || !strcasecmp(instruction, "elseifdef") )
{

  if (label)
{

   if ( ifs.top() )
{
    ifs.pop();
    ifs.push(false);
}
   else if ( defines.find(label) != defines.end() )
{
    ifs.pop();
    ifs.push(true);
}

}
  else
{
   current_location.error( "Could not get elseifdef label" );
}

}
 else if ( !strcasecmp(instruction, "endif") )
{

  if (label)
{
   current_location.error( "Processor directive endif does not accept labels" );
}
  else
{

   if ( ifs.empty() )
{
    current_location.error( "Processor directive endif without ifdef" );
}
   else
{
    ifs.pop();
}

}

}
 else
{
  current_location.error( "Unknown processor directive" );
}

}

//Return the comment from global line variable
char *get_comment( char comment_seperator )
{
 char *comment = find_chr(line, comment_seperator);

 if ( comment )
{
  *comment = 0;
  comment++;

  if ( isspace( comment[ strlen(comment) - 1 ] ) )
{
   comment[strlen(comment)-1] = 0;
}

}

 return(comment);
}

void output_parser_comment( ostream &c_stream, const char *comment )
{

 if (comment)
{
  c_stream << " //" << comment;
}

 c_stream << "\n";
}

void output_header_conditional( ostream &cheader_stream, const char *instruction, const char *label )
{

 if ( ( !strcasecmp(instruction, "elifdef") || !strcasecmp(instruction, "elseifdef") ) && label )
{
  cheader_stream << "#elif defined(" << label << ")\n";
}
 else
{
  cheader_stream << "#" << instruction;

  if (label)
{
   cheader_stream << " " << label;
}

  cheader_stream << "\n";
}

}


void parser_generate( istream &psr_stream, ostream &c_stream, ostream &cheader_stream, string cheader_file = "" )
{
 ostringstream cvars(""), hvars("");
 uLong psr_file_hash = crc32(0L, Z_NULL, 0);

 current_location.line_number = current_location.column_number = 0;

 while ( !psr_stream.eof() )
{
  char *config_comment = 0, *parser_comment = 0, *token = 0;

  psr_stream.getline(line, LINE_LENGTH);
  current_location.line_number++;
  psr_file_hash = crc32(psr_file_hash, (const Bytef *)line, strlen(line));
  parser_comment = get_comment(';');

  if ( all_spaces(line) )
{

   if ( ifs.all_true() )
{
    output_parser_comment(cvars, parser_comment);
}

   continue;
}

  config_comment = get_comment('@');

  if (all_spaces(line) && config_comment)
{

   if ( ifs.all_true() )
{
    variable::config_data.add_comment(config_comment);
}

   continue;
}

  if ( ( token = get_token(line, " " ) ) &&
       ( strcasecmp(token, "NEWSYM" ) || ( token = get_token( 0, " ," ) ) ) )
{
   char *d;
   string varname;
   string dependancy;

   if ( ( *token == '#' ) || ( *token == '%' ) )
{
    char *next_token = get_token(0, " ");

    handle_directive( token + 1, next_token );

    if ( cheader_stream && ( !next_token || strncasecmp( next_token, "PSR_", strlen("PSR_") ) ) )
{
     output_header_conditional(hvars, token+1, next_token);
}

    continue;
}

   if ( ( d = strchr( token, ':' ) ) )
{
    varname = d + 1;
    dependancy.assign(token, d - token);
    dependancies.insert(dependancy);
    dependancy += ':';
}
   else
{
    varname = token;
}

   if ( ( token = get_token( 0, " ," ) ) )
{
    size_t array = 0;
    bool is_array = !strcasecmp(token, "times");
    bool is_packed = !strcasecmp(token, "packed");
    bool is_ptr = !strcasecmp(token, "ptr");

    if ( ( !is_array && !is_packed && !is_ptr) ||
         ( ( token = get_token( 0, " " ) ) && ( array = enhanced_atoi(token) ) &&
           ( token = get_token(0, " ") ) ) )
{
     char *asm_type = token;
     const char *var_type = convert_asm_type(asm_type);

     if (var_type)
{
      string initial_value = get_token(0, " ,\n");
      ostringstream var_init("");

      if ( ( ( initial_value[0] == '\"') &&
             ( initial_value[ initial_value.length() - 1 ] == '\"') ) ||
           ( ( initial_value[0] == '\'') &&
             ( initial_value[ initial_value.length() - 1 ] == '\'') ) )
{
//Make sure it's double quoted
       initial_value[0] = '\"';
       initial_value[ initial_value.length() - 1 ] = '\"';

       if (!array)
{
//Size minus quotes plus null
        array = initial_value.length() - 1;
}

       var_init << "char " << varname << "[" << array << "];";

       if ( ifs.all_true() )
{
        ostringstream memset_line;

        if ( initial_value.length() - 2 < array )
{
         memset_line << "strcpy(" << varname << ", " << initial_value << ");";
}
        else
{
         memset_line << "strncpy(" << varname << ", " << initial_value << ", " << (array-1) << "); "
                     << varname << "[" << array << "] = 0;";
}

        memsets.push_back( memset_line.str() );
        variable::config_data.add_var_quoted( varname, dependancy, CONFIG_COMMENT );
}

}
      else if (is_ptr)
{
       var_init << var_type << " *" << varname << ";";

       if ( ifs.all_true() )
{
        variable::config_data.add_var_ptr( varname, var_type, array, dependancy, CONFIG_COMMENT );
}

}
      else
{
       ssize_t init_value_num = safe_atoi( c_hex_convert( asm2c_hex_convert( initial_value) ) );

       if ( ( init_value_num < 0 ) &&
            !strncmp( var_type, "unsigned ", strlen("unsigned ") ) )
{
        var_type += strlen("unsigned ");
}

       var_init << var_type << " " << varname;

       if (array)
{

        if ( var_type_is_char(var_type) || !init_value_num )
{
         var_init << "[" << array << "]";

         if ( ifs.all_true() )
{
          ostringstream memset_line;
          memset_line << "memset(" << varname << ", " << init_value_num << ", " << array;

          if ( var_type_is_short(var_type) )
{
           memset_line << "*sizeof(short)";
}
          else if ( var_type_is_int(var_type) )
{
           memset_line << "*sizeof(int)";
}

          memset_line << ");";
          memsets.push_back( memset_line.str() );
}

}
        else
{
         var_init << "[" << array << "] = {";

         for ( size_t i = array; i > 1; i-- )
{
          var_init << init_value_num << ",";
}

         var_init << init_value_num << "}";
}

        if ( ifs.all_true() )
{

         if (is_array)
{
          variable::config_data.add_var_mult(varname, var_type, array, dependancy, CONFIG_COMMENT);
}
         else if (is_packed)
{
          variable::config_data.add_var_packed(varname, array, dependancy, CONFIG_COMMENT);
}

}

}
       else
{

        if ( ( token = get_token(0, " ,\n") ) )
{
         array = 1;
         var_init << "[] = {" << init_value_num;

         do
{
          var_init << "," << atoi(token);
          array++;
}        while( ( token = get_token(0, " ,\n") ) );

         var_init << "}";

         if ( ifs.all_true() )
{
          variable::config_data.add_var_mult(varname, var_type, array, dependancy, CONFIG_COMMENT);
}

}
        else
{
         var_init << " = " << init_value_num;

         if ( ifs.all_true() )
{
          variable::config_data.add_var_single(varname, var_type, dependancy, CONFIG_COMMENT);
}

}

}

       var_init << ";";
}

      if ( ifs.all_true() )
{
       cvars << var_init.str();
}

      if (cheader_stream)
{
       string header_data = var_init.str();
       size_t equal_pos;

       if ( ( equal_pos = header_data.find("=") ) != string::npos )
{
        header_data.erase(equal_pos - 1);
        header_data.append(";");
}

       hvars << "extern " << header_data << "\n";
}

}
//Else already handled
}
    else
{
     current_location.error( "Could not get array size" );
}

}
   else
{
    current_location.error( "Could not get type" );
}

}
  else
{
   current_location.error( "Could not get variable name" );
}

  if ( ifs.all_true() )
{
   output_parser_comment(cvars, parser_comment);
}

}

 output_parser_start(c_stream, cheader_file);
 output_extsym_dependancies(c_stream);

 if ( defines.find("PSR_EXTERN") == defines.end() )
{
  c_stream << cvars.str();
  output_init_var(c_stream);
}
 else if ( !cheader_file.length() )
{
  cerr << "Error: Requested PSR_EXTERN yet no header file specified." << endl;
}

 if ( defines.find("PSR_HASH") != defines.end() )
{
  c_stream << "static unsigned int PSR_HASH = 0x" << hex << psr_file_hash << dec << ";\n";
}

 output_write_var(c_stream);
 output_read_var(c_stream);
 c_stream << "\n";

 if (cheader_stream)
{
  output_cheader_start(cheader_stream);
  cheader_stream << hvars.str();
  output_cheader_end(cheader_stream);
}

 if ( !ifs.empty() )
{
  cerr << "Error: " << ifs.size() << " ifdef segments have no endif." << endl;
}

}

int main( int argc, const char **argv )
{
 const char *cheader_file = 0;
 bool compile = false;
 int param_pos = 1;

 for ( ; param_pos < argc; param_pos++ )
{

  if ( !strncmp(argv[param_pos], "-D", 2) )
{
   defines.insert( argv[param_pos] + 2 );
}
  else if ( !strcmp(argv[param_pos], "-cheader") )
{
   param_pos++;
   cheader_file = argv[param_pos];
}
  else if ( !strcmp(argv[param_pos], "-compile") )
{
   compile = true;
}
  else if ( !strcmp(argv[param_pos], "-flags") )
{
   param_pos++;
   cflags = argv[param_pos];
}
  else if ( !strcmp(argv[param_pos], "-fname") )
{
   param_pos++;
   family_name = argv[param_pos];
}
  else if ( !strcmp(argv[param_pos], "-gcc") )
{
   param_pos++;
   gcc = argv[param_pos];
}
  else
{
   break;
}

}

 if ( ( argc - param_pos) != 2 )
{
  cout << "Config file handler creator by Nach (C) 2005-2007\n"
       << "\n"
       << "Usage:\n"
       << "parsegen [options] <output> <input>\n"
       << "\n"
       << "\n"
       << "Options:\n"
       << "\n"
       << "  -Ddefine   Define a processor director. Example: -D__MSDOS__\n"
       << "             Can specify multiple defines.\n"
       << "\n"
       << "  -cheader   Create a C/C++ header with the following name.\n"
       << "             Example: -cheader cfgvars.h\n"
       << "\n"
       << "  -fname     Use the following name for the main functions.\n"
       << "             Example: -fname math\n"
       << "             Would make init_cfg_vars become init_math_vars the\n"
       << "             happens to write_cfg_vars and read_cfg_vars.\n"
       << "\n"
       << "  -compile   Compiles output instead of outputting C file.\n"
       << "\n"
       << "  -gcc       Use with -compile. Parameter passed in the name of\n"
       << "             the C compiler to use, it should be GCC based.\n"
       << "             It will not work with MSVC based compilers.\n"
       << "\n"
       << "  -flags     Use with -compile. Flags passed as next parameter\n"
       << "             are passed to the C compiler.\n"
       << "             Example: -flags \"-O3 -march=pentium3 -ggdb3\"\n"
       << "\n"
       << endl;

  return(1);
}

 string cname = family_name+string(".c");
 const char *psr_file = argv[param_pos+1], *c_file = compile ? cname.c_str() : argv[param_pos], *obj_file = compile ? argv[param_pos] : 0;
 int ret_val = 0;

 ifstream psr_stream(psr_file);

 if (psr_stream)
{
  ofstream c_stream(c_file);

  if (c_stream)
{
   ofstream cheader_stream;

   if (cheader_file)
{
    cheader_stream.open(cheader_file);

    if (cheader_stream)
{
     parser_generate(psr_stream, c_stream, cheader_stream, cheader_file);
}
    else
{
     cerr << "Error opening " << cheader_file << " for writing." << endl;
     ret_val |= 8;
}

    cheader_stream.close();
}
   else
{
    parser_generate(psr_stream, c_stream, cheader_stream);
}

   c_stream.close();
}
  else
{
   cerr << "Error opening " << c_file << " for writing." << endl;
   ret_val |= 2;
}

  psr_stream.close();
}
 else
{
  cerr << "Error opening " << psr_file << " for reading." << endl;
  ret_val |= 4;
}

 if ( !ret_val && compile )
{
  string command = COMPILE_OBJ(obj_file, cname);
  cout << "parsegen: " << command << "\n";
  system(command.c_str());
  remove(cname.c_str());
}

 return(ret_val);
}