diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /graphics/asymptote/runstring.in |
Initial commit
Diffstat (limited to 'graphics/asymptote/runstring.in')
-rw-r--r-- | graphics/asymptote/runstring.in | 453 |
1 files changed, 453 insertions, 0 deletions
diff --git a/graphics/asymptote/runstring.in b/graphics/asymptote/runstring.in new file mode 100644 index 0000000000..a8b0e68bce --- /dev/null +++ b/graphics/asymptote/runstring.in @@ -0,0 +1,453 @@ +/***** + * runstring.in + * + * Runtime functions for string operations. + * + *****/ + +stringarray2* => stringArray2() + +#include <cfloat> +#include <cstring> +#include <algorithm> + +#include "array.h" + +using namespace camp; +using namespace vm; +using namespace settings; + +typedef array stringarray; +typedef array stringarray2; + +using types::stringArray; +using types::stringArray2; + +namespace types { +extern const char *names[]; +} + +namespace run { +extern string emptystring; +} + +static const string defaulttimeformat=string("%a %b %d %T %Z %Y"); +#ifdef HAVE_STRFTIME +static const size_t nTime=256; +static char Time[nTime]; +#endif + +void checkformat(const char *ptr, bool intformat) +{ + while(*ptr != '\0') { + if(*ptr != '%') /* While we have regular characters, print them. */ + ptr++; + else { /* We've got a format specifier. */ + ptr++; + + while(*ptr && strchr ("-+ #0'I", *ptr)) /* Move past flags. */ + ptr++; + + if(*ptr == '*') + ptr++; + else while(isdigit(*ptr)) /* Handle explicit numeric value. */ + ptr++; + + if(*ptr == '.') { + ptr++; /* Go past the period. */ + if(*ptr == '*') { + ptr++; + } else + while(isdigit(*ptr)) /* Handle explicit numeric value. */ + ptr++; + } + while(*ptr && strchr ("hlL", *ptr)) + ptr++; + + if(*ptr == '%') {++ptr; continue;} + else if(*ptr != '\0') { + if(intformat) { + switch(*ptr) { + case 'd': + case 'i': + case 'o': + case 'u': + case 'x': + case 'X': + case 'c': + break; + default: + ostringstream buf; + buf << "Invalid format '" << *ptr << "' for type " + << types::names[types::ty_Int]; + error(buf); + break; + } + } else { + switch(*ptr) { + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + break; + default: + ostringstream buf; + buf << "Invalid format '" << *ptr << "' for type " + << types::names[types::ty_real]; + error(buf); + break; + } + } + } + break; // Only one argument is allowed. + } /* End of else statement */ + } +} + +// Autogenerated routines: + + +// String operations + +string :emptyString() +{ + return emptystring; +} + +Int length(string *s) +{ + return (Int) s->length(); +} + +Int find(string *s, string t, Int pos=0) +{ + size_t n=s->find(t,pos); + return n == string::npos ? (Int) -1 : (Int) n; +} + +Int rfind(string *s, string t, Int pos=-1) +{ + size_t n=s->rfind(t,pos); + return n == string::npos ? (Int) -1 : (Int) n; +} + +string reverse(string s) +{ + reverse(s.begin(),s.end()); + return s; +} + +string insert(string s, Int pos, string t) +{ + if ((size_t) pos < s.length()) + return s.insert(pos,t); + return s; +} + +string substr(string* s, Int pos, Int n=-1) +{ + if ((size_t) pos < s->length()) + return s->substr(pos,n); + return emptystring; +} + +string erase(string s, Int pos, Int n) +{ + if ((size_t) pos < s.length()) + return s.erase(pos,n); + return s; +} + +string downcase(string s) +{ + std::transform(s.begin(),s.end(),s.begin(),tolower); + return s; +} + +string upcase(string s) +{ + std::transform(s.begin(),s.end(),s.begin(),toupper); + return s; +} + +// returns a string constructed by translating all occurrences of the string +// from in an array of string pairs {from,to} to the string to in string s. +string replace(string *S, stringarray2 *translate) +{ + size_t size=checkArray(translate); + for(size_t i=0; i < size; i++) { + array *a=read<array*>(translate,i); + checkArray(a); + } + const char *p=S->c_str(); + ostringstream buf; + while(*p) { + for(size_t i=0; i < size;) { + array *a=read<array*>(translate,i); + size_t size2=checkArray(a); + if(size2 != 2) + error("translation table entry must be an array of length 2"); + string* from=read<string*>(a,0); + size_t len=from->length(); + if(strncmp(p,from->c_str(),len) != 0) {i++; continue;} + buf << read<string>(a,1); + p += len; + if(*p == 0) return buf.str(); + i=0; + } + buf << *(p++); + } + return buf.str(); +} + +string format(string *format, Int x, string locale=emptystring) +{ + ostringstream out; + const char *p0=format->c_str(); + checkformat(p0,true); + + const char *p=p0; + const char *start=NULL; + while(*p != 0) { + char curr=*p; + if(curr == '%') { + p++; + if(*p != '%') {start=p-1; break;} + } + out << *(p++); + } + + if(!start) return out.str(); + + // Allow at most 1 argument + while(*p != 0) { + if(*p == '*' || *p == '$') return out.str(); + if(isupper(*p) || islower(*p)) {p++; break;} + p++; + } + + string f=format->substr(start-p0,p-start); + + const char *oldlocale=NULL; + + if(!locale.empty()) { + oldlocale=setlocale(LC_ALL,NULL); + if(oldlocale) oldlocale=StrdupNoGC(oldlocale); + setlocale(LC_ALL,locale.c_str()); + } + + Int size=snprintf(NULL,0,f.c_str(),x)+1; + if(size < 1) size=255; // Workaround for non-C99 compliant systems. + char *buf=new char[size]; + snprintf(buf,size,f.c_str(),x); + + out << string(buf); + out << p; + + delete[] buf; + + if(oldlocale) { + setlocale(LC_ALL,oldlocale); + delete[] oldlocale; + } + + return out.str(); +} + +string format(string *format, bool forcemath=false, string separator, real x, + string locale=emptystring) +{ + if(*format == "%") return ""; // Temporary workaround for github Issue #29. + + bool tex=getSetting<string>("tex") != "none"; + bool texify=forcemath; + ostringstream out; + + const char *p0=format->c_str(); + checkformat(p0,false); + + const char *phantom="\\phantom{+}"; + + const char *p=p0; + const char *start=NULL; + char prev=0; + while(*p != 0) { + char curr=*p; + if(tex && curr == '$' && prev != '\\') texify=true; + prev=curr; + if(curr == '%') { + p++; + if(*p != '%') {start=p-1; break;} + } + out << *(p++); + } + + if(!start) return out.str(); + + // Allow at most 1 argument + while(*p != 0) { + if(*p == '*' || *p == '$') return out.str(); + if(isupper(*p) || islower(*p)) {p++; break;} + p++; + } + + const char *tail=p; + string f=format->substr(start-p0,tail-start); + + const char *oldlocale=NULL; + if(!locale.empty()) { + oldlocale=setlocale(LC_ALL,NULL); + if(oldlocale) oldlocale=StrdupNoGC(oldlocale); + setlocale(LC_ALL,locale.c_str()); + } + + Int size=snprintf(NULL,0,f.c_str(),x)+1; + if(size < 1) size=255; // Workaround for non-C99 compliant systems. + char *buf=new char[size]; + snprintf(buf,size,f.c_str(),x); + + bool trailingzero=f.find("#") < string::npos; + bool plus=f.find("+") < string::npos; + bool space=f.find(" ") < string::npos; + + char *q=buf; // beginning of formatted number + + if(*q == ' ' && texify) { + out << phantom; + q++; + } + + const char decimal=*(localeconv()->decimal_point); + + // Remove any spurious sign + if(*q == '-' || *q == '+') { + p=q+1; + bool zero=true; + while(*p != 0) { + if(!isdigit(*p) && *p != decimal) break; + if(isdigit(*p) && *p != '0') {zero=false; break;} + p++; + } + if(zero) { + q++; + if((plus || space) && texify) out << phantom; + } + } + + const char *r=p=q; + bool dp=false; + while(*r != 0 && (isspace(*r) || isdigit(*r) || *r == decimal \ + || *r == '+' || *r == '-')) { + if(*r == decimal) dp=true; + r++; + } + if(dp) { // Remove trailing zeros and/or decimal point + r--; + unsigned n=0; + while(r > q && *r == '0') {r--; n++;} + if(*r == decimal) {r--; n++;} + while(q <= r) out << *(q++); + if(!trailingzero) q += n; + } + + bool zero=(r == p && *r == '0') && !trailingzero; + + // Translate "E+/E-/e+/e-" exponential notation to TeX + while(*q != 0) { + if(texify && (*q == 'E' || *q == 'e') && + (*(q+1) == '+' || *(q+1) == '-')) { + if(!zero) out << separator << "10^{"; + bool plus=(*(q+1) == '+'); + q++; + if(plus) q++; + if(*q == '-') out << *(q++); + while(*q == '0' && (zero || isdigit(*(q+1)))) q++; + while(isdigit(*q)) out << *(q++); + if(!zero) + out << "}"; + break; + } + out << *(q++); + } + + while(*tail != 0) + out << *(tail++); + + delete[] buf; + + if(oldlocale) { + setlocale(LC_ALL,oldlocale); + delete[] oldlocale; + } + + return out.str(); +} + +Int hex(string s) +{ + istringstream is(s); + is.setf(std::ios::hex,std::ios::basefield); + Int value; + if(is && is >> value && ((is >> std::ws).eof())) return value; + ostringstream buf; + buf << "invalid hexadecimal cast from string \"" << s << "\""; + error(buf); +} + +Int ascii(string s) +{ + return s.empty() ? -1 : (unsigned char) s[0]; +} + +string string(Int x) +{ + ostringstream buf; + buf << x; + return buf.str(); +} + +string string(real x, Int digits=DBL_DIG) +{ + ostringstream buf; + buf.precision(digits); + buf << x; + return buf.str(); +} + +string time(string format=defaulttimeformat) +{ +#ifdef HAVE_STRFTIME + const time_t bintime=time(NULL); + if(!strftime(Time,nTime,format.c_str(),localtime(&bintime))) return ""; + return Time; +#else + return format; +#endif +} + +string time(Int seconds, string format=defaulttimeformat) +{ +#ifdef HAVE_STRFTIME + const time_t bintime=seconds; + if(!strftime(Time,nTime,format.c_str(),localtime(&bintime))) return ""; + return Time; +#else +// Avoid unused variable warning messages + unused(&seconds); + return format; +#endif +} + +Int seconds(string t=emptystring, string format=emptystring) +{ +#if defined(HAVE_STRPTIME) + const time_t bintime=time(NULL); + tm tm=*localtime(&bintime); + if(t != "" && !strptime(t.c_str(),format.c_str(),&tm)) return -1; + return (Int) mktime(&tm); +#else + return -1; +#endif +} |