mirror of
https://github.com/alliedmodders/metamod-source.git
synced 2025-02-20 13:54:14 +01:00
new shworker. i am pm
--HG-- extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40196
This commit is contained in:
parent
233b4cbf15
commit
0b0a1c7627
@ -330,7 +330,7 @@ void PrintVarArgs(FILE *fout, CString bigblock, int num) {
|
||||
fprintf(fout, bigblock);
|
||||
}
|
||||
|
||||
int hopter(int numargs, const char *filenamein, const char *filenameout)
|
||||
int action_hopter(int numargs, const char *filenamein, const char *filenameout)
|
||||
{
|
||||
|
||||
MaxNumArgs = numargs;
|
||||
|
@ -2,30 +2,99 @@
|
||||
// Inspired by "Hopter" that comes with FastDelegate (http://www.codeproject.com/cpp/FastDelegate.asp)
|
||||
// Much more powerful (and ugly) though
|
||||
|
||||
// Action: iter
|
||||
// @VARARGS@ begins session
|
||||
// @..@ is replaced by .. if num!=0 and removed if num=0. Any
|
||||
// occurences of %% are replaced by the current iter
|
||||
// @$@ is replaced by the current iter
|
||||
// @ENDARGS@ ends session
|
||||
/*
|
||||
|
||||
INPUT FILE DIRECTIVES
|
||||
|
||||
$a is the first additional argument, %b the second, ...
|
||||
|
||||
---
|
||||
ITERATION
|
||||
|
||||
@[variable,min,max:code|separator@]
|
||||
|
||||
variable: this will be replaced in code by its current value.
|
||||
vars are always $ and a number.
|
||||
min: first value to be used for variable
|
||||
max: last value to be used for variable
|
||||
code: the code that will be inserted on each iteration.
|
||||
separator: optional. this will be inserted between iterations.
|
||||
If you don't use a separator, you may leave out the |
|
||||
IMPORTANT: iterations will only be performed if max >= min
|
||||
|
||||
--- ARITHMETIC EXPRESSION
|
||||
|
||||
@(expr)
|
||||
|
||||
expr may contain:
|
||||
variables
|
||||
constants
|
||||
operators (currently only + and * are supported)
|
||||
|
||||
--- CONDITION
|
||||
|
||||
@[expr operator expr:code@]
|
||||
|
||||
Example: @[$1!=0:hello@]
|
||||
|
||||
Currently only != and == are supported operators.
|
||||
|
||||
|
||||
Yes, error handling in here is weird, some stuff uses return values, other code uses exceptions.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <stack>
|
||||
#include <map>
|
||||
#include "stdio.h"
|
||||
|
||||
#ifdef __linux__
|
||||
# define stricmp strcasecmp
|
||||
#endif
|
||||
|
||||
// Ensure that the template version is being used!
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
extern int hopter(int numargs, const char *filenamein, const char *filenameout);
|
||||
extern int action_hopter(int numargs, const char *filenamein, const char *filenameout);
|
||||
|
||||
typedef map<int,int> varmap;
|
||||
|
||||
void TrimString(std::string &str)
|
||||
struct MyError
|
||||
{
|
||||
const char *m_desc;
|
||||
|
||||
MyError(const char *desc) : m_desc(desc)
|
||||
{
|
||||
}
|
||||
|
||||
void Print()
|
||||
{
|
||||
cout << m_desc << endl;
|
||||
}
|
||||
};
|
||||
|
||||
struct SyntaxError : MyError
|
||||
{
|
||||
SyntaxError() : MyError("Syntax error in expression")
|
||||
{
|
||||
}
|
||||
};
|
||||
struct OtherError : MyError
|
||||
{
|
||||
OtherError() : MyError("WTF")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void trim_string(std::string &str)
|
||||
{
|
||||
size_t first = str.find_first_not_of(" \t\v\n\r");
|
||||
if (first == std::string::npos)
|
||||
@ -49,9 +118,10 @@ void TrimString(std::string &str)
|
||||
str = str.substr(first, last - first);
|
||||
}
|
||||
|
||||
// unused
|
||||
bool ExtractToken(std::string &strin, std::string &strout)
|
||||
{
|
||||
TrimString(strin);
|
||||
trim_string(strin);
|
||||
if (strin.begin() == strin.end())
|
||||
{
|
||||
strout.clear();
|
||||
@ -94,28 +164,540 @@ int DoReplace(string &str, const string &what, const string &with)
|
||||
return cnt;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int DoReplace(string &str, const char *what, const char *with)
|
||||
{
|
||||
if (argc < 5)
|
||||
int cnt=0;
|
||||
size_t where = str.find(what);
|
||||
size_t whatsize = strlen(what);
|
||||
while (where != string::npos)
|
||||
{
|
||||
cout << "Usage:" << endl << " shworker [iter/hopter] ..." << endl;
|
||||
cout << " shworker iter [num-of-args] filename.in filename.out" << endl;
|
||||
cout << " shworker hopter [num-of-args] filename.in filename.our" << endl;
|
||||
return 1;
|
||||
str.replace(where, whatsize, with);
|
||||
++cnt;
|
||||
where = str.find(what, where);
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
|
||||
class ExprParser
|
||||
{
|
||||
// grammar:
|
||||
/*
|
||||
expr -> expr + term { do_add }
|
||||
| expr - term { do_sub }
|
||||
| term
|
||||
|
||||
term -> term * factor { do_mul }
|
||||
| term / factor { do_div }
|
||||
| term % factor { do_mod }
|
||||
|
||||
factor -> (expr)
|
||||
| numeric constant { push }
|
||||
|
||||
|
||||
equivalent to:
|
||||
|
||||
expr -> term moreterms
|
||||
moreterms -> + term { do_add } moreterms
|
||||
moreterms -> - term { do_sub } moreterms
|
||||
moreterms -> epsilon
|
||||
|
||||
term -> factor morefactors
|
||||
morefactors -> * factor { do_mul } morefactors
|
||||
morefactors -> / factor { do_div } morefactors
|
||||
morefactors -> % factor { do_mod } morefactors
|
||||
morefactors -> epsilon
|
||||
|
||||
factor -> (expr)
|
||||
factor -> numeric constant { push }
|
||||
|
||||
*/
|
||||
|
||||
string::const_iterator m_begin;
|
||||
string::const_iterator m_end;
|
||||
string::const_iterator m_iter;
|
||||
|
||||
int m_lookahead;
|
||||
int m_tokenval;
|
||||
|
||||
stack<int> m_stack;
|
||||
static const int DONE = 256;
|
||||
static const int NUM = 257;
|
||||
|
||||
int lexan()
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
if (m_iter == m_end)
|
||||
return DONE;
|
||||
|
||||
int t = *m_iter++;
|
||||
|
||||
if (t == ' ' || t == '\t')
|
||||
; // Remove whitespace
|
||||
else if (isdigit(t))
|
||||
{
|
||||
--m_iter;
|
||||
|
||||
m_tokenval = 0;
|
||||
while (m_iter != m_end && isdigit(*m_iter))
|
||||
{
|
||||
m_tokenval *= 10;
|
||||
m_tokenval += *m_iter - '0';
|
||||
++m_iter;
|
||||
}
|
||||
return NUM;
|
||||
}
|
||||
else
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
const char *action = argv[1];
|
||||
int argsnum = atoi(argv[2]);
|
||||
const char *filenamein = argv[3];
|
||||
const char *filenameout = argv[4];
|
||||
|
||||
if (stricmp(action, "hopter") == 0)
|
||||
void match(int t)
|
||||
{
|
||||
return hopter(argsnum, filenamein, filenameout);
|
||||
if (m_lookahead == t)
|
||||
m_lookahead = lexan();
|
||||
else
|
||||
throw SyntaxError();
|
||||
}
|
||||
void factor()
|
||||
{
|
||||
switch (m_lookahead)
|
||||
{
|
||||
case '(':
|
||||
match('('); expr(); match(')');
|
||||
break;
|
||||
case NUM:
|
||||
m_stack.push(m_tokenval); match(NUM);
|
||||
break;
|
||||
default:
|
||||
throw SyntaxError();
|
||||
}
|
||||
}
|
||||
void term()
|
||||
{
|
||||
factor();
|
||||
while (1)
|
||||
{
|
||||
switch (m_lookahead)
|
||||
{
|
||||
case '*':
|
||||
match('*'); factor(); do_mul();
|
||||
continue;
|
||||
case '/':
|
||||
match('/'); factor(); do_div();
|
||||
continue;
|
||||
case '%':
|
||||
match('%'); factor(); do_mod();
|
||||
continue;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void expr()
|
||||
{
|
||||
term();
|
||||
while (1)
|
||||
{
|
||||
switch (m_lookahead)
|
||||
{
|
||||
case '+':
|
||||
match('+'); term(); do_add();
|
||||
continue;
|
||||
case '-':
|
||||
match('-'); term(); do_sub();
|
||||
continue;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void do_add()
|
||||
{
|
||||
int a2 = m_stack.top(); m_stack.pop();
|
||||
int a1 = m_stack.top(); m_stack.pop();
|
||||
m_stack.push(a1 + a2);
|
||||
}
|
||||
|
||||
void do_sub()
|
||||
{
|
||||
int a2 = m_stack.top(); m_stack.pop();
|
||||
int a1 = m_stack.top(); m_stack.pop();
|
||||
m_stack.push(a1 - a2);
|
||||
}
|
||||
|
||||
void do_mul()
|
||||
{
|
||||
int a2 = m_stack.top(); m_stack.pop();
|
||||
int a1 = m_stack.top(); m_stack.pop();
|
||||
m_stack.push(a1 * a2);
|
||||
}
|
||||
|
||||
void do_div()
|
||||
{
|
||||
int a2 = m_stack.top(); m_stack.pop();
|
||||
int a1 = m_stack.top(); m_stack.pop();
|
||||
m_stack.push(a1 / a2);
|
||||
}
|
||||
|
||||
void do_mod()
|
||||
{
|
||||
int a2 = m_stack.top(); m_stack.pop();
|
||||
int a1 = m_stack.top(); m_stack.pop();
|
||||
m_stack.push(a1 % a2);
|
||||
}
|
||||
|
||||
public:
|
||||
ExprParser(string::const_iterator begin, string::const_iterator end) :
|
||||
m_begin(begin), m_end(end), m_iter(begin)
|
||||
{
|
||||
m_lookahead = lexan();
|
||||
expr();
|
||||
}
|
||||
|
||||
operator int()
|
||||
{
|
||||
if (m_stack.size() != 1)
|
||||
throw OtherError();
|
||||
|
||||
return m_stack.top();
|
||||
}
|
||||
};
|
||||
|
||||
int parse_expr(string::const_iterator begin, string::const_iterator end)
|
||||
{
|
||||
return ExprParser(begin, end);
|
||||
}
|
||||
|
||||
size_t find_first_directive(const string &buf, size_t begin=0)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (begin >= buf.size())
|
||||
return string::npos;
|
||||
|
||||
size_t firstdirpos = buf.find('@', begin);
|
||||
if (firstdirpos == string::npos)
|
||||
return firstdirpos;
|
||||
|
||||
if (buf.size() > firstdirpos+1)
|
||||
{
|
||||
if (buf[firstdirpos+1] == '[' || buf[firstdirpos+1] == '(')
|
||||
return firstdirpos;
|
||||
}
|
||||
begin = firstdirpos+1;
|
||||
}
|
||||
}
|
||||
|
||||
// buf begins with a section. Find its end!
|
||||
size_t find_section_end(const string &buf)
|
||||
{
|
||||
int starttype = buf[1];
|
||||
int endtype = (buf[1] == '(') ? ')' : ']';
|
||||
|
||||
int nestlevel = 0;
|
||||
|
||||
if (starttype == '(')
|
||||
{
|
||||
for (string::const_iterator iter = buf.begin(); iter != buf.end(); ++iter)
|
||||
{
|
||||
if (*iter == starttype)
|
||||
++nestlevel;
|
||||
if (*iter == endtype)
|
||||
{
|
||||
if (--nestlevel == 0)
|
||||
return iter - buf.begin() + 1;
|
||||
}
|
||||
}
|
||||
return string::npos;
|
||||
}
|
||||
else if (starttype == '[')
|
||||
{
|
||||
int lastchar = 0;
|
||||
for (string::const_iterator iter = buf.begin(); iter != buf.end(); ++iter)
|
||||
{
|
||||
if (lastchar == '@' && *iter == starttype)
|
||||
++nestlevel;
|
||||
if (lastchar == '@' && *iter == endtype)
|
||||
{
|
||||
if (--nestlevel == 0)
|
||||
return iter - buf.begin() + 1;
|
||||
}
|
||||
lastchar = *iter;
|
||||
}
|
||||
return string::npos;
|
||||
}
|
||||
|
||||
return string::npos;
|
||||
}
|
||||
|
||||
// replaces variables and additional arguments
|
||||
void replace_vars(string &buf, int argc, int *argv, const varmap &vars)
|
||||
{
|
||||
char varname[] = "$ ";
|
||||
char value[32];
|
||||
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
varname[1] = 'a' + i;
|
||||
itoa(argv[i], value, 10);
|
||||
DoReplace(buf, varname, value);
|
||||
}
|
||||
|
||||
for (varmap::const_iterator iter = vars.begin(); iter != vars.end(); ++iter)
|
||||
{
|
||||
varname[1] = '0' + iter->first;
|
||||
itoa(iter->second, value, 10);
|
||||
DoReplace(buf, varname, value);
|
||||
}
|
||||
}
|
||||
|
||||
// do_input
|
||||
// params:
|
||||
// argc: number of additional arguments
|
||||
// argv: additional arguments
|
||||
// outfile: output file
|
||||
// buf: string to be processed. IMPORTANT: buf is modified!
|
||||
// curvars: variables buffer.
|
||||
// retval:
|
||||
// 0 on success, non-zero on error
|
||||
|
||||
int do_input(int argc, int *argv, ofstream &outfile, string &buf, varmap &curvars)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
// Find the next directive.
|
||||
size_t firstdirpos = find_first_directive(buf);
|
||||
|
||||
// Output everything that came before, and remove it from buf
|
||||
outfile << buf.substr(0, firstdirpos);
|
||||
if (firstdirpos == string::npos)
|
||||
return 0;
|
||||
buf = buf.substr(firstdirpos);
|
||||
|
||||
// Now find the matching end.
|
||||
size_t sectionend = find_section_end(buf);
|
||||
if (sectionend == string::npos)
|
||||
{
|
||||
cout << "ERROR: Section not closed!" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Place the section in its own buffer and remove it from the input string.
|
||||
string sect(buf.begin(), buf.begin() + sectionend);
|
||||
buf = buf.substr(sectionend);
|
||||
|
||||
// CASE1: Arithmetic expression
|
||||
if (sect[1] == '(')
|
||||
{
|
||||
replace_vars(sect, argc, argv, curvars);
|
||||
outfile << parse_expr(sect.begin()+1, sect.end());
|
||||
}
|
||||
else if (sect[1] == '[')
|
||||
{
|
||||
int is_iter = 0; // 0 -> no; 1 -> maybe (only used in check); 2 -> yes
|
||||
char lastchar = 0;
|
||||
// This could be an iteration OR a conditional thing.
|
||||
// Pretty braindead check: iterations begin with a variable, then a comma.
|
||||
for (string::iterator iter = sect.begin() + 2; iter != sect.end(); ++iter)
|
||||
{
|
||||
if (*iter == ' ' || *iter == '\t')
|
||||
;
|
||||
else if (is_iter == 0 && lastchar == '$' && isdigit(*iter))
|
||||
is_iter = 1;
|
||||
else if (is_iter == 1 && *iter == ',')
|
||||
{
|
||||
is_iter = 2;
|
||||
break;
|
||||
}
|
||||
else if (*iter == '$')
|
||||
;
|
||||
else
|
||||
break;
|
||||
lastchar = *iter;
|
||||
}
|
||||
if (is_iter == 2)
|
||||
{
|
||||
// CASE2: iteration
|
||||
// Looks like: @[var,min,max:code|sep@]
|
||||
// Replace known variables / additional arguments
|
||||
replace_vars(sect, argc, argv, curvars);
|
||||
|
||||
// get the parts!
|
||||
string varname;
|
||||
int varnum;
|
||||
int expr_min;
|
||||
int expr_max;
|
||||
|
||||
// varname
|
||||
size_t comma = sect.find(',');
|
||||
if (comma == string::npos)
|
||||
{
|
||||
cout << "Invalid iteration syntax" << endl;
|
||||
return 1;
|
||||
}
|
||||
varname.assign(sect.begin() + 2, sect.begin() + comma);
|
||||
trim_string(varname);
|
||||
if (varname.size() != 2 || varname[0] != '$' || !isdigit(varname[1]))
|
||||
{
|
||||
cout << "Invalid variable name" << endl;
|
||||
return 1;
|
||||
}
|
||||
varnum = varname[1] - '0';
|
||||
|
||||
// min
|
||||
++comma;
|
||||
size_t nextcomma = sect.find(',', comma);
|
||||
if (nextcomma == string::npos)
|
||||
{
|
||||
cout << "Invalid iteration syntax" << endl;
|
||||
return 1;
|
||||
}
|
||||
expr_min = parse_expr(sect.begin() + comma, sect.begin() + nextcomma);
|
||||
|
||||
// max
|
||||
comma = nextcomma + 1;
|
||||
nextcomma = sect.find(':', comma);
|
||||
if (nextcomma == string::npos)
|
||||
{
|
||||
cout << "Invalid iteration syntax" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
expr_max = parse_expr(sect.begin() + comma, sect.begin() + nextcomma);
|
||||
|
||||
// separator
|
||||
size_t sepbegin = sect.find('|');
|
||||
size_t sepend = string::npos;
|
||||
if (sepbegin != string::npos && sepbegin < nextcomma)
|
||||
{
|
||||
// There's a separator!
|
||||
++sepbegin;
|
||||
sepend = nextcomma;
|
||||
}
|
||||
else
|
||||
sepbegin = string::npos;
|
||||
|
||||
|
||||
++nextcomma; // nextcomma is now where code begins!
|
||||
|
||||
size_t codeend = sect.size() - 2;
|
||||
|
||||
// Check whether the var is already taken
|
||||
if (curvars.find(varnum) != curvars.end())
|
||||
{
|
||||
cout << "Variable $" << varnum << "already taken!" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Do iterations!!
|
||||
for (int i = expr_min; i <= expr_max; ++i)
|
||||
{
|
||||
curvars[varnum] = i;
|
||||
|
||||
string code(sect.begin() + nextcomma, sect.begin() + codeend);
|
||||
replace_vars(code, argc, argv, curvars);
|
||||
|
||||
// Feed it through the input routine (RECURSE!!!!!! YEAH!)
|
||||
do_input(argc, argv, outfile, code, curvars);
|
||||
|
||||
// Add separator if required
|
||||
if (sepbegin != string::npos && i != expr_max)
|
||||
{
|
||||
do_input(argc, argv, outfile,
|
||||
string(sect.begin() + sepbegin, sect.begin() + sepend), curvars);
|
||||
}
|
||||
}
|
||||
// Remove the var!
|
||||
curvars.erase(varnum);
|
||||
}
|
||||
else
|
||||
{
|
||||
// CASE3: conditional thing.
|
||||
// Looks like: @[expr1 operator expr2:code@]
|
||||
|
||||
// Find the operator position
|
||||
|
||||
enum OP_TYPE
|
||||
{
|
||||
OP_EQ,
|
||||
OP_NEQ
|
||||
};
|
||||
|
||||
OP_TYPE op;
|
||||
size_t oppos = sect.find("==");
|
||||
if (oppos != string::npos)
|
||||
op = OP_EQ;
|
||||
else
|
||||
{
|
||||
oppos = sect.find("!=");
|
||||
if (oppos != string::npos)
|
||||
op = OP_NEQ;
|
||||
else
|
||||
{
|
||||
cout << "Conditional expression without operator!?" << endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
size_t colon = sect.find(':');
|
||||
|
||||
// Now we've got everything. Parse first expr:
|
||||
int expr1 = parse_expr(sect.begin() + 2, sect.begin() + oppos);
|
||||
int expr2 = parse_expr(sect.begin() + oppos + 2, sect.begin() + colon);
|
||||
if ((op == OP_EQ && expr1 == expr2) ||
|
||||
(op == OP_NEQ && expr1 != expr2))
|
||||
{
|
||||
// Condition is true, process it!
|
||||
// The text may still contain arithmetic exprs or other cond. exprs
|
||||
// so send it through do_input
|
||||
do_input(argc, argv, outfile, sect.substr(colon+1, sect.size() - colon - 3), curvars);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "WTF" << endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// action_iter
|
||||
// params:
|
||||
// filenamein: input file name
|
||||
// filenameout: output file name
|
||||
// argc: number of additional arguments
|
||||
// argv: additional arguments
|
||||
// retval: 0 on success, non-zero on error
|
||||
|
||||
// Convert additional arguments
|
||||
// Read whole input file to memory and open output file
|
||||
// Pass to do_input()
|
||||
int action_iter(const char *filenamein, const char *filenameout, int argc, const char *argv[])
|
||||
{
|
||||
// Convert additional arguments
|
||||
const int MAX_ARGC = 10;
|
||||
int converted_argv[MAX_ARGC];
|
||||
|
||||
for (int i = 0; i < argc && i < MAX_ARGC; ++i)
|
||||
converted_argv[i] = atoi(argv[i]);
|
||||
|
||||
if (argc != i)
|
||||
cout << "WARNING: Not all additional arguments processed!" << endl;
|
||||
|
||||
|
||||
// Read whole input file to memory and open output file
|
||||
ifstream fin(filenamein);
|
||||
ofstream fout(filenameout);
|
||||
|
||||
if (!fin)
|
||||
{
|
||||
cout << "Could not open file \"" << filenamein << "\"." << endl;
|
||||
@ -126,122 +708,58 @@ int main(int argc, char *argv[])
|
||||
cout << "Could not open file \"" << filenameout << "\"." << endl;
|
||||
return 1;
|
||||
}
|
||||
string input_str(
|
||||
istreambuf_iterator<char> (fin.rdbuf()),
|
||||
istreambuf_iterator<char> ());
|
||||
|
||||
if (stricmp(action, "iter") == 0)
|
||||
|
||||
// Begin processing input
|
||||
varmap vars;
|
||||
try
|
||||
{
|
||||
// Generate versions of func macros for many parameters
|
||||
string str;
|
||||
string replacebuf;
|
||||
while (!fin.eof())
|
||||
{
|
||||
getline(fin, str);
|
||||
if (str == "@VARARGS@")
|
||||
{
|
||||
replacebuf.clear();
|
||||
|
||||
while (true)
|
||||
{
|
||||
getline(fin, str);
|
||||
if (str == "@ENDARGS@")
|
||||
break;
|
||||
|
||||
replacebuf += str;
|
||||
replacebuf += "\n";
|
||||
if (fin.eof())
|
||||
{
|
||||
cout << "No matching @ENDARGS@ !" << endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i <= argsnum; ++i)
|
||||
{
|
||||
string cur = replacebuf;
|
||||
size_t where = cur.find('@');
|
||||
|
||||
while (where != string::npos)
|
||||
{
|
||||
size_t where2 = cur.find('@', where+1);
|
||||
if (where2 == string::npos)
|
||||
{
|
||||
cout << "No ending @";
|
||||
return 1;
|
||||
}
|
||||
string tmp = cur.substr(where + 1, where2 - where - 1);
|
||||
cur.erase(where, where2 - where + 1);
|
||||
|
||||
if (tmp.size() != 0 && tmp[0] == '$')
|
||||
{
|
||||
int tmp_out = i;
|
||||
if (tmp.size() > 2)
|
||||
{
|
||||
if (tmp[1] == '+')
|
||||
{
|
||||
istringstream istr(tmp.substr(2));
|
||||
int tmp;
|
||||
istr >> tmp;
|
||||
tmp_out += tmp;
|
||||
}
|
||||
else if (tmp[1] == '*')
|
||||
{
|
||||
istringstream istr(tmp.substr(2));
|
||||
int tmp;
|
||||
istr >> tmp;
|
||||
tmp_out *= tmp;
|
||||
}
|
||||
}
|
||||
stringstream istr;
|
||||
istr << tmp_out;
|
||||
cur.insert(where, istr.str());
|
||||
where = cur.find('@', where);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the |.. part, if any
|
||||
string tmpsep;
|
||||
size_t tmpsepbegin = tmp.rfind('|');
|
||||
if (tmpsepbegin != string::npos)
|
||||
{
|
||||
tmpsep = tmp.substr(tmpsepbegin + 1);
|
||||
tmp.erase(tmpsepbegin);
|
||||
}
|
||||
|
||||
size_t pos = where;
|
||||
if (tmp.find("%%") == string::npos)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
cur.insert(pos, tmp);
|
||||
pos += tmp.size();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 1; j <= i; ++j)
|
||||
{
|
||||
stringstream istr;
|
||||
istr << j;
|
||||
string what = tmp;
|
||||
DoReplace(what, string("%%"), istr.str());
|
||||
cur.insert(pos, what);
|
||||
pos += what.size();
|
||||
if (j != i)
|
||||
{
|
||||
cur.insert(pos, tmpsep);
|
||||
pos += tmpsep.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
where = cur.find('@', where);
|
||||
}
|
||||
fout << cur;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fout << str << endl;
|
||||
}
|
||||
}
|
||||
return do_input(argc, converted_argv, fout, input_str, vars);
|
||||
}
|
||||
catch (MyError err)
|
||||
{
|
||||
err.Print();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// MAIN
|
||||
// Prints usage if required
|
||||
// Calls action_hopter OR action_iter
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
if (argc < 4)
|
||||
{
|
||||
cout << "Usage:" << endl << " shworker [iter/hopter] ..." << endl;
|
||||
cout << " shworker iter filename.in filename.out [param1, param2, ...]" << endl;
|
||||
cout << " shworker hopter filename.in filename.out [num-of-args]" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *action = argv[1];
|
||||
|
||||
if (stricmp(action, "hopter") == 0)
|
||||
{
|
||||
const char *filenamein = argv[2];
|
||||
const char *filenameout = argv[3];
|
||||
int argsnum = atoi(argv[4]);
|
||||
|
||||
return action_hopter(argsnum, filenamein, filenameout);
|
||||
}
|
||||
else if (stricmp(action, "iter") == 0)
|
||||
{
|
||||
const char *filenamein = argv[2];
|
||||
const char *filenameout = argv[3];
|
||||
int additional_argc = argc - 4;
|
||||
const char ** additional_argv = argv + 4;
|
||||
return action_iter(filenamein, filenameout, additional_argc, additional_argv);
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Unrecognized action: " << argv[1] << endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding = "Windows-1252"?>
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.00"
|
||||
Version="7.10"
|
||||
Name="shworker"
|
||||
ProjectGUID="{7CD76E64-A9DF-47DB-8A68-36297C67E557}"
|
||||
Keyword="Win32Proj">
|
||||
@ -49,8 +49,14 @@
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
@ -94,10 +100,18 @@
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
@ -106,7 +120,7 @@
|
||||
RelativePath="fd_hopter.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="main.cpp">
|
||||
RelativePath=".\shworker.cpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
|
Loading…
x
Reference in New Issue
Block a user