45 #define S_STREAM std::istrstream
48 #define S_STREAM std::istringstream
60 static char start_key_begin[] =
":START";
61 static char stop_key_begin[] =
":STOP";
62 static char start_key_end[] =
":";
63 static char stop_key_end[] =
":";
64 static char indent_space[] =
" ";
71 class EGS_LOCAL EGS_InputPrivate {
75 vector<EGS_InputPrivate *> children;
78 EGS_InputPrivate() : nref(0) {};
79 EGS_InputPrivate(
const string &Key,
const string &Val =
"") : key(Key),
80 value(Val), children(), nref(0) { };
81 EGS_InputPrivate(
const EGS_InputPrivate &p,
bool deep=
false) :
82 key(p.key), value(p.value), children(), nref(0) {
83 for (
unsigned int j=0; j<p.children.size(); j++) {
85 children.push_back(
new EGS_InputPrivate(*p.children[j],deep));
88 children.push_back(p.children[j]);
95 for (
unsigned int j=0; j<children.size(); j++) {
96 deleteItem(children[j]);
100 int replace(
const string &replace_what,
const string &replace_with);
102 int setContentFromFile(
const char *fname);
103 int setContentFromString(
string &input);
104 int setContent(istream &input);
106 int addContentFromFile(
const char *fname);
107 int addContentFromString(
string &input);
108 int addContent(istream &input);
109 string getCleanInputString(istream &input);
111 void processInputLoop(EGS_InputPrivate *p);
113 void addItem(EGS_InputPrivate *p) {
115 children.push_back(p);
118 EGS_InputPrivate *takeInputItem(
const string &key,
bool self=
true) {
119 if (
self && isA(key)) {
122 for (vector<EGS_InputPrivate *>::iterator it=children.begin();
123 it != children.end(); it++) {
124 if (compareKeys((*it)->key,key)) {
125 EGS_InputPrivate *res = *it;
137 EGS_InputPrivate *getInputItem(
const string &Key) {
141 for (
unsigned int j=0; j<children.size(); j++)
142 if (compareKeys(children[j]->key,Key)) {
148 bool isA(
const string &Key)
const {
149 return compareKeys(key,Key);
152 static void removeComment(
const string &start,
const string &end,
153 string &input,
bool newline);
155 static int findStart(
int start,
int stop,
156 const string &start_key,
const string &end_key,
157 const string &input,
string &what,
int &end);
158 static int findStop(
int start,
const string &start_string,
159 const string &end_string,
const string &input,
int &ie);
161 static bool compareKeys(
const string &s1,
const string &s2);
163 void print(
int nind, ostream &)
const;
165 void removeEmptyLines(
string &input);
167 static void deleteItem(EGS_InputPrivate *p) {
196 p =
new EGS_InputPrivate(name,value);
200 EGS_InputPrivate::deleteItem(p);
204 EGS_InputPrivate::deleteItem(p);
205 p =
new EGS_InputPrivate;
206 return p->setContentFromFile(fname);
210 EGS_InputPrivate::deleteItem(p);
211 p =
new EGS_InputPrivate;
212 return p->setContentFromString(input);
217 p =
new EGS_InputPrivate;
219 return p->addContentFromFile(fname);
224 p =
new EGS_InputPrivate;
226 return p->addContentFromString(input);
237 if (item == p && !
self) {
267 p =
new EGS_InputPrivate(*input.p);
278 return p->key.c_str();
288 template <
class T>
int EGS_LOCAL
289 get_input(
const EGS_InputPrivate *p,
const string &key, vector<T> &values) {
293 const EGS_InputPrivate *p1;
294 if (!p->children.size()) {
301 for (
unsigned int j=0; j<p->children.size(); j++) {
312 values.erase(values.begin(),values.end());
313 S_STREAM in(p1->value.c_str());
315 for (EGS_I64 loopCount=0; loopCount<=
loopMax; ++loopCount) {
317 egsFatal(
"EGS_InputPrivate::findStart: Too many iterations were required! Input may be invalid, or consider increasing loopMax.");
323 values.push_back(tmp);
326 if (values.size() <= 0) {
332 if (values.size() <= 0) {
342 return get_input(p,key,values);
346 return get_input(p,key,values);
350 return get_input(p,key,values);
353 template <
class T>
int EGS_LOCAL
354 get_input(
const EGS_InputPrivate *p,
const string &key, T &value) {
358 const EGS_InputPrivate *p1;
359 if (!p->children.size()) {
366 for (
unsigned int j=0; j<p->children.size(); j++) {
377 S_STREAM in(p1->value.c_str());
390 int err = getInput(key,v);
395 for (
unsigned int j=1; j<v.size(); j++) {
407 return get_input(p,key,value);
411 return get_input(p,key,value);
415 return get_input(p,key,value);
424 int err = getInput(key,aux);
428 if (aux.size() > 1) {
431 if (aux[0].size() < 10) {
435 err = getInput(key,n);
444 if (aux[0][0] ==
'+') {
447 else if (aux[0][0] ==
'-') {
451 EGS_I64 fac=1, res = 0;
452 for (
int j=aux[0].size()-1; j>=nfirst; j--) {
453 if (!isdigit(aux[0][j])) {
456 EGS_I64 c = aux[0][j]-48;
469 int def,
bool *found)
const {
471 int err = getInput(key,res);
473 for (
unsigned int j=0; j<allowed.size(); j++) {
474 if (EGS_InputPrivate::compareKeys(res,allowed[j])) {
489 int EGS_InputPrivate::setContentFromFile(
const char *fname) {
494 return setContent(in);
497 int EGS_InputPrivate::addContentFromFile(
const char *fname) {
501 const char *s = fname;
502 while (isspace(*s) && (*s)) {
509 return addContent(in);
512 int EGS_InputPrivate::setContentFromString(
string &input) {
513 S_STREAM in(input.c_str());
514 return setContent(in);
517 int EGS_InputPrivate::addContentFromString(
string &input) {
518 S_STREAM in(input.c_str());
519 return addContent(in);
522 void EGS_InputPrivate::removeComment(
const string &start,
const string &end,
523 string &input,
bool newline) {
524 string::size_type spos=0, epos=0;
525 while ((epos = input.find(end,spos)) < input.size()) {
526 spos = input.find(start,spos);
528 string::size_type len = epos - spos;
532 input.erase(spos,len);
543 int EGS_InputPrivate::setContent(istream &in) {
544 for (
unsigned int j=0; j<children.size(); j++) {
547 children.erase(children.begin(),children.end());
548 return addContent(in);
551 bool EGS_InputPrivate::compareKeys(
const string &s1,
const string &s2) {
554 for (j=0; j<s1.size(); j++)
555 if (!isspace(s1[j])) {
556 t1 += ::toupper(s1[j]);
558 for (j=0; j<s2.size(); j++)
559 if (!isspace(s2[j])) {
560 t2 += ::toupper(s2[j]);
570 int EGS_InputPrivate::replace(
const string &replace_what,
571 const string &replace_with) {
572 string::size_type pos = 0;
574 while ((pos = key.find(replace_what,pos)) < key.size()) {
575 key.replace(pos,replace_what.size(),replace_with);
579 while ((pos = value.find(replace_what,pos)) < value.size()) {
580 value.replace(pos,replace_what.size(),replace_with);
583 for (
int j=0; j<children.size(); j++) {
584 nr += children[j]->replace(replace_what,replace_with);
683 const char *getVarNameReplacement()
const {
686 const char *getVarReplacement()
const {
689 virtual void setVarReplacement(
int) = 0;
702 void setVarReplacement(
int i) {
703 int v = vmin + vdelta*i;
718 void setVarReplacement(
int i) {
719 double v = vmin + vdelta*i;
720 sprintf(buf,format.c_str(),v);
730 void setVarReplacement(
int i) {
731 string str = list[i];
732 sprintf(buf,
"%s",str.c_str());
747 if (in.fail() || !in.good()) {
748 egsWarning(
"Failed reading type and name from %s\n",input);
751 if (type < 0 || type > 2) {
752 egsFatal(
"Invalid loop type in input: %s\n"
753 "Only integer [0], float [1] and list [2] are valid types!\n",
759 in >> vmin >> vdelta;
762 else if (type == 1) {
764 in >> vmin >> vdelta;
767 if (format.empty()) {
775 else if (type == 2) {
781 vstr.push_back(s_tmp);
785 if (in.fail() && in.eof()) {
789 egsFatal(
"No list-items found reading loop-input: %s\n",input);
797 egsFatal(
"Fatal error reading loop input list from %s\n",input);
801 egsWarning(
"Failed reading vmin vdelta from %s\n",input);
809 void EGS_InputPrivate::processInputLoop(EGS_InputPrivate *p) {
811 EGS_InputPrivate *ic = p->takeInputItem(
"loop count");
813 egsWarning(
"processInputLoop: no 'loop count' input\n");
817 int err = get_input(ic,
"loop count",nloop);
819 if (err || nloop < 1) {
820 egsWarning(
"processInputLoop: got %d for loop count, expecting 1 or "
824 EGS_InputPrivate *iv;
825 vector<EGS_InputLoopVariable *> ivars;
826 while ((iv = p->takeInputItem(
"loop variable")) != 0) {
828 EGS_InputLoopVariable::getInputLoopVariable(iv->value.c_str());
831 egsFatal(
"procesInputLoop: loop size (%d) larger than list size (%d)!\n"
832 "This will cause a segmentation fault error, aborting ....\n",
836 if (!v)
egsWarning(
"processInputLoop: failed to create loop variable"
837 " based on the input %s\n",iv->value.c_str());
844 egsWarning(
"processInputLoop: no loop variables\n");
847 int nvar = ivars.size();
862 for (
int iloop=0; iloop<nloop; iloop++) {
863 for (j=0; j<p->children.size(); j++) {
864 EGS_InputPrivate *pnew =
new EGS_InputPrivate(*p->children[j],
true);
865 for (
int ivar=0; ivar<nvar; ivar++) {
866 ivars[ivar]->setVarReplacement(iloop);
867 pnew->replace(ivars[ivar]->getVarNameReplacement(),
868 ivars[ivar]->getVarReplacement());
870 children.push_back(pnew);
874 for (j=0; j<ivars.size(); j++) {
879 int EGS_InputPrivate::addContent(istream &in) {
880 string input = getCleanInputString(in);
885 string::size_type p1;
887 while ((p1=input.find(
'\n',p)) < input.size()) {
888 string::size_type p2 = input.find(
'=',p);
891 what.assign(input,p,p2-p);
892 if (compareKeys(what,
"includefile")) {
894 value.assign(input,p2+1,p1-p2-1);
897 const char *s = value.c_str();
898 while (isspace(*s) && (*s)) {
903 egsFatal(
"EGS_Input: failed to add content from "
904 "include file %s\n",value.c_str());
907 string input2 = getCleanInputString(in2);
909 input.erase(p, p1 - p);
910 input.insert(p, input2);
918 vector<string> start_keys, stop_keys;
919 int ep = input.size();
923 while ((p=findStart(p,ep,start_key_begin,start_key_end,input,what,ie))>=0) {
924 string the_start = start_key_begin;
925 string the_end = stop_key_begin;
926 for (
int j=0; j<what.size(); j++) {
927 char c = ::toupper(what[j]);
933 the_start += start_key_end;
934 the_end += stop_key_end;
936 int ep = findStop(ie+1,the_start,the_end,input,p1);
938 EGS_InputPrivate *ip =
new EGS_InputPrivate(what);
940 content.assign(input,ie+1,p1-ie-1);
942 ip->setContentFromString(content);
943 if (ip->isA(
"input loop")) {
944 processInputLoop(ip);
948 children.push_back(ip);
952 egsWarning(
"No matching stop delimiter for %s\n",what.c_str());
959 while ((p1=input.find(
'\n',p)) < input.size()) {
961 while (--j > p && isspace(input[j]));
963 if (input[j] ==
',' || input[j] ==
'\\') {
973 while ((p1=input.find(
'\n',p)) < input.size()) {
974 string::size_type p2 = input.find(
'=',p);
977 what.assign(input,p,p2-p);
979 value.assign(input,p2+1,p1-p2-1);
980 for (
int j=0; j<value.size(); j++) {
981 if (value[j] ==
',') {
986 EGS_InputPrivate *ip =
new EGS_InputPrivate(what,value);
987 children.push_back(ip);
1000 string EGS_InputPrivate::getCleanInputString(istream &in) {
1002 bool last_was_space =
false;
1003 for (EGS_I64 loopCount=0; loopCount<=
loopMax; ++loopCount) {
1005 egsFatal(
"EGS_InputPrivate::addContent: Too many iterations were required! Input may be invalid, or consider increasing loopMax.");
1009 if (in.eof() || !in.good()) {
1012 bool take_it =
true;
1014 if (last_was_space && c !=
'\n') {
1017 last_was_space =
true;
1020 last_was_space =
false;
1026 removeComment(
"#",
"\n",input,
true);
1027 removeComment(
"!",
"\n",input,
true);
1028 removeComment(
"//",
"\n",input,
true);
1029 removeComment(
"/*",
"*/",input,
false);
1030 removeEmptyLines(input);
1035 int EGS_InputPrivate::findStop(
int start,
const string &the_start,
1036 const string &the_end,
const string &input,
1039 int have_start=1, have_end=0;
1040 int end_started = start;
1041 for (
int j=start; j<input.size(); j++) {
1042 if (!isspace(input[j])) {
1043 char c = ::toupper(input[j]);
1044 if (the_start[ns] == c) {
1049 if (the_start[ns] == c) {
1053 if (ns == the_start.size()) {
1060 if (the_end[ne] == c) {
1065 if (the_end[ne] == c) {
1070 if (ne == the_end.size()) {
1073 if (have_end == have_start) {
1084 int EGS_InputPrivate::findStart(
int start,
int stop,
const string &start_key,
1085 const string &end_key,
const string &input,
1086 string &what,
int &end) {
1087 string::size_type pos = start;
1089 for (EGS_I64 loopCount=0; loopCount<=
loopMax; ++loopCount) {
1091 egsFatal(
"EGS_InputPrivate::findStart: Too many iterations were required! Input may be invalid, or consider increasing loopMax.");
1097 char c = ::toupper(input[pos++]);
1098 if (start_key[ns] == c) {
1103 if (start_key[ns] == c) {
1107 if (ns == start_key.size()) {
1111 string::size_type epos = input.find(end_key,pos);
1113 what.assign(input,pos,epos-pos);
1114 end = epos + end_key.size();
1115 return pos-start_key.size();
1120 void EGS_InputPrivate::print(
int indent, ostream &out)
const {
1121 if (children.size() > 0) {
1122 if (key.size() > 0) {
1123 for (
int j=0; j<indent; j++) {
1124 out << indent_space;
1126 out << start_key_begin <<
" " << key << start_key_end << endl;
1129 for (
int i=0; i<children.size(); i++) {
1130 children[i]->print(indent,out);
1133 if (key.size() > 0) {
1134 for (
int j=0; j<indent; j++) {
1135 out << indent_space;
1137 out << stop_key_begin <<
" " << key << stop_key_end << endl;
1141 for (
int j=0; j<indent; j++) {
1142 out << indent_space;
1144 out << key <<
" = " << value << endl;
1148 void EGS_InputPrivate::removeEmptyLines(
string &input) {
1150 while ((pos1=input.find(
'\n',pos)) < input.size()) {
1155 bool is_only_space =
true;
1156 for (
int j=pos; j<pos1; j++) {
1157 if (!isspace(input[j])) {
1158 is_only_space =
false;
1162 if (is_only_space) {
1163 input.erase(pos,pos1+1-pos);
1174 return EGS_InputPrivate::compareKeys(s1,s2);
1193 replace(copy.begin(), copy.end(),
',',
' ');
1194 istringstream iss(copy);
1197 vector<string> tokens;
1199 while (iss >> token) {
1200 tokens.push_back(token);
1208 vector<string>::const_iterator end) {
1210 vector<int> integers;
1213 for (
auto it = begin; it != end; ++it) {
1219 istringstream iss(token);
1221 if ((iss >> number) && iss.eof()) {
1222 integers.push_back(number);
1229 istringstream iss(token);
1232 if ((iss >> start >> dash >> stop) && dash ==
'-' && iss.eof()) {
1233 for (
int i = min(start, stop); i <= max(start, stop); i++) {
1234 integers.push_back(i);
1241 sort(integers.begin(), integers.end());
1242 integers.erase(unique(integers.begin(), integers.end()), integers.end());
1257 void egs_warning(
const char *msg,...) {
1260 vfprintf(stderr, msg, ap);
1268 EGS_InputPrivate p(
"test");
Global egspp functions header file.
void(* EGS_InfoFunction)(const char *,...)
Defines a function printf-like prototype for functions to be used to report info, warnings,...
int main(int argc, char **argv)
A main program for egspp applications.
EGS_InfoFunction EGS_EXPORT egsFatal
Always use this function for reporting fatal errors.
const EGS_I64 loopMax
The maximum number of iterations for near-infinite loops.
EGS_InfoFunction EGS_EXPORT egsWarning
Always use this function for reporting warnings.