/* Copyright (C) 2005-2007 Nach ( http://nsrt.edgeemu.com ) Config file handler creator by Nach (C) 2005-2007 */ #include #include #include #include #include #include #include #include #include #include #include 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 defines, dependancies; vector 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::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 \n" << "#include \n" << "#include \n" << "#include \n"; if ( defines.find("PSR_COMPRESSED") != defines.end() ) { c_stream << "#include \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::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::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(" <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::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] \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); }