123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518 |
- ///////////////////////////////////////////////////////////////////////////////////////
- /// \file gutil.cpp
- /// \brief GUTIL LIBRARY (Fully portable version)
- ///
- /// This library is provided as a component of the ecosystem modelling platform
- /// LPJ-GUESS. It combines the functionality of the XTRING and BENUTIL libraries
- ///
- /// FULL PORTABILITY VERSION: tested and should work in any Unix, Linux or Windows
- /// environment.
- ///
- /// Enquiries to: Joe Siltberg, Lund University: joe.siltberg@nateko.lu.se
- /// All rights reserved, copyright retained by the author.
- ///
- /// \author Ben Smith, University of Lund
- /// $Date: 2014-02-05 10:30:16 +0100 (Wed, 05 Feb 2014) $
- ///
- ///////////////////////////////////////////////////////////////////////////////////////
- #include "gutil.h"
- #include <stdarg.h>
- void fail() {
- ::printf("Error in GUTIL library: out of memory\n");
- fprintf(stderr,"Error in GUTIL library: out of memory\n");
- exit(99);
- }
- const unsigned long XEGMENT=32;
- void xtring::init() {
- buf=NULL;
- ptext=new char[XEGMENT];
- if (!ptext) fail();
- nxegment=1;
- *ptext='\0';
- }
- void xtring::resize(unsigned long nchar) {
- // Resizes character buffer pointed to by ptext if necessary to
- // accomodate nchar characters, plus a \0
- if (nchar<0) nchar=0;
- nchar++;
- if (nchar>nxegment*XEGMENT || (nxegment-1)*XEGMENT>=nchar) {
- ptext[nxegment*XEGMENT-1]='\0';
- unsigned long nxegment_old=nxegment;
- nxegment=nchar/XEGMENT+!!(nchar%XEGMENT);
- char* pnew=new char[nxegment*XEGMENT];
- if (!pnew) fail();
- if (nxegment>nxegment_old || strlen(ptext)<nxegment*XEGMENT) strcpy(pnew,ptext);
- else pnew[nxegment*XEGMENT-1]='\0';
- delete[] ptext;
- ptext=pnew;
- }
- }
- void xtring::expand(unsigned long nchar) {
- if (nchar<0) nchar=0;
- if (nchar>=nxegment*XEGMENT) {
- nxegment=nchar/XEGMENT+1;
- char* pnew=new char[nxegment*XEGMENT];
- if (!pnew) fail();
- unsigned long i;
- for (i=0;i<nchar;i++)
- pnew[i]=ptext[i];
- pnew[i]='\0';
- delete[] ptext;
- ptext=pnew;
- }
- }
- xtring::xtring(const xtring& s) {
- // COPY CONSTRUCTOR
- init();
- resize(strlen(s.ptext));
- strcpy(ptext,s.ptext);
- }
- xtring::xtring() {
- // CONSTRUCTOR: xtring s;
- init();
- *ptext='\0';
- }
- xtring::xtring(char* inittext) {
- // CONSTRUCTOR: xtring s="text";
- init();
- resize(strlen(inittext));
- strcpy(ptext,inittext);
- }
- xtring::xtring(const char* inittext) {
- // CONSTRUCTOR: xtring s="text";
- init();
- resize(strlen(inittext));
- strcpy(ptext,inittext);
- }
- xtring::xtring(char c) {
- // CONSTRUCTOR: xtring s='c';
- init();
- ptext[0]=c;
- ptext[1]='\0';
- }
- xtring::xtring(unsigned long n) {
- // CONSTRUCTOR: xtring s[n]
- init();
- resize(n);
- *ptext='\0';
- }
- xtring::xtring(int n) {
- // CONSTRUCTOR: xtring s[n]
- init();
- resize(n);
- *ptext='\0';
- }
- xtring::xtring(unsigned int n) {
- // CONSTRUCTOR: xtring s[n]
- init();
- resize(n);
- *ptext='\0';
- }
- xtring::xtring(long n) {
- // CONSTRUCTOR: xtring s[n]
- init();
- resize(n);
- *ptext='\0';
- }
- xtring::~xtring() {
- // DESTRUCTOR
- if (buf) delete[] buf;
- delete[] ptext;
- }
- xtring::operator char*() {
- // Conversion function (cast operator) to char*
- return ptext;
- }
- xtring::operator const char*() const {
- // Conversion function (cast operator) to const char*
- return ptext;
- }
- void xtring::reserve(unsigned long n) {
- // Set string buffer length to at least n (not including trailing \0)
- resize(n);
- }
- unsigned long xtring::len() {
- // String length not including trailing \0
- return strlen(ptext);
- }
- xtring xtring::upper() {
- // Upper case
- if (buf) delete[] buf;
- buf=new char[len()+1];
- if (!buf) fail();
- char* pold=ptext,*pnew=buf;
- do {
- if (*pold>='a' && *pold<='z') *pnew=*pold-32;
- else *pnew=*pold;
- pnew++;
- } while (*pold++);
- return (xtring)buf;
- }
- xtring xtring::lower() {
- // Lower case
- if (buf) delete[] buf;
- buf=new char[len()+1];
- if (!buf) fail();
- char* pold=ptext,*pnew=buf;
- do {
- if (*pold>='A' && *pold<='Z') *pnew=*pold+32;
- else *pnew=*pold;
- pnew++;
- } while (*pold++);
- return (xtring)buf;
- }
- xtring xtring::printable() {
- // Printable characters (ASCII code >=32)
- if (buf) delete[] buf;
- buf=new char[len()+1];
- if (!buf) fail();
- char* pold=ptext,*pnew=buf;
- while (*pold) {
- if (*pold>=' ') *pnew++=*pold;
- pold++;
- }
- *pnew='\0';
- return (xtring)buf;
- }
- xtring xtring::left(unsigned long n) {
- // Leftmost n characters
- if (buf) delete[] buf;
- if (n<=0) {
- buf=new char[1];
- if (!buf) fail();
- *buf='\0';
- }
- else {
- buf=new char[n+1];
- if (!buf) fail();
- char* pold=ptext,*pnew=buf;
- unsigned long i=0;
- while (i<n && *pold) {
- *pnew=*pold;
- pold++;
- pnew++;
- i++;
- }
- *pnew='\0';
- }
- return (xtring)buf;
- }
- xtring xtring::mid(unsigned long s) {
- // Rightmost portion of xtring, starting at character s
- if (buf) delete[] buf;
- if (s>=len()) {
- buf=new char[1];
- if (!buf) fail();
- *buf='\0';
- }
- else {
- buf=new char[len()-s+1];
- if (!buf) fail();
- strcpy(buf,ptext+s);
- }
- return (xtring)buf;
- }
- xtring xtring::mid(unsigned long s,unsigned long n) {
- // Middle n characters starting at character s
- if (buf) delete[] buf;
- if (s>=len() || n<=0) {
- buf=new char[1];
- if (!buf) fail();
- *buf='\0';
- }
- else {
- buf=new char[n+1];
- if (!buf) fail();
- char* pold=ptext+s,*pnew=buf;
- unsigned long i=0;
- while (i++<n && *pold) *pnew++=*pold++;
- *pnew='\0';
- }
- return (xtring)buf;
- }
- xtring xtring::right(unsigned long n) {
- // Rightmost n characters
- unsigned long s=len()-n;
- if (s<0) s=0;
- return mid(s);
- }
- long xtring::find(const char* s) {
- // Find string s in this xtring
- // (returns -1 if string does not occur)
- long length=strlen(s);
- long bound=len()-length;
- long i=0;
- while (i<=bound) {
- xtring sub=mid(i,length);
- if (sub==s) return i;
- i++;
- }
- return -1;
- }
- long xtring::find(char c) {
- // Find character in this xtring
- long i;
- long bound=len();
- for (i=0;i<bound;i++)
- if (ptext[i]==c) return i;
- return -1;
- }
- long xtring::findoneof(const char* s) {
- // Find one of several characters in this xtring
- long i,j;
- long bound=len();
- long nchar=strlen(s);
- for (i=0;i<bound;i++)
- for (j=0;j<nchar;j++)
- if (ptext[i]==s[j]) return i;
- return -1;
- }
- long xtring::findnotoneof(const char* s) {
- // Find first character NOT matching characters in s
- long i,j;
- long bound=len();
- long nchar=strlen(s);
- char found;
- for (i=0;i<bound;i++) {
- found=0;
- for (j=0;j<nchar && !found;j++)
- if (ptext[i]==s[j]) found=1;
- if (!found) return i;
- }
- return -1;
- }
- double xtring::num() {
- // Conversion to number
- char* endptr;
- double dval;
- dval=strtod(ptext,&endptr);
- if (*endptr) return 0;
- return dval;
- }
- char xtring::isnum() {
- // Whether xtring can be converted to a number
- char* endptr;
- strtod(ptext,&endptr);
- if (*endptr) return 0;
- return 1;
- }
- void xtring::printf(const char* fmt,...) {
- va_list v;
- va_start(v,fmt);
- const int MINBUF=100;
- xtring sect;
- xtring output="";
- xtring fspec;
- xtring wspec;
- xtring buffer(MINBUF);
- const char* pfmt=fmt;
- char* pchar;
- int i;
- char waitspec=0,readspec=0,readwidth,havewidth;
- i=0;
- while (*pfmt) {
- if (waitspec) {
- if ((*pfmt>='0' && *pfmt<='9') || *pfmt=='-' || *pfmt=='+' || *pfmt==' ' ||
- *pfmt=='#' || *pfmt=='h' || *pfmt=='l' || *pfmt=='I' || *pfmt=='L' ||
- *pfmt=='c' || *pfmt=='C' || *pfmt=='d' || *pfmt=='i' || *pfmt=='o' ||
- *pfmt=='u' || *pfmt=='x' || *pfmt=='X' || *pfmt=='e' || *pfmt=='E' ||
- *pfmt=='f' || *pfmt=='g' || *pfmt=='G' || *pfmt=='n' || *pfmt=='p' ||
- *pfmt=='s' || *pfmt=='S' || *pfmt=='.') {
- readspec=1;
- havewidth=0;
- readwidth=0;
- wspec="0";
- fspec="%";
- pfmt--;
- }
- else output+=*pfmt;
- waitspec=0;
- }
- else if (readspec) {
- if (*pfmt!='*') fspec+=*pfmt;
- if (readwidth) {
- if (*pfmt>='0' && *pfmt<='9') wspec+=*pfmt;
- else {
- readwidth=0;
- havewidth=1;
- }
- }
- else if (*pfmt>='0' && *pfmt<='9' && !havewidth) {
- wspec=*pfmt;
- readwidth=1;
- }
- else if (*pfmt=='*' && !havewidth) {
- wspec.reserve(MINBUF);
- sprintf(wspec,"%d",va_arg(v,int));
- fspec+=wspec;
- havewidth=1;
- }
- else if (*pfmt!='-' && *pfmt!='+' && *pfmt!=' ' && *pfmt!='#') {
- havewidth=1;
- }
- if (*pfmt=='c' || *pfmt=='C' || *pfmt=='d' || *pfmt=='i' || *pfmt=='o' ||
- *pfmt=='u' || *pfmt=='x' || *pfmt=='X') {
- buffer.reserve((unsigned long)(MINBUF+wspec.num()));
- sprintf(buffer,fspec,va_arg(v,int));
- output+=buffer;
- readspec=0;
- }
- else if (*pfmt=='e' || *pfmt=='E' || *pfmt=='f' || *pfmt=='g' ||
- *pfmt=='G') {
- buffer.reserve((unsigned long)(MINBUF+wspec.num()));
- sprintf(buffer,fspec,va_arg(v,double));
- output+=buffer;
- readspec=0;
- }
- else if (*pfmt=='p') {
- buffer.reserve((unsigned long)(MINBUF+wspec.num()));
- sprintf(buffer,fspec,va_arg(v,void*));
- output+=buffer;
- readspec=0;
- }
- else if (*pfmt=='s' || *pfmt=='S') {
- pchar=va_arg(v,char*);
- buffer.reserve((unsigned long)(strlen(pchar)+wspec.num()));
- sprintf(buffer,fspec,pchar);
- output+=buffer;
- readspec=0;
- }
- }
- else if (*pfmt=='%') waitspec=1;
- else {
- sect[i++]=*pfmt;
- if (*(pfmt+1)=='%' || !*(pfmt+1)) {
- sect[i]='\0';
- output+=sect;
- i=0;
- }
- }
- pfmt++;
- }
- resize(output.len());
- strcpy(ptext,output);
- }
- xtring& xtring::operator=(xtring& s) {
- // Assignment: s1=s2;
- resize(s.len());
- strcpy(ptext,s.ptext);
- return *this;
- }
- xtring& xtring::operator=(const char* s) {
- // Assignment: s="text"
- resize(strlen(s));
- strcpy(ptext,s);
- return *this;
- }
- xtring& xtring::operator=(char c) {
- // Assignment: s='c'
- resize(1);
- ptext[0]=c;
- ptext[1]='\0';
- return *this;
- }
- xtring xtring::operator+(xtring& s2) {
- // Concatenate: s1+s2
- if (buf) delete[] buf;
- buf=new char[len()+s2.len()+1];
- if (!buf) fail();
- strcpy(buf,ptext);
- strcat(buf,s2.ptext);
- return (xtring)buf;
- }
- xtring xtring::operator+(const char* s2) {
- // Concatenate: s1+"text"
- if (buf) delete[] buf;
- buf=new char[len()+strlen(s2)+1];
- if (!buf) fail();
- strcpy(buf,ptext);
- strcat(buf,s2);
- return xtring(buf);
- }
- xtring xtring::operator+(char c) {
- // Concatenate s1+'c'
- return (xtring)ptext+(xtring)c;
- }
- xtring& xtring::operator+=(xtring& s2) {
- // Concatenate s1+=s2;
- resize(len()+s2.len());
- strcat(ptext,s2.ptext);
- return *this;
- }
- xtring& xtring::operator+=(const char* s2) {
- // Concatenate s1+="text";
- resize(len()+strlen(s2));
- strcat(ptext,s2);
- return *this;
- }
- xtring& xtring::operator+=(char c) {
- // Concatenate s1+='c';
- resize(len()+1);
- strcat(ptext,(xtring)c);
- return *this;
- }
- char& xtring::operator[](unsigned long n) {
- // Reference s[n] (NB: resizes xtring if necessary)
- expand(n);
- return ptext[n];
- }
- char& xtring::operator[](int n) {
- expand(n);
- return ptext[(unsigned long)n];
- }
- char& xtring::operator[](unsigned int n) {
- expand(n);
- return ptext[(unsigned long)n];
- }
- char& xtring::operator[](long n) {
- expand(n);
- return ptext[(unsigned long)n];
- }
- // Comparison operators
- bool xtring::operator==(xtring& s2) const {
- if (strcmp(ptext,s2.ptext)) return false;
- return true;
- }
- bool xtring::operator==(char* s2) const {
- if (strcmp(ptext,s2)) return false;
- return true;
- }
- bool xtring::operator==(const char* s2) const {
- if (strcmp(ptext,s2)) return false;
- return true;
- }
- bool xtring::operator==(char c) const {
- if (strcmp(ptext,(xtring)c)) return false;
- return true;
- }
- bool xtring::operator!=(xtring& s2) const {
- if (strcmp(ptext,s2.ptext)) return true;
- return false;
- }
- bool xtring::operator!=(char* s2) const {
- if (strcmp(ptext,s2)) return true;
- return false;
- }
- bool xtring::operator!=(const char* s2) const {
- if (strcmp(ptext,s2)) return true;
- return false;
- }
- bool xtring::operator!=(char c) const {
- if (strcmp(ptext,(xtring)c)) return true;
- return false;
- }
- bool xtring::operator<(xtring& s2) const {
- if (strcmp(ptext,s2.ptext)<0) return true;
- return false;
- }
- bool xtring::operator<(char* s2) const {
- if (strcmp(ptext,s2)<0) return true;
- return false;
- }
- bool xtring::operator<(const char* s2) const {
- if (strcmp(ptext,s2)<0) return true;
- return false;
- }
- bool xtring::operator<(char c) const {
- if (strcmp(ptext,(xtring)c)<0) return true;
- return false;
- }
- bool xtring::operator>(xtring& s2) const {
- if (strcmp(ptext,s2.ptext)>0) return true;
- return false;
- }
- bool xtring::operator>(char* s2) const {
- if (strcmp(ptext,s2)>0) return true;
- return false;
- }
- bool xtring::operator>(const char* s2) const {
- if (strcmp(ptext,s2)>0) return true;
- return false;
- }
- bool xtring::operator>(char c) const {
- if (strcmp(ptext,(xtring)c)>0) return true;
- return false;
- }
- bool xtring::operator<=(xtring& s2) const {
- if (strcmp(ptext,s2.ptext)<=0) return true;
- return false;
- }
- bool xtring::operator<=(char* s2) const {
- if (strcmp(ptext,s2)<=0) return true;
- return false;
- }
- bool xtring::operator<=(const char* s2) const {
- if (strcmp(ptext,s2)<=0) return true;
- return false;
- }
- bool xtring::operator<=(char c) const {
- if (strcmp(ptext,(xtring)c)<=0) return true;
- return false;
- }
- bool xtring::operator>=(xtring& s2) const {
- if (strcmp(ptext,s2.ptext)>=0) return true;
- return false;
- }
- bool xtring::operator>=(char* s2) const {
- if (strcmp(ptext,s2)>=0) return true;
- return false;
- }
- bool xtring::operator>=(const char* s2) const {
- if (strcmp(ptext,s2)>=0) return true;
- return false;
- }
- bool xtring::operator>=(char c) const {
- if (strcmp(ptext,(xtring)c)>=0) return true;
- return false;
- }
- void unixtime(xtring& result) {
- time_t t;
- time(&t);
- result=ctime(&t);
- result=result.left(result.findoneof("\n"));
- }
- FILE** pin;
- xtring inxtr;
- bool iseol=false;
- char cbuf;
- inline char xgetc() {
- // Equivalent to getc(*pin), but returns character stored in cbuf (global)
- // if there is one (see xungetc below)
- char copy;
- if (cbuf) {
- copy=cbuf;
- cbuf=0;
- return copy;
- }
- return getc(*pin);
- }
- inline void xungetc(char& ch) {
- // Equivalent to ungetc(ch,*pin), but assigns ch to cbuf instead of trying
- // to push it back onto the stream (which may not be possible)
- cbuf=ch;
- }
- inline bool xfeof() {
- // Equivalent to feof(*pin), but returns false if character stored in cbuf
- // even if feof(*pin)==true
- if (feof(*pin) && !cbuf) return true;
- return false;
- }
- inline int readfixedwidth(int& width) {
- // Reads the next 'width' characters from stream in
- // Returns the number of characters successfully read (may be <width on eof)
- int cread=0;
- char ch;
- iseol=false;
- inxtr.reserve(width);
- if (xfeof()) {
- inxtr[cread]='\0';
- iseol=1;
- return 0;
- }
- while (cread<width) {
- ch=xgetc();
- if (xfeof() || ch=='\n') {
- inxtr[cread]='\0';
- iseol=1;
- return cread;
- }
- inxtr[cread++]=ch;
- }
- inxtr[cread]='\0';
- return cread;
- }
- inline int readtoeol(bool breakcomma) {
- // Reads to end of the current line or eof from stream in
- // Returns number of characters read
- int cread=0;
- char ch;
- iseol=false;
- do {
- ch=xgetc();
- if (xfeof() || ch=='\n') {
- inxtr[cread]='\0';
- iseol=true;
- return cread;
- }
- else if (breakcomma && ch==',') {
- inxtr[cread]='\0';
- return cread;
- }
- inxtr[cread++]=ch;
- } while (true);
- }
- inline void readtocomma() {
- // Reads to next comma or next non-white-space character,
- // whichever comes first (newline or eof always terminates input)
- char ch;
- iseol=false;
- do {
- ch=xgetc();
- if (xfeof() || ch=='\n') {
- iseol=true;
- return;
- }
- if (ch==',') return;
- if (ch!=' ' && ch!='\t') {
- xungetc(ch);
- return;
- }
- } while (true);
- }
- inline int readtowhitespace(bool& breakcomma) {
- // Reads to next space, tab, newline or eof from stream in
- // Space or tab is not read in (returned to stream)
- // Returns number of characters read
- int cread=0;
- char ch;
- iseol=false;
- do {
- ch=xgetc();
- if (xfeof() || ch=='\n') {
- iseol=true;
- inxtr[cread]='\0';
- return cread;
- }
- if (breakcomma) {
- if (ch==' ' || ch=='\t') {
- inxtr[cread]='\0';
- readtocomma();
- return cread;
- }
- if (ch==',') {
- inxtr[cread]='\0';
- return cread;
- }
- }
- else {
- if (ch==' ' || ch=='\t') {
- xungetc(ch);
- inxtr[cread]='\0';
- return cread;
- }
- }
- inxtr[cread++]=ch;
- } while (true);
- }
- inline int readtochar(char sep) {
- // Reads to next instance of character 'sep'
- // Character sep is lost to the stream, but not stored as part of the input string
- // Newline or eof also terminate input
- // Returns number of characters read
- int cread=0;
- char ch;
- iseol=false;
- do {
- ch=xgetc();
- if (xfeof() || ch=='\n') {
- iseol=true;
- inxtr[cread]='\0';
- return cread;
- }
- if (ch==sep) {
- inxtr[cread]='\0';
- return cread;
- }
- inxtr[cread++]=ch;
- } while (true);
- }
- inline void skipwhitespace() {
- // Reads to next non-white-space character
- // Newline or eof also terminate input
- iseol=false;
- char ch;
- do {
- ch=xgetc();
- if (xfeof() || ch=='\n') {
- iseol=true;
- return;
- }
- if (ch!=' ' && ch!='\t') {
- xungetc(ch);
- return;
- }
- } while (true);
- }
- bool readfloat(int nitem,int& width,int dec,int exp,char termch,double* parg) {
- int i,j,len;
- char ch;
- bool havesign;
- bool negcard;
- bool haveexpsign;
- bool havedec;
- bool haveexp;
- bool negexp;
- double cardpart;
- double decpart;
- double decmul;
- double value;
- int exppart;
- int posdec;
- int posexp;
- bool breakcomma=termch==',';
- if (termch==',' || termch=='$') termch=0;
- do {
- if (xfeof()) return false;
- havesign=false;
- negcard=false;
- haveexpsign=false;
- negexp=false;
- havedec=false;
- haveexp=false;
- cardpart=0;
- decpart=0;
- decmul=1.0;
- exppart=0;
- if (width) {
- readfixedwidth(width);
- }
- else { // no width specified, read to next white space or end of line
- if (!iseol) skipwhitespace();
- if (iseol) {
- *parg++=0.0;
- goto next;
- }
- if (termch) readtochar(termch);
- else readtowhitespace(breakcomma);
- }
- len=inxtr.len();
- if (dec>=0 || exp>=0) { // strip non-numeric characters from string
- i=j=0;
- ch=inxtr[j];
- posdec=posexp=-1;
- while (ch) {
- if (ch=='e' || ch=='E') {
- if (posexp<0) {
- inxtr[i++]=inxtr[j++];
- posexp=i;
- }
- else j++;
- }
- else if (ch=='.') {
- if (posexp<0 && posdec<0) {
- inxtr[i++]=inxtr[j++];
- posdec=i;
- }
- else j++;
- }
- else if (ch=='-' || (ch>='0' && ch<='9'))
- inxtr[i++]=inxtr[j++];
- else j++;
- ch=inxtr[j];
- }
- inxtr[i]='\0';
- len=inxtr.len();
- if (exp>=0 && posexp<0 && posdec<len-exp) posexp=len-exp;
- else posexp=len;
- if (dec>=0 && posdec<0) posdec=posexp-dec;
- else posdec=posexp;
- }
- else posdec=posexp=len;
- len=inxtr.len();
- for (i=0;i<len;i++) {
- ch=inxtr[i];
- if (i<posdec) { // cardinal part
- if (ch=='-' && !havesign) negcard=true;
- else if (ch=='.' && !havedec && !haveexp) {
- posdec=i+1;
- if (posexp<posdec) posexp=posdec;
- havedec=true;
- }
- else if ((ch=='E' || ch=='e') && !haveexp) {
- posexp=i+1;
- posdec=i+1;
- haveexp=true;
- }
- else if (ch>='0' && ch<='9') {
- havesign=true;
- cardpart=cardpart*10.0+(double)(ch-'0');
- }
- }
- else if (i<posexp) { // decimal part
- if ((ch=='E' || ch=='e') && !haveexp) {
- posexp=i+1;
- posdec=i+1;
- haveexp=true;
- }
- else if (ch>='0' && ch<='9') {
- decmul/=10.0;
- decpart+=(double)(ch-'0')*decmul;
- }
- }
- else { // exponent part
- if (ch=='-' && !haveexpsign) negexp=true;
- else if (ch>='0' && ch<='9') {
- haveexpsign=true;
- exppart=exppart*10+(ch-'0');
- }
- }
- }
- if (negcard)
- value=-cardpart-decpart;
- else
- value=cardpart+decpart;
- if (exppart) {
- if (negexp)
- inxtr.printf("1E-%d",exppart);
- else
- inxtr.printf("1E%d",exppart);
- value*=inxtr.num();
- }
- *parg++=value;
- next:
- nitem--;
- } while (nitem>0);
- return true;
- }
- bool readint(int& nitem,int& width,char termch,int* parg) {
- bool havesign;
- bool neg;
- int value;
- int len,i;
- char ch;
- bool breakcomma=termch==',';
- if (termch==',' || termch=='$') termch=0;
- do {
- if (xfeof()) return false;
- havesign=false;
- neg=false;
- value=0;
- if (width) {
- readfixedwidth(width);
- }
- else { // no width specified, read to next white space or end of line
- if (!iseol) skipwhitespace();
- if (iseol) {
- *parg++=0;
- goto next;
- }
- if (termch) readtochar(termch);
- else readtowhitespace(breakcomma);
- }
- len=inxtr.len();
- for (i=0;i<len;i++) {
- ch=inxtr[i];
- if (ch=='-' && !havesign) {
- havesign=true;
- neg=true;
- }
- else if (ch>='0' && ch<='9') {
- havesign=true;
- value=value*10+ch-'0';
- }
- }
- if (neg) value=-value;
- *parg++=value;
- next:
- nitem--;
- } while (nitem>0);
- return true;
- }
- bool readchar(int nitem,int& width,char termch,xtring* parg,bool read_to_eol) {
- bool nomulti=nitem>1 && width<0;
- bool breakcomma=termch==',';
- if (termch==',' || termch=='$') termch=0;
- do {
- if (xfeof()) return false;
- if (width) {
- readfixedwidth(width);
- }
- else {
- if (!iseol) skipwhitespace();
- if (iseol) {
- *parg++="";
- goto next;
- }
- if (termch) readtochar(termch);
- else if (read_to_eol) readtoeol(breakcomma);
- else readtowhitespace(breakcomma);
- }
- *parg++=inxtr;
- next:
- nitem--;
- while (nomulti && nitem>0) {
- // Disallow multiple strings if width not specified
- // Set extra arguments to blank
- *parg++="";
- }
- } while (nitem>0);
- return true;
- }
- bool readfor(FILE* in, const char* fmt, ...) {
- va_list v;
- va_start(v,fmt);
- bool waitwidth=false;
- bool waitfloat=false;
- bool waitdec=false;
- bool waitexp=false;
- bool waitint=false;
- bool waitchar=false;
- bool waitcomma=false;
- bool croff=false;
- bool read_to_eol=false;
- const char* pchar = fmt;
- int nitem=0;
- int width=0;
- int dec=0;
- int exp=0;
- iseol=false;
- pin=∈
- cbuf=0;
- while (*pchar) {
- if (*pchar!=' ') {
- if (*pchar!='$' && *pchar!='#') croff=read_to_eol=false;
- else if (*pchar=='$') croff=true;
- else if (*pchar=='#') read_to_eol=true;
- if (waitwidth) {
- if (*pchar>='0' && *pchar<='9') { // width specifier
- width=width*10+*pchar-'0';
- }
- else if (*pchar=='.' && waitfloat) {
- waitdec=true;
- waitwidth=false;
- }
- else if ((*pchar=='e' || *pchar=='E') && waitfloat) {
- dec=0;
- waitexp=true;
- waitwidth=false;
- }
- else if (*pchar=='/') {
- if (waitfloat) {
- if (!readfloat(nitem,width,-1,-1,0,va_arg(v,double*))) return false;
- waitfloat=false;
- nitem=0;
- width=0;
- }
- else if (waitint) {
- if (!readint(nitem,width,0,va_arg(v,int*))) return false;
- waitint=false;
- nitem=0;
- width=0;
- }
- else {
- if (!readchar(nitem,width,0,va_arg(v,xtring*),read_to_eol)) return false;
- waitchar=false;
- nitem=0;
- width=0;
- }
- if (!iseol) readtoeol(false);
- iseol=false;
- waitwidth=false;
- }
- else if (waitfloat) {
- if (!readfloat(nitem,width,-1,-1,*pchar,va_arg(v,double*))) return false;
- waitfloat=false;
- waitwidth=false;
- nitem=0;
- width=0;
- }
- else if (waitint) {
- if (!readint(nitem,width,*pchar,va_arg(v,int*))) return false;
- waitint=false;
- waitwidth=false;
- nitem=0;
- width=0;
- }
- else {
- if (!readchar(nitem,width,*pchar,va_arg(v,xtring*),read_to_eol)) return false;
- waitchar=false;
- waitwidth=false;
- nitem=0;
- width=0;
- }
- }
- else if (waitdec) {
- if (*pchar>='0' && *pchar<='9') { // decimal places specifier
- dec=dec*10+*pchar-'0';
- }
- else if (*pchar=='e' || *pchar=='E') {
- waitexp=true;
- waitdec=false;
- }
- else if (*pchar=='/') {
- if (!readfloat(nitem,width,dec,-1,0,va_arg(v,double*))) return false;
- if (!iseol) readtoeol(false);
- iseol=false;
- waitdec=false;
- waitfloat=false;
- nitem=0;
- width=0;
- dec=0;
- }
- else {
- if (!readfloat(nitem,width,dec,-1,*pchar,va_arg(v,double*))) return false;
- waitdec=false;
- waitfloat=false;
- nitem=0;
- width=0;
- dec=0;
- }
- }
- else if (waitexp) {
- if (*pchar>='0' && *pchar<='9') { // exponent width specifier
- exp=exp*10+*pchar-'0';
- }
- else if (*pchar=='/') {
- if (!readfloat(nitem,width,dec,exp,0,va_arg(v,double*))) return false;
- if (!iseol) readtoeol(false);
- iseol=false;
- waitexp=false;
- waitfloat=false;
- nitem=0;
- width=0;
- dec=0;
- exp=0;
- }
- else {
- if (!readfloat(nitem,width,dec,exp,*pchar,va_arg(v,double*))) return false;
- waitexp=false;
- waitfloat=false;
- nitem=0;
- width=0;
- dec=0;
- exp=0;
- }
- }
- else if (waitcomma) {
- waitcomma=false;
- }
- else {
- if (*pchar>='0' && *pchar<='9') { // number of items specifier
- nitem=nitem*10+*pchar-'0';
- }
- else if (*pchar=='f' || *pchar=='F') { // floating point number
- waitfloat=true;
- waitwidth=true;
- }
- else if (*pchar=='i' || *pchar=='I') { // integer
- waitint=true;
- waitwidth=true;
- }
- else if (*pchar=='A' || *pchar=='a') { // character string
- waitchar=true;
- waitwidth=true;
- }
- else if (*pchar=='/') { // to end of line
- readtoeol(false);
- iseol=false;
- }
- else if (*pchar=='X' || *pchar=='x') { // skip characters
- readfixedwidth(nitem);
- nitem=0;
- waitcomma=true;
- }
- else if (*pchar!='$') { // take any other character (including a comma) as a separator specifier
- readtochar(*pchar);
- }
- }
- }
- pchar++;
- }
- if (waitfloat) {
- if (waitexp) {
- if (!readfloat(nitem,width,dec,exp,0,va_arg(v,double*))) return false;
- }
- else if (waitdec) {
- if (!readfloat(nitem,width,dec,-1,0,va_arg(v,double*))) return false;
- }
- else {
- if (!readfloat(nitem,width,-1,-1,0,va_arg(v,double*))) return false;
- }
- }
- else if (waitint) {
- if (!readint(nitem,width,0,va_arg(v,int*))) return false;
- }
- else if (waitchar) {
- if (!readchar(nitem,width,0,va_arg(v,xtring*),read_to_eol)) return false;
- }
- if (!iseol && !croff) readtoeol(false);
- return true;
- }
- void formatf(xtring& output,char* format,va_list& v) {
- const int MINBUF=100;
- char* pchar;
- xtring sect;
- xtring fspec;
- xtring wspec;
- xtring buffer(MINBUF);
- char* pfmt=(char*)format;
- int i;
- char waitspec=0,readspec=0,readwidth,havewidth;
- output="";
- i=0;
- while (*pfmt) {
- if (waitspec) {
- if ((*pfmt>='0' && *pfmt<='9') || *pfmt=='-' || *pfmt=='+' || *pfmt==' ' ||
- *pfmt=='#' || *pfmt=='h' || *pfmt=='l' || *pfmt=='I' || *pfmt=='L' ||
- *pfmt=='c' || *pfmt=='C' || *pfmt=='d' || *pfmt=='i' || *pfmt=='o' ||
- *pfmt=='u' || *pfmt=='x' || *pfmt=='X' || *pfmt=='e' || *pfmt=='E' ||
- *pfmt=='f' || *pfmt=='g' || *pfmt=='G' || *pfmt=='n' || *pfmt=='p' ||
- *pfmt=='s' || *pfmt=='S' || *pfmt=='.') {
- readspec=1;
- havewidth=0;
- readwidth=0;
- wspec="0";
- fspec="%";
- pfmt--;
- }
- else output+=*pfmt;
- waitspec=0;
- }
- else if (readspec) {
- if (*pfmt!='*') fspec+=*pfmt;
- if (readwidth) {
- if (*pfmt>='0' && *pfmt<='9') wspec+=*pfmt;
- else {
- readwidth=0;
- havewidth=1;
- }
- }
- else if (*pfmt>='0' && *pfmt<='9' && !havewidth) {
- wspec=*pfmt;
- readwidth=1;
- }
- else if (*pfmt=='*' && !havewidth) {
- wspec.reserve(MINBUF);
- sprintf(wspec,"%d",va_arg(v,int));
- fspec+=wspec;
- havewidth=1;
- }
- else if (*pfmt!='-' && *pfmt!='+' && *pfmt!=' ' && *pfmt!='#') {
- havewidth=1;
- }
- if (*pfmt=='c' || *pfmt=='C' || *pfmt=='d' || *pfmt=='i' || *pfmt=='o' ||
- *pfmt=='u' || *pfmt=='x' || *pfmt=='X') {
- buffer.reserve((unsigned long)(MINBUF+wspec.num()));
- sprintf(buffer,fspec,va_arg(v,int));
- output+=buffer;
- readspec=0;
- }
- else if (*pfmt=='e' || *pfmt=='E' || *pfmt=='f' || *pfmt=='g' ||
- *pfmt=='G') {
- buffer.reserve((unsigned long)(MINBUF+wspec.num()));
- sprintf(buffer,fspec,va_arg(v,double));
- output+=buffer;
- readspec=0;
- }
- else if (*pfmt=='p') {
- buffer.reserve((unsigned long)(MINBUF+wspec.num()));
- sprintf(buffer,fspec,va_arg(v,void*));
- output+=buffer;
- readspec=0;
- }
- else if (*pfmt=='s' || *pfmt=='S') {
- pchar=va_arg(v,char*);
- buffer.reserve((unsigned long)(strlen(pchar)+wspec.num()));
- sprintf(buffer,fspec,pchar);
- output+=buffer;
- readspec=0;
- }
- }
- else if (*pfmt=='%') waitspec=1;
- else {
- sect[i++]=*pfmt;
- if (*(pfmt+1)=='%' || !*(pfmt+1)) {
- sect[i]='\0';
- output+=sect;
- i=0;
- }
- }
- pfmt++;
- }
- }
- bool fileexists(const xtring& filename) {
- // Returns true if filename exists
- FILE* handle;
- handle=fopen(filename,"r+t");
- if (!handle) return false;
- fclose(handle);
- return true;
- }
|