diff options
Diffstat (limited to 'Build/source/utils/asymptote/settings.cc')
-rw-r--r-- | Build/source/utils/asymptote/settings.cc | 1820 |
1 files changed, 1820 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/settings.cc b/Build/source/utils/asymptote/settings.cc new file mode 100644 index 00000000000..edd9fec7840 --- /dev/null +++ b/Build/source/utils/asymptote/settings.cc @@ -0,0 +1,1820 @@ +/***** + * settings.cc + * Andy Hammerlindl 2004/05/10 + * + * Declares a list of global variables that act as settings in the system. + *****/ + +#include <iostream> +#include <iomanip> +#include <cstdlib> +#include <cerrno> +#include <sys/stat.h> +#include <cfloat> +#include <locale.h> +#include <unistd.h> +#include <algorithm> + +#include "common.h" + +#if HAVE_GNU_GETOPT_H +#include <getopt.h> +#else +#include "getopt.h" +#endif + +#include "util.h" +#include "settings.h" +#include "interact.h" +#include "locate.h" +#include "lexical.h" +#include "record.h" +#include "env.h" +#include "item.h" +#include "refaccess.h" +#include "pipestream.h" +#include "array.h" + +#include "glrender.h" + +#ifdef HAVE_LIBCURSES +extern "C" { + +#ifdef HAVE_NCURSES_CURSES_H +#include <ncurses/curses.h> +#include <ncurses/term.h> +#elif HAVE_NCURSES_H +#include <ncurses.h> +#include <term.h> +#elif HAVE_CURSES_H +#include <curses.h> +#include <term.h> +#endif +} +#endif + +// Workaround broken curses.h files: +#ifdef clear +#undef clear +#endif +// Workaround broken header file on i386-solaris with g++ 3.4.3. +#ifdef erase +#undef erase +#endif + +using vm::item; + +using trans::itemRefAccess; +using trans::refAccess; +using trans::varEntry; +using vm::array; + +void runFile(const string& filename); + + +namespace settings { + +using camp::pair; + +#ifdef HAVE_LIBGLM +const bool havegl=true; +#else +const bool havegl=false; +#endif + +mode_t mask; + +string systemDir=ASYMPTOTE_SYSDIR; +string defaultPSdriver="ps2write"; +string defaultEPSdriver="eps2write"; +string defaultAsyGL="https://vectorgraphics.github.io/asymptote/base/webgl/asygl-"+ + string(AsyGLVersion)+".js"; + +#ifndef __MSDOS__ + +bool msdos=false; +string HOME="HOME"; +string docdir=ASYMPTOTE_DOCDIR; +const char pathSeparator=':'; +#ifdef __APPLE__ +string defaultPSViewer="open"; +string defaultPDFViewer="open"; +string defaultHTMLViewer="open"; +#else +string defaultPSViewer="gv"; +string defaultPDFViewer="acroread"; +string defaultHTMLViewer="google-chrome"; +#endif +string defaultGhostscript="gs"; +string defaultGhostscriptLibrary=""; +string defaultDisplay="display"; +string defaultAnimate="animate"; +void queryRegistry() {} +const string dirsep="/"; + +#else + +bool msdos=true; +string HOME="USERPROFILE"; +string docdir="c:\\Program Files\\Asymptote"; +const char pathSeparator=';'; +//string defaultPSViewer="gsview32.exe"; +string defaultPSViewer="cmd"; +//string defaultPDFViewer="AcroRd32.exe"; +string defaultPDFViewer="cmd"; +string defaultHTMLViewer="cmd"; +string defaultGhostscript; +string defaultGhostscriptLibrary; +//string defaultDisplay="imdisplay"; +string defaultDisplay="cmd"; +//string defaultAnimate="animate"; +string defaultAnimate="cmd"; +const string dirsep="\\"; + +#include <dirent.h> + +// Use key to look up an entry in the MSWindows registry, respecting wild cards +string getEntry(const string& location, const string& key) +{ + string path="/proc/registry"+location+key; + size_t star; + string head; + while((star=path.find("*")) < string::npos) { + string prefix=path.substr(0,star); + string suffix=path.substr(star+1); + size_t slash=suffix.find("/"); + if(slash < string::npos) { + path=suffix.substr(slash); + suffix=suffix.substr(0,slash); + } else { + path=suffix; + suffix=""; + } + string directory=head+stripFile(prefix); + string file=stripDir(prefix); + DIR *dir=opendir(directory.c_str()); + if(dir == NULL) return ""; + dirent *p; + string rsuffix=suffix; + reverse(rsuffix.begin(),rsuffix.end()); + while((p=readdir(dir)) != NULL) { + string dname=p->d_name; + string rdname=dname; + reverse(rdname.begin(),rdname.end()); + if(dname != "." && dname != ".." && + dname.substr(0,file.size()) == file && + rdname.substr(0,suffix.size()) == rsuffix) { + head=directory+p->d_name; + break; + } + } + if(p == NULL) return ""; + } + std::ifstream fin((head+path).c_str()); + if(fin) { + string s; + getline(fin,s); + size_t end=s.find('\0'); + if(end < string::npos) + return s.substr(0,end); + } + return ""; +} + +// Use key to look up an entry in the MSWindows registry, respecting wild cards +string getEntry(const string& key) +{ + string entry=getEntry("64/HKEY_CURRENT_USER/Software/",key); + if(entry.empty()) entry=getEntry("64/HKEY_LOCAL_MACHINE/SOFTWARE/",key); + if(entry.empty()) entry=getEntry("/HKEY_CURRENT_USER/Software/",key); + if(entry.empty()) entry=getEntry("/HKEY_LOCAL_MACHINE/SOFTWARE/",key); + return entry; +} + +void queryRegistry() +{ + string defaultGhostscriptLibrary=getEntry("GPL Ghostscript/*/GS_DLL"); + if(defaultGhostscriptLibrary.empty()) + defaultGhostscriptLibrary=getEntry("AFPL Ghostscript/*/GS_DLL"); + + string gslib=stripDir(defaultGhostscriptLibrary); + defaultGhostscript=stripFile(defaultGhostscriptLibrary)+ + ((gslib.empty() || gslib.substr(5,2) == "32") ? "gswin32c.exe" : "gswin64c.exe"); + if(defaultPDFViewer != "cmd") + defaultPDFViewer=getEntry("Adobe/Acrobat Reader/*/InstallPath/@")+"\\"+ + defaultPDFViewer; + if(defaultPSViewer != "cmd") + defaultPSViewer=getEntry("Ghostgum/GSview/*")+"\\gsview\\"+defaultPSViewer; + string s; + s=getEntry("Microsoft/Windows/CurrentVersion/App Paths/Asymptote/Path"); + if(!s.empty()) docdir=s; + // An empty systemDir indicates a TeXLive build + if(!systemDir.empty() && !docdir.empty()) + systemDir=docdir; +} + +#endif + +const char PROGRAM[]=PACKAGE_NAME; +const char VERSION[]=PACKAGE_VERSION; +const char BUGREPORT[]=PACKAGE_BUGREPORT; + +// The name of the program (as called). Used when displaying help info. +char *argv0; + +// The verbosity setting, a global variable. +Int verbose; + +// Conserve memory at the expense of speed. +bool compact; + +// Colorspace conversion flags (stored in global variables for efficiency). +bool gray; +bool bw; +bool rgb; +bool cmyk; + +// Disable system calls. +bool safe=true; +// Enable reading from other directories +bool globalRead=true; +// Enable writing to (or changing to) other directories +bool globalWrite=false; + +bool globalwrite() {return globalWrite || !safe;} +bool globalread() {return globalRead || !safe;} + +const string suffix="asy"; +const string guisuffix="gui"; +const string standardprefix="out"; + +string initdir; +string tempdir; +string historyname; + +// Local versions of the argument list. +int argCount = 0; +char **argList = 0; + +typedef ::option c_option; + +types::dummyRecord *settingsModule; + +types::record *getSettingsModule() { + return settingsModule; +} + +void noWarn(const string& s) +{ + array *Warn=getSetting<array *>("suppress"); + size_t size=checkArray(Warn); + if(s.empty()) return; + for(size_t i=0; i < size; i++) + if(vm::read<string>(Warn,i) == s) return; + Warn->push(s); +} + +void Warn(const string& s) +{ + array *Warn=getSetting<array *>("suppress"); + size_t size=checkArray(Warn); + for(size_t i=0; i < size; i++) + if(vm::read<string>(Warn,i) == s) + (*Warn).erase((*Warn).begin()+i,(*Warn).begin()+i+1); +} + +bool warn(const string& s) +{ + if(getSetting<bool>("debug")) return true; + array *Warn=getSetting<array *>("suppress"); + size_t size=checkArray(Warn); + for(size_t i=0; i < size; i++) + if(vm::read<string>(Warn,i) == s) return false; + return true; +} + +// The dictionaries of long options and short options. +struct option; +typedef mem::map<CONST string, option *> optionsMap_t; +optionsMap_t optionsMap; + +typedef mem::map<CONST char, option *> codeMap_t; +codeMap_t codeMap; + +struct option : public gc { + string name; + char code; // Command line option, i.e. 'V' for -V. + bool argument; // If it takes an argument on the command line. This is set + // based on whether argname is empty. + string argname; // The argument name for printing the description. + string desc; // One line description of what the option does. + bool cmdlineonly; // If it is only available on the command line. + string Default; // A string containing an optional default value. + + option(string name, char code, string argname, string desc, + bool cmdlineonly=false, string Default="") + : name(name), code(code), argument(!argname.empty()), argname(argname), + desc(desc), cmdlineonly(cmdlineonly), Default(Default) {} + + virtual ~option() {} + + // Builds this option's contribution to the optstring argument of get_opt(). + virtual string optstring() { + if (code) { + string base; + base.push_back(code); + if(argument) base.push_back(':'); + return base; + } + else return ""; + } + + // Sets the contribution to the longopt array. + virtual void longopt(c_option &o) { + o.name=name.c_str(); + o.has_arg=argument ? 1 : 0; + o.flag=0; + o.val=0; + } + + // Add to the dictionaries of options. + virtual void add() { + optionsMap[name]=this; + if (code) + codeMap[code]=this; + } + + // Set the option from the command-line argument. Return true if the option + // was correctly parsed. + virtual bool getOption() = 0; + + void error(string msg) { + cerr << endl << argv0 << ": "; + if (code) + cerr << "-" << code << " "; + cerr << "(-" << name << ") " << msg << endl; + } + + // The "-f,-outformat format" part of the option. + virtual string describeStart() { + ostringstream ss; + if (code) + ss << "-" << code << ","; + ss << "-" << name; + if (argument) + ss << " " << argname; + return ss.str(); + } + + // Outputs description of the command for the -help option. + virtual void describe() { + // Don't show the option if it has no desciption. + if (!desc.empty()) { + const unsigned WIDTH=22; + string start=describeStart(); + cerr << std::left << std::setw(WIDTH) << start; + if (start.size() >= WIDTH) { + cerr << endl; + cerr << std::left << std::setw(WIDTH) << ""; + } + cerr << " " << desc; + if(cmdlineonly) cerr << "; command-line only"; + if(Default != "") + cerr << " [" << Default << "]"; + cerr << endl; + } + } + + virtual void reset() { + } +}; + +const string noarg; + +struct setting : public option { + types::ty *t; + +private: + trans::permission perm; + bool added; + + // Flag the setting as secure, so that it can only be set on the command-line, + // though it can still be read in Asymptote code. + void secure() { + assert(!added); + perm = trans::RESTRICTED; + } + +public: + setting(string name, char code, string argname, string desc, + types::ty *t, string Default) + : option(name, code, argname, desc, false,Default), + t(t), perm(trans::PUBLIC), added(false) {} + + void reset() = 0; + + virtual trans::access *buildAccess() = 0; + + // Add to the dictionaries of options and to the settings module. + virtual void add() { + assert(!added); + + option::add(); + settingsModule->add(name, t, buildAccess(), perm); + + added=true; + } + + friend void addSecureSetting(setting *s) { + s->secure(); + s->add(); + } +}; + +struct itemSetting : public setting { + item defaultValue; + item value; + + itemSetting(string name, char code, + string argname, string desc, + types::ty *t, item defaultValue, string Default="") + : setting(name, code, argname, desc, t, Default), + defaultValue(defaultValue) {reset();} + + void reset() { + value=defaultValue; + } + + trans::access *buildAccess() { + return new itemRefAccess(&(value)); + } +}; + +item& Setting(string name) { + itemSetting *s=dynamic_cast<itemSetting *>(optionsMap[name]); + if(!s) { + cerr << "Cannot find setting named '" << name << "'" << endl; + exit(-1); + } + return s->value; +} + +struct boolSetting : public itemSetting { + boolSetting(string name, char code, string desc, + bool defaultValue=false) + : itemSetting(name, code, noarg, desc, + types::primBoolean(), (item)defaultValue, + defaultValue ? "true" : "false") {} + + bool getOption() { + value=(item)true; + return true; + } + + option *negation(string name) { + struct negOption : public option { + boolSetting &base; + + negOption(boolSetting &base, string name) + : option(name, 0, noarg, ""), base(base) {} + + bool getOption() { + base.value=(item)false; + return true; + } + }; + return new negOption(*this, name); + } + + void add() { + setting::add(); + negation("no"+name)->add(); + if (code) { + string nocode="no"; nocode.push_back(code); + negation(nocode)->add(); + } + } + + // Set several related boolean options at once. Used for view and trap which + // have batch and interactive settings. + struct multiOption : public option { + typedef mem::list<boolSetting *> setlist; + setlist set; + multiOption(string name, char code, string desc) + : option(name, code, noarg, desc, true) {} + + void add(boolSetting *s) { + set.push_back(s); + } + + void setValue(bool value) { + for (setlist::iterator s=set.begin(); s!=set.end(); ++s) + (*s)->value=(item)value; + } + + bool getOption() { + setValue(true); + return true; + } + + option *negation(string name) { + struct negOption : public option { + multiOption &base; + + negOption(multiOption &base, string name) + : option(name, 0, noarg, ""), base(base) {} + + bool getOption() { + base.setValue(false); + return true; + } + }; + return new negOption(*this, name); + } + + void add() { + option::add(); + negation("no"+name)->add(); + if (code) { + string nocode="no"; nocode.push_back(code); + negation(nocode)->add(); + } + + for (multiOption::setlist::iterator s=set.begin(); s!=set.end(); ++s) + (*s)->add(); + } + }; +}; + +typedef boolSetting::multiOption multiOption; + +struct argumentSetting : public itemSetting { + argumentSetting(string name, char code, + string argname, string desc, + types::ty *t, item defaultValue) + : itemSetting(name, code, argname, desc, t, defaultValue) + { + assert(!argname.empty()); + } +}; + +struct stringSetting : public argumentSetting { + stringSetting(string name, char code, + string argname, string desc, + string defaultValue="") + : argumentSetting(name, code, argname, desc.empty() ? "" : + desc+(defaultValue.empty() ? "" : " ["+defaultValue+"]"), + types::primString(), (item)defaultValue) {} + + bool getOption() { + value=(item)(string)optarg; + return true; + } +}; + +struct userSetting : public argumentSetting { + userSetting(string name, char code, + string argname, string desc, + string defaultValue="") + : argumentSetting(name, code, argname, desc, + types::primString(), (item)defaultValue) {} + + bool getOption() { + string s=vm::get<string>(value)+string(optarg); + s.push_back(';'); + value=(item) s; + return true; + } +}; + +struct warnSetting : public option { + warnSetting(string name, char code, + string argname, string desc) + : option(name, code, argname, desc, true) {} + + bool getOption() { + Warn(string(optarg)); + return true; + } + + option *negation(string name) { + struct negOption : public option { + warnSetting &base; + + negOption(warnSetting &base, string name, string argname) + : option(name, 0, argname, ""), base(base) {} + + bool getOption() { + noWarn(string(optarg)); + return true; + } + }; + return new negOption(*this, name, argname); + } + + void add() { + option::add(); + negation("no"+name)->add(); + if (code) { + string nocode="no"; nocode.push_back(code); + negation(nocode)->add(); + } + } +}; + +string GetEnv(string s, string Default) { + transform(s.begin(), s.end(), s.begin(), toupper); + string t=Getenv(("ASYMPTOTE_"+s).c_str(),msdos); + return t.empty() ? Default : t; +} + +struct envSetting : public stringSetting { + envSetting(string name, string Default) + : stringSetting(name, 0, " ", "", GetEnv(name,Default)) {} +}; + +template<class T> +struct dataSetting : public argumentSetting { + string text; + dataSetting(const char *text, string name, char code, + string argname, string desc, types::ty *type, + T defaultValue) + : argumentSetting(name, code, argname, desc, + type, (item)defaultValue), text(text) {} + + bool getOption() { + try { + value=(item)lexical::cast<T>(optarg); + } catch (lexical::bad_cast&) { + error("option requires " + text + " as an argument"); + return false; + } + return true; + } +}; + +template<class T> +string description(string desc, T defaultValue) +{ + return desc.empty() ? "" : desc+" ["+String(defaultValue)+"]"; +} + +struct IntSetting : public dataSetting<Int> { + IntSetting(string name, char code, + string argname, string desc, Int defaultValue=0) + : dataSetting<Int>("an int", name, code, argname, + description(desc,defaultValue), + types::primInt(), defaultValue) {} +}; + +struct realSetting : public dataSetting<double> { + realSetting(string name, char code, + string argname, string desc, double defaultValue=0.0) + : dataSetting<double>("a real", name, code, argname, + description(desc,defaultValue), + types::primReal(), defaultValue) {} +}; + +struct pairSetting : public dataSetting<pair> { + pairSetting(string name, char code, + string argname, string desc, pair defaultValue=0.0) + : dataSetting<pair>("a pair", name, code, argname, + description(desc,defaultValue), + types::primPair(), defaultValue) {} +}; + +// For setting the alignment of a figure on the page. +struct alignSetting : public argumentSetting { + alignSetting(string name, char code, + string argname, string desc, + string defaultValue) + : argumentSetting(name, code, argname, description(desc,defaultValue), + types::primString(), (item)defaultValue) {} + + bool getOption() { + string str=optarg; + if(str == "C" || str == "T" || str == "B" || str == "Z") { + value=str; + return true; + } + error("invalid argument for option"); + return false; + } +}; + +struct stringArraySetting : public itemSetting { + stringArraySetting(string name, array *defaultValue) + : itemSetting(name, 0, "", "", + types::stringArray(), (item) defaultValue) {} + + bool getOption() {return true;} +}; + +struct engineSetting : public argumentSetting { + engineSetting(string name, char code, + string argname, string desc, + string defaultValue) + : argumentSetting(name, code, argname, description(desc,defaultValue), + types::primString(), (item)defaultValue) {} + + bool getOption() { + string str=optarg; + + if(str == "latex" || str == "pdflatex" || str == "xelatex" || + str == "tex" || str == "pdftex" || str == "luatex" || + str == "lualatex" || str == "context" || str == "none") { + value=str; + return true; + } + error("invalid argument for option"); + return false; + } +}; + +template<class T> +string stringCast(T x) +{ + ostringstream buf; + buf.precision(DBL_DIG); + buf.setf(std::ios::boolalpha); + buf << x; + return string(buf.str()); +} + +template <class T> +struct refSetting : public setting { + T *ref; + T defaultValue; + string text; + + refSetting(string name, char code, string argname, + string desc, types::ty *t, T *ref, T defaultValue, + const char *text="") + : setting(name, code, argname, desc, t, stringCast(defaultValue)), + ref(ref), defaultValue(defaultValue), text(text) { + reset(); + } + + virtual bool getOption() { + try { + *ref=lexical::cast<T>(optarg); + } catch (lexical::bad_cast&) { + error("option requires " + text + " as an argument"); + return false; + } + return true; + } + + virtual void reset() { + *ref=defaultValue; + } + + trans::access *buildAccess() { + return new refAccess<T>(ref); + } +}; + +struct boolrefSetting : public refSetting<bool> { + boolrefSetting(string name, char code, string desc, bool *ref, + bool Default=false) + : refSetting<bool>(name, code, noarg, desc, + types::primBoolean(), ref, Default) {} + virtual bool getOption() { + *ref=true; + return true; + } + + virtual option *negation(string name) { + struct negOption : public option { + boolrefSetting &base; + + negOption(boolrefSetting &base, string name) + : option(name, 0, noarg, ""), base(base) {} + + bool getOption() { + *(base.ref)=false; + return true; + } + }; + return new negOption(*this, name); + } + + void add() { + setting::add(); + negation("no"+name)->add(); + if (code) { + string nocode="no"; nocode.push_back(code); + negation(nocode)->add(); + } + } +}; + +struct compactSetting : public boolrefSetting { + compactSetting(string name, char code, string desc, bool *ref, + bool Default=false) + : boolrefSetting(name,code,desc,ref,Default) {} + bool getOption() { + mem::compact(1); + return boolrefSetting::getOption(); + } + + option *negation(string name) { + mem::compact(0); + return boolrefSetting::negation(name); + } +}; + +struct incrementSetting : public refSetting<Int> { + incrementSetting(string name, char code, string desc, Int *ref) + : refSetting<Int>(name, code, noarg, desc, + types::primInt(), ref, 0) {} + + bool getOption() { + // Increment the value. + ++(*ref); + return true; + } + + option *negation(string name) { + struct negOption : public option { + incrementSetting &base; + + negOption(incrementSetting &base, string name) + : option(name, 0, noarg, ""), base(base) {} + + bool getOption() { + if(*base.ref) --(*base.ref); + return true; + } + }; + return new negOption(*this, name); + } + + void add() { + setting::add(); + negation("no"+name)->add(); + if (code) { + string nocode="no"; nocode.push_back(code); + negation(nocode)->add(); + } + } +}; + +struct incrementOption : public option { + Int *ref; + Int level; + + incrementOption(string name, char code, string desc, Int *ref, + Int level=1) + : option(name, code, noarg, desc, true), ref(ref), level(level) {} + + bool getOption() { + // Increment the value. + (*ref) += level; + return true; + } +}; + +void addOption(option *o) { + o->add(); +} + +void version() +{ + cerr << PROGRAM << " version " << REVISION + << " [(C) 2004 Andy Hammerlindl, John C. Bowman, Tom Prince]" + << endl; +} + +void usage(const char *program) +{ + version(); + cerr << "\t\t\t" << "https://asymptote.sourceforge.io/" + << endl + << "Usage: " << program << " [options] [file ...]" + << endl; +} + +void reportSyntax() { + cerr << endl; + usage(argv0); + cerr << endl << "Type '" << argv0 + << " -h' for a description of options." << endl; + exit(1); +} + +void displayOptions() +{ + cerr << endl; + cerr << "Options (negate by replacing - with -no): " + << endl << endl; + for (optionsMap_t::iterator opt=optionsMap.begin(); + opt!=optionsMap.end(); + ++opt) + opt->second->describe(); +} + +struct helpOption : public option { + helpOption(string name, char code, string desc) + : option(name, code, noarg, desc, true) {} + + bool getOption() { + usage(argv0); + displayOptions(); + cerr << endl; + exit(0); + + // Unreachable code. + return true; + } +}; + +struct versionOption : public option { + versionOption(string name, char code, string desc) + : option(name, code, noarg, desc, true) {} + + bool disabled; + + const void feature(const char *s, bool enabled) { + if(enabled ^ disabled) + cerr << s << endl; + } + + void features(bool enabled) { + disabled=!enabled; + cerr << endl << (disabled ? "DIS" : "EN") << "ABLED OPTIONS:" << endl; + + bool glm=false; + bool gl=false; + bool gsl=false; + bool fftw3=false; + bool xdr=false; + bool curl=false; + bool readline=false; + bool editline=false; + bool sigsegv=false; + bool usegc=false; + +#if HAVE_LIBGLM + glm=true; +#endif + +#ifdef HAVE_GL + gl=true; +#endif + +#ifdef HAVE_LIBGSL + gsl=true; +#endif + +#ifdef HAVE_LIBFFTW3 + fftw3=true; +#endif + +#ifdef HAVE_RPC_RPC_H + xdr=true; +#endif + +#ifdef HAVE_LIBCURL + curl=true; +#endif + +#ifdef HAVE_LIBCURSES +#ifdef HAVE_LIBREADLINE + readline=true; +#else +#ifdef HAVE_LIBEDIT + editline=true; +#endif +#endif +#endif + +#ifdef HAVE_LIBSIGSEGV + sigsegv=true; +#endif + +#ifdef USEGC + usegc=true; +#endif + + feature("WebGL 3D HTML rendering",glm); +#ifdef HAVE_LIBOSMESA + feature("OpenGL 3D OSMesa offscreen rendering",gl); +#else + feature("OpenGL 3D OpenGL rendering",gl); +#endif + feature("GSL GNU Scientific Library (special functions)",gsl); + feature("FFTW3 Fast Fourier transforms",fftw3); + feature("XDR external data representation (portable binary file format)",xdr); + feature("CURL URL support",curl); + feature("Readline interactive history and editing",readline); + if(!readline) + feature("Editline interactive editing (if Readline is unavailable)",editline); + feature("Sigsegv distinguish stack overflows from segmentation faults", + sigsegv); + feature("GC Boehm garbage collector",usegc); + } + + bool getOption() { + version(); + features(1); + features(0); + exit(0); + + // Unreachable code. + return true; + } +}; + +struct divisorOption : public option { + divisorOption(string name, char code, string argname, string desc) + : option(name, code, argname, desc) {} + + bool getOption() { + try { +#ifdef USEGC + Int n=lexical::cast<Int>(optarg); + if(n > 0) GC_set_free_space_divisor((GC_word) n); +#endif + } catch (lexical::bad_cast&) { + error("option requires an int as an argument"); + return false; + } + return true; + } +}; + +// For security reasons, these options aren't fields of the settings module. +struct stringOption : public option { + char **variable; + stringOption(string name, char code, string argname, + string desc, char **variable) + : option(name, code, argname, desc, true), variable(variable) {} + + bool getOption() { + *variable=optarg; + return true; + } +}; + +string build_optstring() { + string s; + for (codeMap_t::iterator p=codeMap.begin(); p !=codeMap.end(); ++p) + s +=p->second->optstring(); + + return s; +} + +c_option *build_longopts() { + size_t n=optionsMap.size(); + + c_option *longopts=new(UseGC) c_option[n+1]; + Int i=0; + for (optionsMap_t::iterator p=optionsMap.begin(); + p !=optionsMap.end(); + ++p, ++i) + p->second->longopt(longopts[i]); + + longopts[n].name=NULL; + longopts[n].has_arg=0; + longopts[n].flag=NULL; + longopts[n].val=0; + + return longopts; +} + +void resetOptions() +{ + for(optionsMap_t::iterator opt=optionsMap.begin(); opt != optionsMap.end(); + ++opt) + if(opt->first != "config" && opt->first != "dir" && opt->first != "sysdir") + opt->second->reset(); +} + +void getOptions(int argc, char *argv[]) +{ + bool syntax=false; + optind=0; + + string optstring=build_optstring(); + //cerr << "optstring: " << optstring << endl; + c_option *longopts=build_longopts(); + int long_index = 0; + + errno=0; + for(;;) { + int c = getopt_long_only(argc,argv, + optstring.c_str(), longopts, &long_index); + if (c == -1) + break; + + if (c == 0) { + const char *name=longopts[long_index].name; + //cerr << "long option: " << name << endl; + if (!optionsMap[name]->getOption()) + syntax=true; + } + else if (codeMap.find((char)c) != codeMap.end()) { + //cerr << "char option: " << (char)c << endl; + if (!codeMap[(char)c]->getOption()) + syntax=true; + } + else { + syntax=true; + } + + errno=0; + } + + if (syntax) + reportSyntax(); +} + +#ifdef USEGC +void no_GCwarn(char *, GC_word) +{ +} +#endif + +array* stringArray(const char **s) +{ + size_t count=0; + while(s[count]) + ++count; + array *a=new array(count); + for(size_t i=0; i < count; ++i) + (*a)[i]=string(s[i]); + return a; +} + +void initSettings() { + static bool initialize=true; + if(initialize) { + queryRegistry(); + initialize=false; + } + + settingsModule=new types::dummyRecord(symbol::trans("settings")); + +// Default mouse bindings + +// LEFT: rotate +// SHIFT LEFT: zoom +// CTRL LEFT: shift +// ALT LEFT: pan + const char *leftbutton[]={"rotate","zoom","shift","pan",NULL}; + +// MIDDLE: + const char *middlebutton[]={NULL}; + +// RIGHT: zoom +// SHIFT RIGHT: rotateX +// CTRL RIGHT: rotateY +// ALT RIGHT: rotateZ + const char *rightbutton[]={"zoom","rotateX","rotateY","rotateZ",NULL}; + +// WHEEL_UP: zoomin + const char *wheelup[]={"zoomin",NULL}; + +// WHEEL_DOWN: zoomout + const char *wheeldown[]={"zoomout",NULL}; + + addOption(new stringArraySetting("leftbutton", stringArray(leftbutton))); + addOption(new stringArraySetting("middlebutton", stringArray(middlebutton))); + addOption(new stringArraySetting("rightbutton", stringArray(rightbutton))); + addOption(new stringArraySetting("wheelup", stringArray(wheelup))); + addOption(new stringArraySetting("wheeldown", stringArray(wheeldown))); + addOption(new stringArraySetting("suppress", new array)); + + addOption(new warnSetting("warn", 0, "string", "Enable warning")); + + multiOption *view=new multiOption("View", 'V', "View output"); + view->add(new boolSetting("batchView", 0, "View output in batch mode", + msdos)); + view->add(new boolSetting("multipleView", 0, + "View output from multiple batch-mode files", + false)); + view->add(new boolSetting("interactiveView", 0, + "View output in interactive mode", true)); + addOption(view); + addOption(new stringSetting("outformat", 'f', "format", + "Convert each output file to specified format", + "")); + addOption(new boolSetting("svgemulation", 0, + "Emulate unimplemented SVG shading", true)); + addOption(new boolSetting("prc", 0, + "Embed 3D PRC graphics in PDF output", true)); + addOption(new boolSetting("toolbar", 0, + "Show 3D toolbar in PDF output", true)); + addOption(new boolSetting("axes3", 0, + "Show 3D axes in PDF output", true)); + addOption(new boolSetting("envmap", 0, + "Enable environment map image-based lighting (Experimental)", false)); + + + addOption(new realSetting("render", 0, "n", + "Render 3D graphics using n pixels per bp (-1=auto)", + havegl ? -1.0 : 0.0)); + addOption(new realSetting("devicepixelratio", 0, "n", "Ratio of physical to logical pixels", 1.0)); + addOption(new IntSetting("antialias", 0, "n", + "Antialiasing width for rasterized output", 2)); + addOption(new IntSetting("multisample", 0, "n", + "Multisampling width for screen images", 4)); + addOption(new boolSetting("twosided", 0, + "Use two-sided 3D lighting model for rendering", + true)); + addOption(new pairSetting("position", 0, "pair", + "Initial 3D rendering screen position")); + addOption(new pairSetting("maxviewport", 0, "pair", + "Maximum viewport size",pair(0,0))); + addOption(new pairSetting("viewportmargin", 0, "pair", + "Horizontal and vertical 3D viewport margin", + pair(0.5,0.5))); + addOption(new boolSetting("absolute", 0, + "Use absolute WebGL dimensions", false)); + addOption(new pairSetting("maxtile", 0, "pair", + "Maximum rendering tile size",pair(1024,768))); + addOption(new boolSetting("iconify", 0, + "Iconify rendering window", false)); + addOption(new boolSetting("thick", 0, + "Render thick 3D lines", true)); + addOption(new boolSetting("thin", 0, + "Render thin 3D lines", true)); + addOption(new boolSetting("autobillboard", 0, + "3D labels always face viewer by default", true)); + addOption(new boolSetting("threads", 0, + "Use POSIX threads for 3D rendering", true)); + addOption(new boolSetting("fitscreen", 0, + "Fit rendered image to screen", true)); + addOption(new boolSetting("interactiveWrite", 0, + "Write expressions entered at the prompt to stdout", + true)); + addOption(new helpOption("help", 'h', "Show summary of options")); + addOption(new versionOption("version", 0, "Show version")); + + addOption(new pairSetting("offset", 'O', "pair", "PostScript offset")); + addOption(new pairSetting("aligndir", 0, "pair", + "Directional page alignment (overrides align)")); + addOption(new alignSetting("align", 'a', "C|B|T|Z", + "Center, Bottom, Top, or Zero page alignment", + "C")); + + addOption(new boolSetting("debug", 'd', "Enable debugging messages")); + addOption(new incrementSetting("verbose", 'v', + "Increase verbosity level (can specify multiple times)", &verbose)); + // Resolve ambiguity with --version + addOption(new incrementOption("vv", 0,"", &verbose,2)); + addOption(new incrementOption("novv", 0,"", &verbose,-2)); + + addOption(new boolSetting("keep", 'k', "Keep intermediate files")); + addOption(new boolSetting("keepaux", 0, + "Keep intermediate LaTeX .aux files")); + addOption(new engineSetting("tex", 0, "engine", + "latex|pdflatex|xelatex|lualatex|tex|pdftex|luatex|context|none", + "latex")); + + addOption(new boolSetting("twice", 0, + "Run LaTeX twice (to resolve references)")); + addOption(new boolSetting("inlinetex", 0, "Generate inline TeX code")); + addOption(new boolSetting("embed", 0, "Embed rendered preview image", true)); + addOption(new boolSetting("auto3D", 0, "Automatically activate 3D scene", + true)); + addOption(new boolSetting("autoplay", 0, "Autoplay 3D animations", false)); + addOption(new boolSetting("loop", 0, "Loop 3D animations", false)); + addOption(new boolSetting("interrupt", 0, "", false)); + addOption(new boolSetting("animating", 0, "", false)); + addOption(new boolSetting("reverse", 0, "reverse 3D animations", false)); + + addOption(new boolSetting("inlineimage", 0, + "Generate inline embedded image")); + addOption(new boolSetting("compress", 0, + "Compress images in PDF output", true)); + addOption(new boolSetting("parseonly", 'p', "Parse file")); + addOption(new boolSetting("translate", 's', + "Show translated virtual machine code")); + addOption(new boolSetting("tabcompletion", 0, + "Interactive prompt auto-completion", true)); + addOption(new boolSetting("listvariables", 'l', + "List available global functions and variables")); + addOption(new boolSetting("where", 0, + "Show where listed variables are declared")); + + multiOption *mask=new multiOption("mask", 'm', + "Mask fpu exceptions"); + mask->add(new boolSetting("batchMask", 0, + "Mask fpu exceptions in batch mode", false)); + mask->add(new boolSetting("interactiveMask", 0, + "Mask fpu exceptions in interactive mode", true)); + addOption(mask); + + addOption(new boolrefSetting("bw", 0, + "Convert all colors to black and white",&bw)); + addOption(new boolrefSetting("gray", 0, "Convert all colors to grayscale", + &gray)); + addOption(new boolrefSetting("rgb", 0, "Convert cmyk colors to rgb",&rgb)); + addOption(new boolrefSetting("cmyk", 0, "Convert rgb colors to cmyk",&cmyk)); + + addSecureSetting(new boolrefSetting("safe", 0, "Disable system call", + &safe, true)); + addSecureSetting(new boolrefSetting("globalwrite", 0, + "Allow write to other directory", + &globalWrite, false)); + addSecureSetting(new boolrefSetting("globalread", 0, + "Allow read from other directory", + &globalRead, true)); + addSecureSetting(new stringSetting("outname", 'o', "name", + "Alternative output directory/filename")); + addOption(new stringOption("cd", 0, "directory", "Set current directory", + &startpath)); + +#ifdef USEGC + addOption(new compactSetting("compact", 0, + "Conserve memory at the expense of speed", + &compact)); + addOption(new divisorOption("divisor", 0, "n", + "Garbage collect using purge(divisor=n) [2]")); +#endif + + addOption(new stringSetting("prompt", 0,"string","Prompt","> ")); + addOption(new stringSetting("prompt2", 0,"string", + "Continuation prompt for multiline input ", + "..")); + addOption(new boolSetting("multiline", 0, + "Input code over multiple lines at the prompt")); + addOption(new boolSetting("xasy", 0, + "Special interactive mode for xasy")); + + addOption(new boolSetting("wait", 0, + "Wait for child processes to finish before exiting")); + addOption(new IntSetting("inpipe", 0, "n","",-1)); + addOption(new IntSetting("outpipe", 0, "n","",-1)); + addOption(new boolSetting("exitonEOF", 0, "Exit interactive mode on EOF", + true)); + + addOption(new boolSetting("quiet", 'q', + "Suppress welcome text and noninteractive stdout")); + addOption(new boolSetting("localhistory", 0, + "Use a local interactive history file")); + addOption(new IntSetting("historylines", 0, "n", + "Retain n lines of history",1000)); + addOption(new IntSetting("scroll", 0, "n", + "Scroll standard output n lines at a time",0)); + addOption(new IntSetting("level", 0, "n", "Postscript level",3)); + addOption(new boolSetting("autoplain", 0, + "Enable automatic importing of plain", + true)); + addOption(new boolSetting("autorotate", 0, + "Enable automatic PDF page rotation", + false)); + addOption(new boolSetting("offline", 0, + "Produce offline html files",false)); + addOption(new boolSetting("pdfreload", 0, + "Automatically reload document in pdfviewer", + false)); + addOption(new IntSetting("pdfreloaddelay", 0, "usec", + "Delay before attempting initial pdf reload" + ,750000)); + addOption(new stringSetting("autoimport", 0, "string", + "Module to automatically import")); + addOption(new userSetting("command", 'c', "string", + "Command to autoexecute")); + addOption(new userSetting("user", 'u', "string", + "General purpose user string")); + + addOption(new realSetting("zoomfactor", 0, "factor", "Zoom step factor", + 1.05)); + addOption(new realSetting("zoomPinchFactor", 0, "n", + "WebGL zoom pinch sensitivity", 10)); + addOption(new realSetting("zoomPinchCap", 0, "limit", + "WebGL maximum zoom pinch", 100)); + addOption(new realSetting("zoomstep", 0, "step", "Mouse motion zoom step", + 0.1)); + addOption(new realSetting("shiftHoldDistance", 0, "n", + "WebGL touch screen distance limit for shift mode", + 20)); + addOption(new realSetting("shiftWaitTime", 0, "ms", + "WebGL touch screen shift mode delay", + 200)); + addOption(new realSetting("vibrateTime", 0, "ms", + "WebGL shift mode vibrate duration", + 25)); + addOption(new realSetting("spinstep", 0, "deg/s", "Spin speed", + 60.0)); + addOption(new realSetting("framerate", 0, "frames/s", "Animation speed", + 30.0)); + addOption(new realSetting("framedelay", 0, "ms", + "Additional frame delay", 0.0)); + addOption(new realSetting("resizestep", 0, "step", "Resize step", 1.2)); + addOption(new IntSetting("digits", 0, "n", + "Default output file precision", 7)); + + addOption(new realSetting("paperwidth", 0, "bp", "")); + addOption(new realSetting("paperheight", 0, "bp", "")); + + addOption(new stringSetting("dvipsOptions", 0, "string", "")); + addOption(new stringSetting("dvisvgmOptions", 0, "string", "")); + addOption(new stringSetting("convertOptions", 0, "string", "")); + addOption(new stringSetting("gsOptions", 0, "string", "")); + addOption(new stringSetting("htmlviewerOptions", 0, "string", "")); + addOption(new stringSetting("psviewerOptions", 0, "string", "")); + addOption(new stringSetting("pdfviewerOptions", 0, "string", "")); + addOption(new stringSetting("pdfreloadOptions", 0, "string", "")); + addOption(new stringSetting("glOptions", 0, "string", "")); + addOption(new stringSetting("hyperrefOptions", 0, "str", + "","setpagesize=false,unicode,pdfborder=0 0 0")); + + addOption(new envSetting("config","config."+suffix)); + addOption(new envSetting("htmlviewer", defaultHTMLViewer)); + addOption(new envSetting("pdfviewer", defaultPDFViewer)); + addOption(new envSetting("psviewer", defaultPSViewer)); + addOption(new envSetting("gs", defaultGhostscript)); + addOption(new envSetting("libgs", defaultGhostscriptLibrary)); + addOption(new envSetting("epsdriver", defaultEPSdriver)); + addOption(new envSetting("psdriver", defaultPSdriver)); + addOption(new envSetting("asygl", defaultAsyGL)); + addOption(new envSetting("texpath", "")); + addOption(new envSetting("texcommand", "")); + addOption(new envSetting("dvips", "dvips")); + addOption(new envSetting("dvisvgm", "dvisvgm")); + addOption(new envSetting("convert", "convert")); + addOption(new envSetting("display", defaultDisplay)); + addOption(new envSetting("animate", defaultAnimate)); + addOption(new envSetting("papertype", "letter")); + addOption(new envSetting("dir", "")); + addOption(new envSetting("sysdir", systemDir)); + addOption(new envSetting("textcommand","groff")); + addOption(new envSetting("textcommandOptions","-e -P -b16")); + addOption(new envSetting("textextension", "roff")); + addOption(new envSetting("textoutformat", "ps")); + addOption(new envSetting("textprologue", ".EQ\ndelim $$\n.EN")); + addOption(new envSetting("textinitialfont", ".fam T\n.ps 12")); + addOption(new envSetting("textepilogue", ".bp")); +} + +// Access the arguments once options have been parsed. +int numArgs() { return argCount; } +char *getArg(int n) { return argList[n]; } + +void setInteractive() +{ + if(numArgs() == 0 && !getSetting<bool>("listvariables") && + getSetting<string>("command").empty() && + (isatty(STDIN_FILENO) || getSetting<Int>("xasy"))) + interact::interactive=true; + + if(getSetting<bool>("localhistory")) + historyname=string(getPath())+dirsep+"."+suffix+"_history"; + else { + if(mkdir(initdir.c_str(),0777) != 0 && errno != EEXIST) + cerr << "failed to create directory "+initdir+"." << endl; + historyname=initdir+"/history"; + } + if(verbose > 1) + cerr << "Using history " << historyname << endl; +} + +bool view() +{ + if (interact::interactive) + return getSetting<bool>("interactiveView"); + else + return getSetting<bool>("batchView") && + (numArgs() == 1 || getSetting<bool>("multipleView")); +} + +bool trap() +{ + if (interact::interactive) + return !getSetting<bool>("interactiveMask"); + else + return !getSetting<bool>("batchMask"); +} + +string outname() +{ + string name=getSetting<string>("outname"); + if(name.empty() && interact::interactive) return standardprefix; + if(msdos) backslashToSlash(name); + return name; +} + +string lookup(const string& symbol) +{ + string s; + mem::vector<string> cmd; + string kpsewhich="kpsewhich"; + string fullname=stripFile(argv0)+kpsewhich; + std::ifstream exists(fullname.c_str()); + if(!exists) fullname=kpsewhich; + cmd.push_back(fullname); + cmd.push_back("--var-value="+symbol); + iopipestream pipe(cmd); + pipe >> s; + size_t n=s.find('\r'); + if(n != string::npos) + s.erase(n,1); + n=s.find('\n'); + if(n != string::npos) + s.erase(n,1); + return s; +} + +void initDir() { + if(getSetting<string>("sysdir").empty()) { + string s=lookup("TEXMFMAIN"); + if(s.size() > 1) { + string texmf=s+dirsep; + docdir=texmf+"doc"+dirsep+"asymptote"; + Setting("sysdir")=texmf+"asymptote"; + s=lookup("ASYMPTOTE_HOME"); + if(s.size() > 1) + initdir=s; + } + } + + if(initdir.empty()) + initdir=Getenv("ASYMPTOTE_HOME",msdos); + + if(initdir.empty()) + initdir=Getenv(HOME.c_str(),msdos)+dirsep+"."+suffix; + +#ifdef __MSDOS__ + mask=umask(0); + if(mask == 0) mask=0027; + umask(mask); + tempdir=Getenv("TEMP",true); +#else + tempdir="/tmp"; +#endif + if(access(initdir.c_str(),F_OK) == 0) { + if(verbose > 1) + cerr << "Using configuration directory " << initdir << endl; + } +} + +void setPath() { + searchPath.clear(); + searchPath.push_back("."); + string asydir=getSetting<string>("dir"); + if(asydir != "") { + size_t p,i=0; + while((p=asydir.find(pathSeparator,i)) < string::npos) { + if(p > i) searchPath.push_back(asydir.substr(i,p-i)); + i=p+1; + } + if(i < asydir.length()) searchPath.push_back(asydir.substr(i)); + } + if(access(initdir.c_str(),F_OK) == 0) + searchPath.push_back(initdir); + string sysdir=getSetting<string>("sysdir"); + if(sysdir != "") + searchPath.push_back(sysdir); + searchPath.push_back(docdir+"/examples"); +} + +void SetPageDimensions() { + string paperType=getSetting<string>("papertype"); + + if(paperType.empty() && + getSetting<double>("paperwidth") != 0.0 && + getSetting<double>("paperheight") != 0.0) return; + + if(paperType == "letter") { + Setting("paperwidth")=8.5*inches; + Setting("paperheight")=11.0*inches; + } else { + Setting("paperwidth")=21.0*cm; + Setting("paperheight")=29.7*cm; + + if(paperType != "a4") { + cerr << "Unknown paper size \'" << paperType << "\'; assuming a4." + << endl; + Setting("papertype")=string("a4"); + } + } +} + +bool xe(const string& texengine) +{ + return texengine == "xelatex"; +} + +bool lua(const string& texengine) +{ + return texengine == "luatex" || texengine == "lualatex"; +} + +bool context(const string& texengine) +{ + return texengine == "context"; +} + +bool pdf(const string& texengine) +{ + return texengine == "pdflatex" || texengine == "pdftex" || xe(texengine) || + lua(texengine) || context(texengine); +} + +bool latex(const string& texengine) +{ + return texengine == "latex" || texengine == "pdflatex" || + texengine == "xelatex" || texengine == "lualatex"; +} + +string nativeformat() +{ + return pdf(getSetting<string>("tex")) ? "pdf" : "eps"; +} + +string defaultformat() +{ + string format=getSetting<string>("outformat"); + return (format.empty()) ? nativeformat() : format; +} + +// TeX special command to set up currentmatrix for typesetting labels. +const char *beginlabel(const string& texengine) +{ + if(pdf(texengine)) + return xe(texengine) ? "\\special{pdf:literal q #5 0 0 cm}" : + "\\special{pdf:q #5 0 0 cm}"; + else + return "\\special{ps:gsave currentpoint currentpoint translate [#5 0 0] " + "concat neg exch neg exch translate}"; +} + +// TeX special command to restore currentmatrix after typesetting labels. +const char *endlabel(const string& texengine) +{ + if(pdf(texengine)) + return xe(texengine) ? "\\special{pdf:literal Q}" : "\\special{pdf:Q}"; + else + return "\\special{ps:currentpoint grestore moveto}"; +} + +// TeX macro to typeset raw postscript code +const char *rawpostscript(const string& texengine) +{ + if(pdf(texengine)) + return "\\def\\ASYraw#1{#1}"; + else + return "\\def\\ASYraw#1{\n" + "currentpoint currentpoint translate matrix currentmatrix\n" + "100 12 div -100 12 div scale\n" + "#1\n" + "setmatrix neg exch neg exch translate}"; +} + +// TeX macro to begin picture +const char *beginpicture(const string& texengine) +{ + if(latex(texengine)) + return "\\begin{picture}"; + if(context(texengine)) + return ""; + else + return "\\picture"; +} + +// TeX macro to end picture +const char *endpicture(const string& texengine) +{ + if(latex(texengine)) + return "\\end{picture}%"; + else if(context(texengine)) + return "%"; + else + return "\\endpicture%"; +} + +// Begin TeX special command. +const char *beginspecial(const string& texengine) +{ + if(pdf(texengine)) + return xe(texengine) ? "\\special{pdf:literal " : "\\special{pdf:"; + else + return "\\special{ps:"; +} + +// End TeX special command. +const char *endspecial() +{ + return "}%"; +} + +string texcommand() +{ + string command=getSetting<string>("texcommand"); + return command.empty() ? getSetting<string>("tex") : command; +} + +string texprogram() +{ + string path=getSetting<string>("texpath"); + string engine=texcommand(); + return path.empty() ? engine : (string) (path+"/"+engine); +} + +Int getScroll() +{ + Int scroll=settings::getSetting<Int>("scroll"); + if(scroll < 0) { +#ifdef HAVE_LIBCURSES + static char *terminal=NULL; + if(!terminal) + terminal=getenv("TERM"); + if(terminal) { +#ifndef __MSDOS__ + int error=setupterm(terminal,1,&error); + if(error == 0) scroll=lines > 2 ? lines-1 : 1; + else +#endif + scroll=0; + } else scroll=0; +#else + scroll=0; +#endif + } + return scroll; +} + +void doConfig(string file) +{ + bool autoplain=getSetting<bool>("autoplain"); + bool listvariables=getSetting<bool>("listvariables"); + if(autoplain) Setting("autoplain")=false; // Turn off for speed. + if(listvariables) Setting("listvariables")=false; + + runFile(file); + + if(autoplain) Setting("autoplain")=true; + if(listvariables) Setting("listvariables")=true; +} + +void setOptions(int argc, char *argv[]) +{ + argv0=argv[0]; + + cout.precision(DBL_DIG); + + // Build settings module. + initSettings(); + + // Read command-line options initially to obtain config, dir, sysdir, verbose. + getOptions(argc,argv); + + // Make configuration and history directory + initDir(); + + Int Verbose=verbose; + string sysdir=getSetting<string>("sysdir"); + + resetOptions(); + + // Read user configuration file. + setPath(); + string filename=getSetting<string>("config"); + if(!filename.empty()) { + string file=locateFile(filename); + if(!file.empty()) { + if(Verbose > 1) + cerr << "Loading " << filename << " from " << file << endl; + doConfig(file); + } + } + + // Read command-line options again to override configuration file defaults. + getOptions(argc,argv); + + if(getSetting<Int>("outpipe") == 2) // Redirect cerr to cout + std::cerr.rdbuf(std::cout.rdbuf()); + + Setting("sysdir")=sysdir; + + if(docdir.empty()) + docdir=getSetting<string>("dir"); + +#ifdef USEGC + if(verbose == 0 && !getSetting<bool>("debug")) GC_set_warn_proc(no_GCwarn); +#endif + + if(setlocale (LC_ALL, "") == NULL && getSetting<bool>("debug")) + perror("setlocale"); + + // Set variables for the file arguments. + argCount = argc - optind; + argList = argv + optind; + + // Recompute search path. + setPath(); + + if(getSetting<double>("paperwidth") != 0.0 && + getSetting<double>("paperheight") != 0.0) + Setting("papertype")=string(""); + + SetPageDimensions(); + + setInteractive(); +} + +} |