You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
205 lines
4.4 KiB
205 lines
4.4 KiB
/*
|
|
This program merges binplace placefiles.
|
|
It reads in the files named on the command line, and
|
|
writes out a merged placefile to stdout.
|
|
*/
|
|
|
|
#include "yvals.h"
|
|
#pragma warning(disable:4100)
|
|
#pragma warning(disable:4663)
|
|
#pragma warning(disable:4511)
|
|
#pragma warning(disable:4512)
|
|
#pragma warning(disable:4127)
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <string>
|
|
#include <map>
|
|
#include <string.h>
|
|
#include <set>
|
|
#include "strtok_r.h"
|
|
#include "windows.h"
|
|
|
|
const char comment_char = ';';
|
|
const char comment_chars[] = { comment_char , 0 };
|
|
const char horizontal_whitespace_chars[] = { ' ', '\t', 0 };
|
|
const char destination_delim = ':';
|
|
const char destination_delims[] = { destination_delim, 0 };
|
|
|
|
class String_t : public std::string
|
|
{
|
|
typedef std::string Base;
|
|
public:
|
|
String_t(const std::string & s) : Base(s) { }
|
|
String_t() { }
|
|
~String_t() { }
|
|
String_t(const String_t & s) : Base(s) { }
|
|
String_t(const char * s) : Base(s) { }
|
|
|
|
bool operator<( const String_t & s) const
|
|
{
|
|
return _stricmp(c_str(), s.c_str()) < 0;
|
|
}
|
|
|
|
bool operator==( const String_t & s) const
|
|
{
|
|
return _stricmp(c_str(), s.c_str()) == 0;
|
|
}
|
|
};
|
|
|
|
class File_t : public std::map<String_t, std::set<String_t> >
|
|
{
|
|
public:
|
|
void Read( const char * filename );
|
|
};
|
|
|
|
class CMutableString
|
|
{
|
|
public:
|
|
CMutableString() { }
|
|
|
|
CMutableString(const char * s)
|
|
{
|
|
size_t len = strlen(s);
|
|
this->chars.resize(len + 1);
|
|
strcpy(&this->chars[0], s);
|
|
}
|
|
|
|
size_t length() const { return ::strlen(&chars[0]); }
|
|
|
|
void operator=(const CMutableString & t)
|
|
{
|
|
if (&t == this)
|
|
return;
|
|
this->chars = t.chars;
|
|
}
|
|
|
|
void operator=(const char * s)
|
|
{
|
|
//
|
|
// s may point into chars, and resize may realloc, so use a temp
|
|
//
|
|
CMutableString temp(s);
|
|
std::swap(this->chars, temp.chars);
|
|
}
|
|
|
|
operator char * () { return &chars[0]; }
|
|
|
|
std::vector<char> chars;
|
|
};
|
|
|
|
class CStringTokenizer
|
|
{
|
|
public:
|
|
CStringTokenizer() : state(0) { }
|
|
~CStringTokenizer() { }
|
|
|
|
char * operator()(char * string, const char * delims)
|
|
{
|
|
return strtok_r(string, delims, &state);
|
|
}
|
|
|
|
char * state;
|
|
};
|
|
|
|
void TrimHorizontalWhitespaceFromEnds(char * & s)
|
|
{
|
|
s += strspn(s, horizontal_whitespace_chars);
|
|
char * q = s + strlen(s);
|
|
while (q != s && strchr(horizontal_whitespace_chars, *q) != NULL)
|
|
{
|
|
*q = 0;
|
|
q -= 1;
|
|
}
|
|
}
|
|
void File_t::Read(const char * filename)
|
|
{
|
|
String_t line;
|
|
std::ifstream file;
|
|
CMutableString mutable_line;
|
|
char * p = 0;
|
|
|
|
file.open(filename, std::ios_base::in);
|
|
while (std::getline(file, line))
|
|
{
|
|
mutable_line = line.c_str();
|
|
p = mutable_line;
|
|
p += strspn(p, horizontal_whitespace_chars);
|
|
if (p[0] == 0)
|
|
continue;
|
|
if (strchr(comment_chars, p[0]) != NULL)
|
|
continue;
|
|
char * comment = strchr(p, comment_char);
|
|
if (comment != NULL)
|
|
*comment = 0;
|
|
mutable_line = p;
|
|
p = mutable_line;
|
|
|
|
const char * image_name = p;
|
|
p += strcspn(p, horizontal_whitespace_chars);
|
|
*p = 0;
|
|
const String_t image_name_string = image_name;
|
|
p += 1;
|
|
p += strspn(p, horizontal_whitespace_chars);
|
|
char * destinations = p;
|
|
|
|
TrimHorizontalWhitespaceFromEnds(destinations);
|
|
|
|
CStringTokenizer tokenize;
|
|
for ( char * destination = tokenize(destinations, destination_delims) ;
|
|
destination != NULL ;
|
|
destination = tokenize(NULL, destination_delims)
|
|
)
|
|
{
|
|
(*this)[image_name_string].insert(destination);
|
|
//printf("%s -> %s\n", image_name, destination);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MergePlacefiles(int nfiles, char ** filenames)
|
|
{
|
|
File_t accum;
|
|
if (nfiles == 0)
|
|
return;
|
|
for ( int i = 0 ; i < nfiles - 1; ++i )
|
|
{
|
|
accum.Read(filenames[i]);
|
|
}
|
|
DeleteFileA(filenames[nfiles - 1]);
|
|
FILE * fout = fopen(filenames[nfiles - 1], "w");
|
|
if (fout == NULL)
|
|
{
|
|
fprintf(stderr, "Error fopen(%s)\n", filenames[nfiles - 1]);
|
|
exit(-1);
|
|
}
|
|
for (
|
|
File_t::const_iterator it = accum.begin();
|
|
it != accum.end();
|
|
++it
|
|
)
|
|
{
|
|
fprintf(fout, "%s ", it->first.c_str());
|
|
bool first = true;
|
|
for (
|
|
std::set<String_t>::const_iterator it2 = it->second.begin();
|
|
it2 != it->second.end();
|
|
++it2
|
|
)
|
|
{
|
|
if (!first)
|
|
fprintf(fout, ":");
|
|
fprintf(fout, "%s", it2->c_str());
|
|
first = false;
|
|
}
|
|
fprintf(fout, "\n");
|
|
}
|
|
fclose(fout);
|
|
}
|
|
|
|
int __cdecl main(int argc, char ** argv)
|
|
{
|
|
MergePlacefiles(argc - 1 , argv + 1);
|
|
return 0;
|
|
}
|