45 #define S_STREAM std::istrstream
48 #define S_STREAM std::istringstream
57 static char start_key_begin[] =
":START";
58 static char stop_key_begin[] =
":STOP";
59 static char start_key_end[] =
":";
60 static char stop_key_end[] =
":";
61 static char indent_space[] =
" ";
68 class EGS_LOCAL EGS_InputPrivate {
72 vector<EGS_InputPrivate *> children;
75 EGS_InputPrivate() : nref(0) {};
76 EGS_InputPrivate(
const string &Key,
const string &Val =
"") : key(Key),
77 value(Val), children(), nref(0) { };
78 EGS_InputPrivate(
const EGS_InputPrivate &p,
bool deep=
false) :
79 key(p.key), value(p.value), children(), nref(0) {
80 for (
unsigned int j=0; j<p.children.size(); j++) {
82 children.push_back(
new EGS_InputPrivate(*p.children[j],deep));
85 children.push_back(p.children[j]);
92 for (
unsigned int j=0; j<children.size(); j++) {
93 deleteItem(children[j]);
97 int replace(
const string &replace_what,
const string &replace_with);
99 int setContentFromFile(
const char *fname);
100 int setContentFromString(
string &input);
101 int setContent(istream &input);
103 int addContentFromFile(
const char *fname);
104 int addContentFromString(
string &input);
105 int addContent(istream &input);
106 string getCleanInputString(istream &input);
108 void processInputLoop(EGS_InputPrivate *p);
110 void addItem(EGS_InputPrivate *p) {
112 children.push_back(p);
115 EGS_InputPrivate *takeInputItem(
const string &key,
bool self=
true) {
116 if (
self && isA(key)) {
119 for (vector<EGS_InputPrivate *>::iterator it=children.begin();
120 it != children.end(); it++) {
121 if (compareKeys((*it)->key,key)) {
122 EGS_InputPrivate *res = *it;
134 EGS_InputPrivate *getInputItem(
const string &Key) {
138 for (
unsigned int j=0; j<children.size(); j++)
139 if (compareKeys(children[j]->key,Key)) {
145 bool isA(
const string &Key)
const {
146 return compareKeys(key,Key);
149 static void removeComment(
const string &start,
const string &end,
150 string &input,
bool newline);
152 static int findStart(
int start,
int stop,
153 const string &start_key,
const string &end_key,
154 const string &input,
string &what,
int &end);
155 static int findStop(
int start,
const string &start_string,
156 const string &end_string,
const string &input,
int &ie);
158 static bool compareKeys(
const string &s1,
const string &s2);
160 void print(
int nind, ostream &)
const;
162 void removeEmptyLines(
string &input);
164 static void deleteItem(EGS_InputPrivate *p) {
193 p =
new EGS_InputPrivate(name,value);
197 EGS_InputPrivate::deleteItem(p);
201 EGS_InputPrivate::deleteItem(p);
202 p =
new EGS_InputPrivate;
203 return p->setContentFromFile(fname);
207 EGS_InputPrivate::deleteItem(p);
208 p =
new EGS_InputPrivate;
209 return p->setContentFromString(input);
214 p =
new EGS_InputPrivate;
216 return p->addContentFromFile(fname);
221 p =
new EGS_InputPrivate;
223 return p->addContentFromString(input);
234 if (item == p && !
self) {
264 p =
new EGS_InputPrivate(*input.p);
275 return p->key.c_str();
285 template <
class T>
int EGS_LOCAL
286 get_input(
const EGS_InputPrivate *p,
const string &key, vector<T> &values) {
290 const EGS_InputPrivate *p1;
291 if (!p->children.size()) {
298 for (
unsigned int j=0; j<p->children.size(); j++) {
309 values.erase(values.begin(),values.end());
310 S_STREAM in(p1->value.c_str());
312 for (EGS_I64 loopCount=0; loopCount<=
loopMax; ++loopCount) {
314 egsFatal(
"EGS_InputPrivate::findStart: Too many iterations were required! Input may be invalid, or consider increasing loopMax.");
320 values.push_back(tmp);
323 if (values.size() <= 0) {
329 if (values.size() <= 0) {
339 return get_input(p,key,values);
343 return get_input(p,key,values);
347 return get_input(p,key,values);
350 template <
class T>
int EGS_LOCAL
351 get_input(
const EGS_InputPrivate *p,
const string &key, T &value) {
355 const EGS_InputPrivate *p1;
356 if (!p->children.size()) {
363 for (
unsigned int j=0; j<p->children.size(); j++) {
374 S_STREAM in(p1->value.c_str());
387 int err = getInput(key,v);
392 for (
unsigned int j=1; j<v.size(); j++) {
404 return get_input(p,key,value);
408 return get_input(p,key,value);
412 return get_input(p,key,value);
421 int err = getInput(key,aux);
425 if (aux.size() > 1) {
428 if (aux[0].size() < 10) {
432 err = getInput(key,n);
441 if (aux[0][0] ==
'+') {
444 else if (aux[0][0] ==
'-') {
448 EGS_I64 fac=1, res = 0;
449 for (
int j=aux[0].size()-1; j>=nfirst; j--) {
450 if (!isdigit(aux[0][j])) {
453 EGS_I64 c = aux[0][j]-48;
466 int def,
bool *found)
const {
468 int err = getInput(key,res);
470 for (
unsigned int j=0; j<allowed.size(); j++) {
471 if (EGS_InputPrivate::compareKeys(res,allowed[j])) {
486 int EGS_InputPrivate::setContentFromFile(
const char *fname) {
491 return setContent(in);
494 int EGS_InputPrivate::addContentFromFile(
const char *fname) {
498 const char *s = fname;
499 while (isspace(*s) && (*s)) {
506 return addContent(in);
509 int EGS_InputPrivate::setContentFromString(
string &input) {
510 S_STREAM in(input.c_str());
511 return setContent(in);
514 int EGS_InputPrivate::addContentFromString(
string &input) {
515 S_STREAM in(input.c_str());
516 return addContent(in);
519 void EGS_InputPrivate::removeComment(
const string &start,
const string &end,
520 string &input,
bool newline) {
521 string::size_type spos=0, epos=0;
522 while ((epos = input.find(end,spos)) < input.size()) {
523 spos = input.find(start,spos);
525 string::size_type len = epos - spos;
529 input.erase(spos,len);
540 int EGS_InputPrivate::setContent(istream &in) {
541 for (
unsigned int j=0; j<children.size(); j++) {
544 children.erase(children.begin(),children.end());
545 return addContent(in);
548 bool EGS_InputPrivate::compareKeys(
const string &s1,
const string &s2) {
551 for (j=0; j<s1.size(); j++)
552 if (!isspace(s1[j])) {
553 t1 += ::toupper(s1[j]);
555 for (j=0; j<s2.size(); j++)
556 if (!isspace(s2[j])) {
557 t2 += ::toupper(s2[j]);
567 int EGS_InputPrivate::replace(
const string &replace_what,
568 const string &replace_with) {
569 string::size_type pos = 0;
571 while ((pos = key.find(replace_what,pos)) < key.size()) {
572 key.replace(pos,replace_what.size(),replace_with);
576 while ((pos = value.find(replace_what,pos)) < value.size()) {
577 value.replace(pos,replace_what.size(),replace_with);
580 for (
int j=0; j<children.size(); j++) {
581 nr += children[j]->replace(replace_what,replace_with);
680 const char *getVarNameReplacement()
const {
683 const char *getVarReplacement()
const {
686 virtual void setVarReplacement(
int) = 0;
699 void setVarReplacement(
int i) {
700 int v = vmin + vdelta*i;
715 void setVarReplacement(
int i) {
716 double v = vmin + vdelta*i;
717 sprintf(buf,format.c_str(),v);
727 void setVarReplacement(
int i) {
728 string str = list[i];
729 sprintf(buf,
"%s",str.c_str());
744 if (in.fail() || !in.good()) {
745 egsWarning(
"Failed reading type and name from %s\n",input);
748 if (type < 0 || type > 2) {
749 egsFatal(
"Invalid loop type in input: %s\n"
750 "Only integer [0], float [1] and list [2] are valid types!\n",
756 in >> vmin >> vdelta;
759 else if (type == 1) {
761 in >> vmin >> vdelta;
764 if (format.empty()) {
772 else if (type == 2) {
778 vstr.push_back(s_tmp);
782 if (in.fail() && in.eof()) {
786 egsFatal(
"No list-items found reading loop-input: %s\n",input);
794 egsFatal(
"Fatal error reading loop input list from %s\n",input);
798 egsWarning(
"Failed reading vmin vdelta from %s\n",input);
806 void EGS_InputPrivate::processInputLoop(EGS_InputPrivate *p) {
808 EGS_InputPrivate *ic = p->takeInputItem(
"loop count");
810 egsWarning(
"processInputLoop: no 'loop count' input\n");
814 int err = get_input(ic,
"loop count",nloop);
816 if (err || nloop < 1) {
817 egsWarning(
"processInputLoop: got %d for loop count, expecting 1 or "
821 EGS_InputPrivate *iv;
822 vector<EGS_InputLoopVariable *> ivars;
823 while ((iv = p->takeInputItem(
"loop variable")) != 0) {
825 EGS_InputLoopVariable::getInputLoopVariable(iv->value.c_str());
828 egsFatal(
"procesInputLoop: loop size (%d) larger than list size (%d)!\n"
829 "This will cause a segmentation fault error, aborting ....\n",
833 if (!v)
egsWarning(
"processInputLoop: failed to create loop variable"
834 " based on the input %s\n",iv->value.c_str());
841 egsWarning(
"processInputLoop: no loop variables\n");
844 int nvar = ivars.size();
859 for (
int iloop=0; iloop<nloop; iloop++) {
860 for (j=0; j<p->children.size(); j++) {
861 EGS_InputPrivate *pnew =
new EGS_InputPrivate(*p->children[j],
true);
862 for (
int ivar=0; ivar<nvar; ivar++) {
863 ivars[ivar]->setVarReplacement(iloop);
864 pnew->replace(ivars[ivar]->getVarNameReplacement(),
865 ivars[ivar]->getVarReplacement());
867 children.push_back(pnew);
871 for (j=0; j<ivars.size(); j++) {
876 int EGS_InputPrivate::addContent(istream &in) {
877 string input = getCleanInputString(in);
882 string::size_type p1;
884 while ((p1=input.find(
'\n',p)) < input.size()) {
885 string::size_type p2 = input.find(
'=',p);
888 what.assign(input,p,p2-p);
889 if (compareKeys(what,
"includefile")) {
891 value.assign(input,p2+1,p1-p2-1);
894 const char *s = value.c_str();
895 while (isspace(*s) && (*s)) {
900 egsFatal(
"EGS_Input: failed to add content from "
901 "include file %s\n",value.c_str());
904 string input2 = getCleanInputString(in2);
906 input.erase(p, p1 - p);
907 input.insert(p, input2);
915 vector<string> start_keys, stop_keys;
916 int ep = input.size();
920 while ((p=findStart(p,ep,start_key_begin,start_key_end,input,what,ie))>=0) {
921 string the_start = start_key_begin;
922 string the_end = stop_key_begin;
923 for (
int j=0; j<what.size(); j++) {
924 char c = ::toupper(what[j]);
930 the_start += start_key_end;
931 the_end += stop_key_end;
933 int ep = findStop(ie+1,the_start,the_end,input,p1);
935 EGS_InputPrivate *ip =
new EGS_InputPrivate(what);
937 content.assign(input,ie+1,p1-ie-1);
939 ip->setContentFromString(content);
940 if (ip->isA(
"input loop")) {
941 processInputLoop(ip);
945 children.push_back(ip);
949 egsWarning(
"No matching stop delimiter for %s\n",what.c_str());
956 while ((p1=input.find(
'\n',p)) < input.size()) {
958 while (--j > p && isspace(input[j]));
960 if (input[j] ==
',' || input[j] ==
'\\') {
970 while ((p1=input.find(
'\n',p)) < input.size()) {
971 string::size_type p2 = input.find(
'=',p);
974 what.assign(input,p,p2-p);
976 value.assign(input,p2+1,p1-p2-1);
977 for (
int j=0; j<value.size(); j++) {
978 if (value[j] ==
',') {
983 EGS_InputPrivate *ip =
new EGS_InputPrivate(what,value);
984 children.push_back(ip);
997 string EGS_InputPrivate::getCleanInputString(istream &in) {
999 bool last_was_space =
false;
1000 for (EGS_I64 loopCount=0; loopCount<=
loopMax; ++loopCount) {
1002 egsFatal(
"EGS_InputPrivate::addContent: Too many iterations were required! Input may be invalid, or consider increasing loopMax.");
1006 if (in.eof() || !in.good()) {
1009 bool take_it =
true;
1011 if (last_was_space && c !=
'\n') {
1014 last_was_space =
true;
1017 last_was_space =
false;
1023 removeComment(
"#",
"\n",input,
true);
1024 removeComment(
"!",
"\n",input,
true);
1025 removeComment(
"//",
"\n",input,
true);
1026 removeComment(
"/*",
"*/",input,
false);
1027 removeEmptyLines(input);
1032 int EGS_InputPrivate::findStop(
int start,
const string &the_start,
1033 const string &the_end,
const string &input,
1036 int have_start=1, have_end=0;
1037 int end_started = start;
1038 for (
int j=start; j<input.size(); j++) {
1039 if (!isspace(input[j])) {
1040 char c = ::toupper(input[j]);
1041 if (the_start[ns] == c) {
1046 if (the_start[ns] == c) {
1050 if (ns == the_start.size()) {
1057 if (the_end[ne] == c) {
1062 if (the_end[ne] == c) {
1067 if (ne == the_end.size()) {
1070 if (have_end == have_start) {
1081 int EGS_InputPrivate::findStart(
int start,
int stop,
const string &start_key,
1082 const string &end_key,
const string &input,
1083 string &what,
int &end) {
1084 string::size_type pos = start;
1086 for (EGS_I64 loopCount=0; loopCount<=
loopMax; ++loopCount) {
1088 egsFatal(
"EGS_InputPrivate::findStart: Too many iterations were required! Input may be invalid, or consider increasing loopMax.");
1094 char c = ::toupper(input[pos++]);
1095 if (start_key[ns] == c) {
1100 if (start_key[ns] == c) {
1104 if (ns == start_key.size()) {
1108 string::size_type epos = input.find(end_key,pos);
1110 what.assign(input,pos,epos-pos);
1111 end = epos + end_key.size();
1112 return pos-start_key.size();
1117 void EGS_InputPrivate::print(
int indent, ostream &out)
const {
1118 if (children.size() > 0) {
1119 if (key.size() > 0) {
1120 for (
int j=0; j<indent; j++) {
1121 out << indent_space;
1123 out << start_key_begin <<
" " << key << start_key_end << endl;
1126 for (
int i=0; i<children.size(); i++) {
1127 children[i]->print(indent,out);
1130 if (key.size() > 0) {
1131 for (
int j=0; j<indent; j++) {
1132 out << indent_space;
1134 out << stop_key_begin <<
" " << key << stop_key_end << endl;
1138 for (
int j=0; j<indent; j++) {
1139 out << indent_space;
1141 out << key <<
" = " << value << endl;
1145 void EGS_InputPrivate::removeEmptyLines(
string &input) {
1147 while ((pos1=input.find(
'\n',pos)) < input.size()) {
1152 bool is_only_space =
true;
1153 for (
int j=pos; j<pos1; j++) {
1154 if (!isspace(input[j])) {
1155 is_only_space =
false;
1159 if (is_only_space) {
1160 input.erase(pos,pos1+1-pos);
1171 return EGS_InputPrivate::compareKeys(s1,s2);
1189 void egs_warning(
const char *msg,...) {
1192 vfprintf(stderr, msg, ap);
1200 EGS_InputPrivate p(
"test");
const EGS_I64 loopMax
The maximum number of iterations for near-infinite loops.
int main(int argc, char **argv)
A main program for egspp applications.
Global egspp functions header file.
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
void(* EGS_InfoFunction)(const char *,...)
Defines a function printf-like prototype for functions to be used to report info, warnings...
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.