The saved game structure is a little harder to get into a postable state than I thought (I've separated everything into classes). It's going to take some additional time to get it in a state which I can share.
In the mean time, here is a collection of functions I wrote for editing EHM 2007 I've called lib_ehm07. I've written some simple examples to show how the functions work. Hopefully these functions will save you a lot of time (e.g. you can load and save from/to the database using just one line of code). Follow the steps below:
You'll see once you've followed the instructions below that at the bottom of lib_ehm07.h there are implementations of the ReadDB and WriteDB function templates. The list isn't comprehensive. If you want to open or save a dat file which isn't listed there, you'll need to add an implementation for it. For example, if you wanted to open the currencies.dat file (which uses the CURRENCIES struct), you'd add this for ReadDB (and you'd need to add one for WriteDB if you want to use this function with currencies.dat):
1) Create a new project in MS Visual C++ (or whichever IDE you're using). Add a new cpp file to it and call it something like main.cpp. Then paste the following code into main.cpp:
2) Add the usual database_flags.h and database_types.h to your project. In MS Visual C++ you can do this by clicking on the Project menu -> Add Existing Item.
3) Add a new .h file and call it lib_ehm07.h. Paste in the following code:
Code: Select all
#ifndef LIB_EHM07_H
#define LIB_EHM07_H
#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include "database_flags.h"
#include "database_types.h"
// ehm:: namespace is used for all functions below
namespace ehm
{
// CSV Functions
char DelimiterDetect(const std::string &);
char DelimiterLocale();
void Parse(std::string[], const int &, const std::string &, const char &);
void Parse(std::vector<std::string> &, const short &, const std::string &, const char &);
bool ReadCSV(const char [], std::vector<std::vector<std::string>> &, const short &, const short &, const bool & = false);
// Database I/O Functions
template <typename T> bool ReadDB(const char [], std::vector<T> &);
template <typename T> bool WriteDB(const char [], const std::vector<T> &, const bool & = false);
// Date Functions
short EHMDate(short &, short &, const bool &);
bool LeapYearCheck(const short &);
void StandardDate(short, short &, short &, const bool &);
// General Functions
long IndexSize(char [], unsigned int);
bool IndexUpdate();
// Text Functions
std::string ASCII(std::string &, const bool & = true);
void LowerCase(std::string &);
std::string StripText(std::string &, const bool & = true);
}
/* ============================================================== */
/* DATABASE I/O FUNCTIONS (IMPLEMENTATION OF TEMPLATES) */
/* ============================================================== */
// Load a database .dat file for reading into a vector of structs
template bool ehm::ReadDB(const char [], std::vector<CITIES> &);
template bool ehm::ReadDB(const char [], std::vector<CLUBS> &);
template bool ehm::ReadDB(const char [], std::vector<CLUB_COMP_HISTORIES> &);
template bool ehm::ReadDB(const char [], std::vector<CLUB_COMPS> &);
template bool ehm::ReadDB(const char [], std::vector<DB_CLUB_RECORDS> &);
template bool ehm::ReadDB(const char [], std::vector<DB_PLAYER_INFO> &);
template bool ehm::ReadDB(const char [], std::vector<DB_PLAYER_RIGHTS> &);
template bool ehm::ReadDB(const char [], std::vector<DB_STAFF_INFO> &);
template bool ehm::ReadDB(const char [], std::vector<DRAFTED_PLAYERS> &);
template bool ehm::ReadDB(const char [], std::vector<NAMES> &);
template bool ehm::ReadDB(const char [], std::vector<NATIONS> &);
template bool ehm::ReadDB(const char [], std::vector<NON_PLAYERS> &);
template bool ehm::ReadDB(const char [], std::vector<OFFICIALS> &);
template bool ehm::ReadDB(const char [], std::vector<PLAYERS> &);
template bool ehm::ReadDB(const char [], std::vector<STAFF> &);
template bool ehm::ReadDB(const char [], std::vector<STAFF_COMPS> &);
template bool ehm::ReadDB(const char [], std::vector<STAFF_COMP_HISTORIES> &);
template bool ehm::ReadDB(const char [], std::vector<STAFF_HISTORIES> &);
template bool ehm::ReadDB(const char [], std::vector<STAFF_LANGUAGES> &);
template bool ehm::ReadDB(const char [], std::vector<STAFF_PREFERENCES> &);
// Write the vector of structs to a database .dat file
template bool ehm::WriteDB(const char [], const std::vector<CLUBS> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<CLUB_COMP_HISTORIES> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<DB_CLUB_RECORDS> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<DB_PLAYER_INFO> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<DB_PLAYER_RIGHTS> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<DB_STAFF_INFO> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<DRAFTED_PLAYERS> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<NAMES> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<NATIONS> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<NON_PLAYERS> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<OFFICIALS> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<PLAYERS> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<STAFF> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<STAFF_COMP_HISTORIES> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<STAFF_HISTORIES> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<STAFF_LANGUAGES> &, const bool &);
template bool ehm::WriteDB(const char [], const std::vector<STAFF_PREFERENCES> &, const bool &);
#endif
4. Add a new .cpp file and call it lib_ehm07.cpp. Paste in the following code:
Code: Select all
#define _WIN32_WINNT _WIN32_WINNT_WINXP // Helps with Windows XP compatibility
#pragma pack(1)
#include "lib_ehm07.h"
/* ======================= */
/* CSV FUNCTIONS */
/* ======================= */
// --- Detect delimiter based up a string of text --- //
// ehm::DelimiterDetect(string of text)
char ehm::DelimiterDetect(const std::string &text)
{
unsigned short count = 0;
for(auto itr = text.begin(); itr < text.end(); ++itr)
if(*itr == ';')
++count;
// If the number of semicolons is greater than zero, return the delimiter as semicolon; otherwise return it as comma
return (count > 0) ? ';' : ',';
}
// --- Determine default delimiter based upon system locale --- //
char ehm::DelimiterLocale()
{
return (std::use_facet<std::numpunct<char>>(std::cout.getloc()).decimal_point() == '.') ? ',' : ';';
}
// --- Parse a string of delimited text (array method) --- //
void ehm::Parse(std::string string_buffer[], const int &max_element, const std::string &csv_string, const char &delimiter)
{
std::stringstream csv_line(csv_string);
// Parse each delimiter until the final delimiter
for(int i = 0; i < (max_element-1); ++i)
std::getline(csv_line, string_buffer[i], delimiter);
// After the final delimiter, get the remaining text from the line
getline(csv_line, string_buffer[max_element-1]);
return;
}
// --- Parse a string of delimited text (vector method) --- //
void ehm::Parse(std::vector<std::string> &string_buffer, const short &columns, const std::string &csv_string, const char &delimiter)
{
// Clear and resize the buffer before proceeding
string_buffer.clear();
string_buffer.resize(columns);
// Stringstream the string of text
std::stringstream csv_line(csv_string);
// Parse each delimiter until the final delimiter
for(int i = 0; i < columns; ++i)
std::getline(csv_line, string_buffer[i], delimiter);
// After the final delimiter, get the remaining text from the line
getline(csv_line, string_buffer[columns-1]);
return;
}
// --- Read a CSV delimited file into vector of strings --- //
// ehm::ReadCSV("filename.csv", vector to store unformatted string data, number of columns in csv, number of header rows in csv to ignore, false)
bool ehm::ReadCSV(const char filename[], std::vector<std::vector<std::string>> &vect, const short &columns, const short &header_rows, const bool &setting)
{
std::cout << "Loading " + (std::string) filename << "\t";
std::fstream file (filename, std::ios::in);
// Abort if the file could not be opened
if(!file.is_open())
{
std::cout << "ERROR" << std::endl;
return false;
}
// Calculate file size
file.seekg (0, std::ios::end);
std::streamoff filesize = file.tellg();
file.seekg (0, std::ios::beg);
// Buffers
std::string csv_string; // Line of text from the csv file
std::vector<std::string> buffer; // Buffer for storing the parsed data
buffer.reserve(columns); // Reserve the correct number of elements in the buffer according to the number columns of data
char d = ','; // Delimiter type. Default as comma to start with. It can be changed later using DelimiterDetect().
if(setting == false)
{
// Skip the two header rows
for(short i = 0; i < header_rows; ++i)
std::getline(file, csv_string);
// Detect the d based upon the header row
d = ehm::DelimiterDetect(csv_string);
}
else
{
// Get the first header row...
std::getline(file, csv_string);
// Detect the d based upon the header row
d = ehm::DelimiterDetect(csv_string);
// ...and check the first column for the setting text
ehm::Parse(buffer, columns, csv_string, d);
// Skip and remaining header rows
for(short i = 1; i < header_rows; ++i)
std::getline(file, csv_string);
}
while(file.tellg() < filesize)
{
// Get the line of csv and parse it
std::getline(file, csv_string);
ehm::Parse(buffer, columns, csv_string, d);
// Only add the data to the vector if both the first two columns of data are present (i.e. not empty)
if(!buffer[0].empty() && !buffer[1].empty())
vect.push_back(buffer);
}
file.close();
std::cout << vect.size() << "\t" << "DONE" << std::endl;
return true;
}
/* ================================ */
/* DATABASE I/O FUNCTIONS */
/* ================================ */
// --- Load a database .dat file and populate a vector of the relevant struct
// ehm::ReadDB("filename.dat", vector of structs);
template <typename T> bool ehm::ReadDB(const char filename[], std::vector<T> &vect)
{
std::cout << "Loading " + (std::string) filename << "\t";
std::fstream file (filename, std::ios::in | std::ios::binary);
// Calculate file size
file.seekg (0, std::ios::end);
std::streamoff filesize = file.tellg();
file.seekg (0, std::ios::beg);
// Struct buffer
T struct_buffer;
// Abort if the file cannot be opened
if(!file.is_open())
{
std::cout << "ERROR" << std::endl;
return false;
}
// Add the data to the vector of structs
while(file.tellg() < filesize)
{
file.read((char*)&struct_buffer, sizeof(T));
vect.push_back(struct_buffer);
}
file.close();
std::cout << vect.size() << "\t" << "DONE" << std::endl;
return true;
}
// --- Open a database .dat file for writing and write a vector of structs to the file --- //
// ehm::WriteDB("filename.dat", vector of structs, true = erase existing contents / false = add contents of vector to end of file)
template <typename T> bool ehm::WriteDB(const char filename[], const std::vector<T> &vect, const bool &truncate)
{
std::cout << "Saving " + (std::string) filename << "\t";
// Open the file
std::fstream file;
// Truncate and write
if(truncate == true)
file.open(filename, std::fstream::out | std::fstream::trunc | std::ios::binary);
// Append and write
else
file.open(filename, std::ios::in | std::fstream::out | std::fstream::ate | std::ios::binary);
// Abort if the file cannot be opened
if(!file.is_open())
{
std::cout << "ERROR" << std::endl;
return false;
}
// Write the vector of structs
for(unsigned long i = 0; i < vect.size(); ++i)
file.write((char*)&vect[i], sizeof(T));
file.close();
std::cout << vect.size() << "\t" << "DONE" << std::endl;
return true;
}
/* ======================== */
/* DATE FUNCTIONS */
/* ======================== */
// --- Convert a standard date to an EHM date --- //
// ehm::EHMDate(date of month, month, true = the year is a leap year / false = not a leap year)
short ehm::EHMDate(short &day, short &month, const bool &leap_year)
{
short month_lengths[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if(leap_year == true)
month_lengths[1] = 29;
short date = 0;
// Prevent any dates out of range prior to processing.
if(day < 1) day = 1;
else if(day > 31) day = 31;
if(month < 1) month = 1;
else if(month > 12) month = 12;
for(short i = 0; i < (month-1); ++i) date += month_lengths[i];
// The first day of the year is zero. Therefore you must subtract one from the date.
day += (date - 1);
// Prevent any dates out of range after processing.
if(day < 0) day = 0;
else if(day > 365) day = 365;
return day;
}
// --- Check whether a given year is a leap year --- //
// ehm::LeapYearCheck(year)
bool ehm::LeapYearCheck(const short &year)
{
return((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
}
// --- Convert an EHM date to a standard date. ehm_day is passed by value because temporary changes must be made to it during the calculation process --- //
// ehm::StandardDate(ehm day value, destination for storing the day, destination for storing the month, ehm leap year value)
void ehm::StandardDate(short ehm_day, short &day, short &month, const bool &leap_year)
{
short month_length[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
short month_days = 0;
month = 0;
if(leap_year == true) month_length[1] = 29;
// The first SI_DATE day of the year is zero. Therefore you must add one to the si_days before conversion.
++ehm_day;
while(ehm_day > month_days) month_days += month_length[(month)++];
day = ehm_day - month_days + month_length[(month)-1];
// Prevent any dates out of range (well, at least the day won't exceed 31).
if(day < 0) day = 0;
else if(day > 31) day = 31;
if(month < 1) month = 1;
else if(month > 12) month = 12;
return;
}
/* =========================== */
/* GENERAL FUNCTIONS */
/* =========================== */
// -- Calculate number of entries in a database file for updating index.dat --- //
// ehm::IndexSize("filename.dat", sizeof(STRUCT) - this is used via IndexUpdate() - you shouldn't really need to use this function directly
long ehm::IndexSize(char filename[], unsigned int structure)
{
std::fstream file (filename, std::ios::in | std::ios::binary);
if(!file.is_open())
return -1;
file.seekg (0, std::ios::end);
return static_cast<unsigned int>(file.tellg()) / structure;
}
// -- Update index.dat --- //
bool ehm::IndexUpdate()
{
// Array to store index values for each database file
long index[35];
std::cout << "Updating index.dat" << "\t";
// Calculate index values for each database file
index[0] = ehm::IndexSize("club.dat", sizeof(CLUBS));
index[1] = ehm::IndexSize("nat_club.dat", sizeof(CLUBS));
index[2] = ehm::IndexSize("colour.dat", sizeof(COLOURS));
index[3] = ehm::IndexSize("continent.dat", sizeof(CONTINENTS));
index[4] = ehm::IndexSize("nation.dat", sizeof(NATIONS));
index[5] = ehm::IndexSize("officials.dat", sizeof(OFFICIALS));
index[6] = ehm::IndexSize("stadium.dat", sizeof(ARENAS));
index[7] = ehm::IndexSize("staff.dat", sizeof(STAFF));
index[8] = ehm::IndexSize("nonplayer.dat", sizeof(NON_PLAYERS));
index[9] = ehm::IndexSize("player.dat", sizeof(PLAYERS));
index[10] = ehm::IndexSize("staff_comp.dat", sizeof(STAFF_COMPS));
index[11] = ehm::IndexSize("city.dat", sizeof(CITIES));
index[12] = ehm::IndexSize("club_comp.dat", sizeof(CLUB_COMPS));
index[13] = ehm::IndexSize("nation_comp.dat", sizeof(CLUB_COMPS));
index[14] = ehm::IndexSize("first_names.dat", sizeof(NAMES));
index[15] = ehm::IndexSize("second_names.dat", sizeof(NAMES));
index[16] = ehm::IndexSize("staff_history.dat", sizeof(STAFF_HISTORIES));
index[17] = ehm::IndexSize("staff_comp_history.dat", sizeof(STAFF_COMP_HISTORIES));
index[18] = ehm::IndexSize("club_comp_history.dat", sizeof(CLUB_COMP_HISTORIES));
index[19] = ehm::IndexSize("nation_comp_history.dat", sizeof(CLUB_COMP_HISTORIES));
index[20] = ehm::IndexSize("affiliations.dat", sizeof(AFFILIATIONS));
index[21] = ehm::IndexSize("retired_numbers.dat", sizeof(RETIRED_NUMBERS));
index[22] = ehm::IndexSize("states_provinces.dat", sizeof(STATES_PROVINCES));
index[23] = ehm::IndexSize("injuries.dat", sizeof(INJURIES));
index[24] = ehm::IndexSize("staff_preferences.dat", sizeof(STAFF_PREFERENCES));
index[25] = ehm::IndexSize("currencies.dat", sizeof(CURRENCIES));
index[26] = ehm::IndexSize("club_records.dat", sizeof(DB_CLUB_RECORDS));
index[27] = ehm::IndexSize("club_histories.dat", sizeof(CLUB_HISTORIES));
index[28] = ehm::IndexSize("drafts.dat", sizeof(DRAFTS));
index[29] = ehm::IndexSize("drafted_players.dat", sizeof(DRAFTED_PLAYERS));
index[30] = ehm::IndexSize("player_rights.dat", sizeof(DB_PLAYER_RIGHTS));
index[31] = ehm::IndexSize("stage_names.dat", sizeof(STAGE_NAMES));
index[32] = ehm::IndexSize("staff_languages.dat", sizeof(STAFF_LANGUAGES));
index[33] = ehm::IndexSize("player_info.dat", sizeof(DB_PLAYER_INFO));
index[34] = ehm::IndexSize("staff_info.dat", sizeof(DB_STAFF_INFO));
std::cout << "N/A" << "\t";
// Check for any errors returned from the IndexSize function (and abort before writing to index.dat)
for(short i = 0; i < 35; ++i)
{
if(index[i] < 0)
{
std::cout << "ERROR" << std::endl << "Unable to open all .dat files" << std::endl;
return false;
}
}
// Write to index.dat
std::fstream file_index ("index.dat", std::ios::in | std::ios::out | std::ios::binary);
if(!file_index.is_open())
{
std::cout << "ERROR" << std::endl << "Unable to open index.dat" << std::endl;
return false;
}
// File position marker
std::streamoff pos = 63;
for(short i = 0; i < 35; ++i)
{
file_index.seekp (pos, std::ios::beg);
file_index.write ((char*)&index[i], sizeof(index[i]));
pos += 63;
}
file_index.close();
std::cout << "DONE" << std::endl;
return true;
}
/* ======================== */
/* TEXT FUNCTIONS */
/* ======================== */
// --- Convert SI Font text to ASCII text. The bLowerCase bool enables conversion to lower case --- //
// ehm::ASCII(string of text, true = convert to lowercase / false = leave the case as it is)
std::string ehm::ASCII(std::string &ehm_text, const bool &lower_case)
{
// Don't process the string if it is empty
if(ehm_text.empty())
return ehm_text;
// Multidimensional array of SI font characters ([i][0]) and ASCII characters ([i][1])
const int font[][2] =
{
{ '\xBC', '\x43' }, // C - Caron - Uppercase
{ '\xA0', '\x63' }, // c - Caron - Lowercase
{ '\xBE', '\x44' }, // D - Caron - Uppercase
{ '\xBB', '\x64' }, // d - Caron - Lowercase
{ '\x86', '\x45' }, // E - Caron - Uppercase
{ '\x90', '\x65' }, // e - Caron - Lowercase
{ '\xB1', '\x4E' }, // N - Caron - Uppercase
{ '\x8F', '\x6E' }, // n - Caron - Lowercase
{ '\xB3', '\x52' }, // R - Caron - Uppercase
{ '\xA7', '\x72' }, // r - Caron - Lowercase
{ '\x8A', '\x53' }, // S - Caron - Uppercase
{ '\xBD', '\x53' }, // S - Caron - Uppercase
{ '\x9A', '\x73' }, // s - Caron - Lowercase
{ '\x87', '\x55' }, // U - Ring Above - Uppercase
{ '\x9E', '\x7A' }, // z - Caron - Lowercase
{ '\x9F', '\x7A' }, // z - Caron - Lowercase
{ '\x8E', '\x5A' }, // Z - Caron - Uppercase
{ ',', '_'}, // Comma delimiter
{ ';', '_'} // Semicolon delimiter
};
short font_size = sizeof(font)/sizeof(*font);
// Check for SI Font characters
for(short i = 0; i < font_size; ++i)
replace(ehm_text.begin(), ehm_text.end(), font[i][0], font[i][1]);
// Remove trademark symbol if present at the end of the string
if(ehm_text[ehm_text.length()-1] == '\x99')
ehm_text.erase(ehm_text.length()-1);
// Convert the text to lower case
if(lower_case == true)
ehm::LowerCase(ehm_text);
return ehm_text;
}
// --- Convert text to lowercase --- //
// ehm::LowerCase(string of text)
void ehm::LowerCase(std::string &text)
{
// Multidimensional array of uppercase ([i][0]) to lowercase characters ([i][1])
const int font[][2] =
{
{ '\xC0', '\xE0' }, // A - Grave - Uppercase
{ '\xC1', '\xE1' }, // A - Acute - Uppercase
{ '\xC2', '\xE2' }, // A - Circumflex - Uppercase
{ '\xC3', '\xE3' }, // A - Tilde - Uppercase
{ '\xC4', '\xE4' }, // A - Umlauts - Uppercase
{ '\xC5', '\xE5' }, // A - Ring Above - Uppercase
{ '\xC6', '\xE6' }, // AE - Joined - Uppercase
{ '\xC7', '\xE7' }, // C - Cedilla - Uppercase
{ '\xC8', '\xE8' }, // E - Grave - Uppercase
{ '\xC9', '\xE9' }, // E - Acute - Uppercase
{ '\xCA', '\xEA' }, // E - Circumflex - Uppercase
{ '\xCB', '\xEB' }, // E - Umlauts - Uppercase
{ '\xCC', '\xEC' }, // I - Grave - Uppercase
{ '\xCD', '\xED' }, // I - Acute - Uppercase
{ '\xCE', '\xEE' }, // I - Circumflex - Uppercase
{ '\xCF', '\xEF' }, // I - Umlauts - Uppercase
{ '\xD1', '\xF1' }, // N - Tilde - Uppercase
{ '\xD2', '\xF2' }, // O - Grave - Uppercase
{ '\xD3', '\xF3' }, // O - Acute - Uppercase
{ '\xD4', '\xF4' }, // O - Circumflex - Uppercase
{ '\xD5', '\xF5' }, // O - Tilde - Uppercase
{ '\xD6', '\xF6' }, // O - Umlauts - Uppercase
{ '\xD8', '\xF8' }, // O - Stroke - Uppercase
{ '\xD9', '\xF9' }, // U - Grave - Uppercase
{ '\xDA', '\xFA' }, // U - Acute - Uppercase
{ '\xDB', '\xFB' }, // U - Circumflex - Uppercase
{ '\xDC', '\xFC' }, // U - Umlauts - Uppercase
{ '\xDD', '\xFD' }, // Y - Acute - Uppercase
{ '\x9F', '\xFF' }, // Y - Umlauts - Uppercase
{ '\xDE', '\xFE' } // ? - Thorn - Uppercase
};
short font_size = sizeof(font)/sizeof(*font);
// Convert text to lowercase
int(*pf)(int)=tolower;
transform(text.begin(), text.end(), text.begin(), pf);
// Convert additional accented characters to lowercase
for(short i = 0; i < font_size; ++i)
replace(text.begin(), text.end(), font[i][0], font[i][1]);
return;
}
// --- Strip ASCII text by converting carons and removing trailing 'TM' symbols. The lower_case bool enables conversion to lower case --- //
// ehm::StripText(string of text, true = convert to lowercase / false = leave the case as it is)
std::string ehm::StripText(std::string &text, const bool &lower_case)
{
// Don't process the string if it is empty
if(text.empty())
return text;
// Before proceeding, check for and remove any text qualifiers. Some software encloses text within speech marks or apostrophes in csv files
if((text[0] == '\"' && text[text.length()-1] == '\"') || (text[0] == '\'' && text[text.length()-1] == '\''))
{
text.erase(text.begin());
text.erase(text.length()-1);
}
// Multidimensional array of strip characters ([i][0]) and replace characters ([i][1])
const int font[][2] =
{
{ '\x8A', '\x53' }, // S - Caron - Uppercase
{ '\x9A', '\x73' }, // s - Caron - Lowercase
{ '\x8E', '\x5A' }, // Z - Caron - Uppercase
{ '\x9E', '\x7A' } // z - Caron - Lowercase
};
short font_size = sizeof(font)/sizeof(*font);
// Check for bad characters
for(short i = 0; i < font_size; ++i)
replace(text.begin(), text.end(), font[i][0], font[i][1]);
// Remove trademark symbol if present at the end of the string
if(text[text.length()-1] == '\x99')
text.erase(text.length()-1);
// Convert the text to lower case
if(lower_case == true)
ehm::LowerCase(text);
// If the text string consists of solely a space then erase it. Single space strings are likely to be an artefact from text qualified cells that were subsequently blanked in the spreadsheet software.
if(text == " ")
text.clear();
return text;
}
5. You will need to add an example EHM database (such as one of the Manimal DBs) to your project folder. If you go to the My Documents -> Projects in Windows, you'll find a sub-folder with the same name as your project. Go into this folder and you'll see a further sub-folder with the same name as your project. Go into this folder and put your database dat files. For example, I called the project "EHM 2007 Examples" and so I placed the Manimal v5.3d database here:
6. Complile your code by pressing F5.