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/util.cc |
Initial commit
Diffstat (limited to 'graphics/asymptote/util.cc')
-rw-r--r-- | graphics/asymptote/util.cc | 444 |
1 files changed, 444 insertions, 0 deletions
diff --git a/graphics/asymptote/util.cc b/graphics/asymptote/util.cc new file mode 100644 index 0000000000..2d66fb2316 --- /dev/null +++ b/graphics/asymptote/util.cc @@ -0,0 +1,444 @@ +/***** + * util.cc + * John Bowman + * + * A place for useful utility functions. + *****/ + +#ifdef __CYGWIN__ +#define _POSIX_C_SOURCE 200809L +#endif + +#include <cassert> +#include <iostream> +#include <cstdio> +#include <cfloat> +#include <sstream> +#include <cerrno> +#include <sys/wait.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <cstring> +#include <algorithm> + +#include "util.h" +#include "settings.h" +#include "errormsg.h" +#include "camperror.h" +#include "interact.h" + +using namespace settings; + +bool False=false; + +namespace vm { +void error(const char* message); +} + +#if __GNUC__ +#include <cxxabi.h> +string demangle(const char *s) +{ + int status; + char *demangled = abi::__cxa_demangle(s,NULL,NULL,&status); + if (status == 0 && demangled) { + string str(demangled); + free(demangled); + return str; + } else if (status == -2) { + free(demangled); + return s; + } else { + free(demangled); + return string("Unknown(") + s + ")"; + } +} +#else +string demangle(const char* s) +{ + return s; +} +#endif + +char *Strdup(string s) +{ + size_t size=s.size()+1; + char *dest=new(UseGC) char[size]; + std::memcpy(dest,s.c_str(),size*sizeof(char)); + return dest; +} + +char *StrdupNoGC(string s) +{ + size_t size=s.size()+1; + char *dest=new char[size]; + std::memcpy(dest,s.c_str(),size*sizeof(char)); + return dest; +} + +char *StrdupMalloc(string s) +{ + size_t size=s.size()+1; + char *dest=(char *) std::malloc(size); + std::memcpy(dest,s.c_str(),size*sizeof(char)); + return dest; +} + +string stripDir(string name) +{ + size_t p; +#ifdef __MSDOS__ + p=name.rfind('\\'); + if(p < string::npos) name.erase(0,p+1); +#endif + p=name.rfind('/'); + if(p < string::npos) name.erase(0,p+1); + return name; +} + +string stripFile(string name) +{ + size_t p; + bool dir=false; +#ifdef __MSDOS__ + p=name.rfind('\\'); + if(p < string::npos) { + dir=true; + while(p > 0 && name[p-1] == '\\') --p; + name.erase(p+1); + } +#endif + p=name.rfind('/'); + if(p < string::npos) { + dir=true; + while(p > 0 && name[p-1] == '/') --p; + name.erase(p+1); + } + + return dir ? name : ""; +} + +string stripExt(string name, const string& ext) +{ + string suffix="."+ext; + size_t p=name.rfind(suffix); + size_t n=suffix.length(); + if(n == 1 || p == name.length()-n) + return name.substr(0,p); + else return name; +} + +void backslashToSlash(string& s) +{ + size_t p; + while((p=s.find('\\')) < string::npos) + s[p]='/'; +} + +void spaceToUnderscore(string& s) +{ + size_t p; + while((p=s.find(' ')) < string::npos) + s[p]='_'; +} + +string Getenv(const char *name, bool msdos) +{ + char *s=getenv(name); + if(!s) return ""; + string S=string(s); + if(msdos) backslashToSlash(S); + return S; +} + +void writeDisabled() +{ + camp::reportError("Write to other directories disabled; override with option -globalwrite"); +} + +string cleanpath(string name) +{ + string dir=stripFile(name); + name=stripDir(name); + spaceToUnderscore(name); + return dir+name; +} + +string outpath(string name) +{ + bool global=globalwrite(); + string dir=stripFile(name); + if(global && !dir.empty()) return name; + string outdir=stripFile(outname()); + if(!(global || dir.empty() || dir == outdir)) writeDisabled(); + return outdir+stripDir(name); +} + +string buildname(string name, string suffix, string aux) +{ + name=stripExt(outpath(name),defaultformat())+aux; + if(!suffix.empty()) name += "."+suffix; + return name; +} + +string auxname(string filename, string suffix) +{ + return buildname(filename,suffix,"_"); +} + +sighandler_t Signal(int signum, sighandler_t handler) +{ + struct sigaction action,oldaction; + action.sa_handler=handler; + sigemptyset(&action.sa_mask); + action.sa_flags=0; + return sigaction(signum,&action,&oldaction) == 0 ? oldaction.sa_handler : + SIG_ERR; +} + +void push_split(mem::vector<string>& a, const string& S) +{ + const char *p=S.c_str(); + string s; + char c; + while((c=*(p++))) { + if(c == ' ') { + if(s.size() > 0) { + a.push_back(s); + s.clear(); + } + } else s += c; + } + if(s.size() > 0) + a.push_back(s); +} + +char **args(const mem::vector<string>& s, bool quiet) +{ + size_t count=s.size(); + + char **argv=NULL; + argv=new char*[count+1]; + for(size_t i=0; i < count; ++i) + argv[i]=StrdupNoGC(s[i]); + + if(!quiet && settings::verbose > 1) { + cerr << argv[0]; + for(size_t i=1; i < count; ++i) cerr << " " << argv[i]; + cerr << endl; + } + + argv[count]=NULL; + return argv; +} + +void execError(const char *command, const char *hint, const char *application) +{ + cerr << "Cannot execute " << command << endl; + if(*application == 0) application=hint; + if(hint) { + string s=string(hint); + transform(s.begin(), s.end(), s.begin(), toupper); + cerr << "Please put in a file " << getSetting<string>("config") + << ": " << endl << endl + << "import settings;" << endl + << hint << "=\"LOCATION\";" << endl << endl + << "where LOCATION specifies the location of " + << application << "." << endl << endl + << "Alternatively, set the environment variable ASYMPTOTE_" << s + << endl << "or use the command line option -" << hint + << "=\"LOCATION\". For further details, see" << endl + << "http://asymptote.sourceforge.net/doc/Configuring.html" << endl + << "http://asymptote.sourceforge.net/doc/Search-paths.html" << endl; + } +} + +// quiet: 0=none; 1=suppress stdout; 2=suppress stdout+stderr. +int System(const mem::vector<string> &command, int quiet, bool wait, + const char *hint, const char *application, int *ppid) +{ + int status; + + cout.flush(); // Flush stdout to avoid duplicate output. + + char **argv=args(command); + + int pid=fork(); + if(pid == -1) + camp::reportError("Cannot fork process"); + + if(pid == 0) { + if(interact::interactive) signal(SIGINT,SIG_IGN); + if(quiet) { + static int null=creat("/dev/null",O_WRONLY); + close(STDOUT_FILENO); + dup2(null,STDOUT_FILENO); + if(quiet == 2) { + close(STDERR_FILENO); + dup2(null,STDERR_FILENO); + } + } + if(argv) { + execvp(argv[0],argv); + execError(argv[0],hint,application); + _exit(-1); + } + } + + if(ppid) *ppid=pid; + for(;;) { + if(waitpid(pid, &status, wait ? 0 : WNOHANG) == -1) { + if(errno == ECHILD) return 0; + if(errno != EINTR) { + if(quiet < 2) { + ostringstream msg; + msg << "Command failed: "; + for(size_t i=0; i < command.size(); ++i) msg << command[i] << " "; + camp::reportError(msg); + } + } + } else { + if(!wait) return 0; + if(WIFEXITED(status)) { + if(argv) { + char **p=argv; + char *s; + while((s=*(p++)) != NULL) + delete [] s; + delete [] argv; + } + return WEXITSTATUS(status); + } else { + if(quiet < 2) { + ostringstream msg; + msg << "Command exited abnormally: "; + for(size_t i=0; i < command.size(); ++i) msg << command[i] << " "; + camp::reportError(msg); + } + } + } + } +} + +string stripblanklines(const string& s) +{ + string S=string(s); + bool blank=true; + const char *t=S.c_str(); + size_t len=S.length(); + + for(size_t i=0; i < len; i++) { + if(t[i] == '\n') { + if(blank) S[i]=' '; + else blank=true; + } else if(t[i] != '\t' && t[i] != ' ') blank=false; + } + return S; +} + +char *startpath=NULL; + +void noPath() +{ + camp::reportError("Cannot get current path"); +} + +char *getPath(char *p) +{ +#ifdef MAXPATHLEN + static size_t size = MAXPATHLEN; +#else + static size_t size = 1024; +#endif + if(!p) p=new(UseGC) char[size]; + if(!p) noPath(); + else while(getcwd(p,size) == NULL) { + if(errno == ERANGE) { + size *= 2; + p=new(UseGC) char[size]; + } else {noPath(); p=NULL;} + } + return p; +} + +const char *setPath(const char *s, bool quiet) +{ + if(startpath == NULL) startpath=getPath(startpath); + if(s == NULL || *s == 0) s=startpath; + int rc=chdir(s); + if(rc != 0) { + ostringstream buf; + buf << "Cannot change to directory '" << s << "'"; + camp::reportError(buf); + } + char *p=getPath(); + if(p && (!interact::interactive || quiet) && verbose > 1) + cout << "cd " << p << endl; + return p; +} + +void push_command(mem::vector<string>& a, const string& s) +{ + a.push_back(s); +#ifdef __MSDOS__ + if(s == "cmd") { + a.push_back("/c"); + a.push_back("start"); + a.push_back("\"\""); + } +#endif +} + +void popupHelp() { + // If the popped-up help is already running, pid stores the pid of the viewer. + static int pid=0; + + // Status is ignored. + static int status=0; + + // If the help viewer isn't running (or its last run has termined), launch the + // viewer again. + if (pid==0 || (waitpid(pid, &status, WNOHANG) == pid)) { + mem::vector<string> cmd; + push_command(cmd,getSetting<string>("pdfviewer")); + string viewerOptions=getSetting<string>("pdfviewerOptions"); + if(!viewerOptions.empty()) + cmd.push_back(viewerOptions); + cmd.push_back(docdir+dirsep+"asymptote.pdf"); + status=System(cmd,0,false,"pdfviewer","your PDF viewer",&pid); + } +} + +const char *intrange="integer argument is outside valid range"; +const char *uintrange="integer argument is outside valid unsigned range"; + +unsigned unsignedcast(Int n) +{ + if(n < 0 || n/2 > INT_MAX) + vm::error(uintrange); + return (unsigned) n; +} + +unsignedInt unsignedIntcast(Int n) +{ + if(n < 0) + vm::error(uintrange); + return (unsignedInt) n; +} + +int intcast(Int n) +{ + if(Abs(n) > INT_MAX) + vm::error(intrange); + return (int) n; +} + +Int Intcast(unsignedInt n) +{ + if(n > (unsignedInt) Int_MAX) + vm::error(intrange); + return (Int) n; +} |