diff options
author | Karl Berry <karl@freefriends.org> | 2009-05-16 00:19:13 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2009-05-16 00:19:13 +0000 |
commit | bab45528d65eaafe68a705dbb2a57075c7b7cbd8 (patch) | |
tree | 10b4ae2b5195c8dede153ab89359ec00f55f325f /Build/source/utils/asymptote/settings.cc | |
parent | 8643d90372e9c31e0f461c15c596b60a545bd7d3 (diff) |
asymptote 1.72 sources (not integrated into build yet)
git-svn-id: svn://tug.org/texlive/trunk@13110 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/asymptote/settings.cc')
-rw-r--r-- | Build/source/utils/asymptote/settings.cc | 1391 |
1 files changed, 1391 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..a4961176660 --- /dev/null +++ b/Build/source/utils/asymptote/settings.cc @@ -0,0 +1,1391 @@ +/***** + * 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" + +#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 + +using vm::item; + +using trans::itemRefAccess; +using trans::refAccess; +using trans::varEntry; + +void doConfig(string filename); + +namespace settings { + +using camp::pair; + +string asyInstallDir; +string defaultXasy="xasy"; + +#ifdef HAVE_LIBGL +const bool haveglut=true; +#else +const bool haveglut=false; +#endif + +#ifndef __CYGWIN__ + +bool msdos=false; +const char *HOME="HOME"; +const char pathSeparator=':'; +string defaultPSViewer="gv"; +#ifdef __APPLE__ +string defaultPDFViewer="open"; +#else +string defaultPDFViewer="acroread"; +#endif +string defaultGhostscript="gs"; +string defaultPython; +string defaultDisplay="display"; +string systemDir=ASYMPTOTE_SYSDIR; +const string docdir=ASYMPTOTE_DOCDIR; +void queryRegistry() {} +const string dirsep="/"; + +#else + +bool msdos=true; +const char *HOME="USERPROFILE"; +const char pathSeparator=';'; +string defaultPSViewer="gsview32.exe"; +string defaultPDFViewer="AcroRd32.exe"; +string defaultGhostscript="gswin32c.exe"; +string defaultPython="python.exe"; +string defaultDisplay="imdisplay"; +string systemDir; +const string docdir="."; +const string dirsep="\\"; + +#include <dirent.h> + +// Use key to look up an entry in the MSWindows registry, respecting wild cards +string getEntry(const string& key) +{ + string path="/proc/registry/HKEY_LOCAL_MACHINE/SOFTWARE/"+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 ""; +} + +void queryRegistry() +{ + string gs=getEntry("GPL Ghostscript/*/GS_DLL"); + if(gs.empty()) + gs=getEntry("AFPL Ghostscript/*/GS_DLL"); + defaultGhostscript=stripFile(gs)+defaultGhostscript; + defaultPDFViewer=getEntry("Adobe/Acrobat Reader/*/InstallPath/@")+"\\"+ + defaultPDFViewer; + defaultPSViewer=getEntry("Ghostgum/GSview/*")+"\\gsview\\"+defaultPSViewer; + defaultPython=getEntry("Python/PythonCore/*/InstallPath/@")+defaultPython; + systemDir=getEntry("Microsoft/Windows/CurrentVersion/App Paths/Asymptote/Path"); + defaultXasy=asyInstallDir+"\\"+defaultXasy; +} + +#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; + +// Colorspace conversion flags (stored in global variables for efficiency). +bool gray; +bool bw; +bool rgb; +bool cmyk; + +// Disable system calls. +bool safe=true; +// Enable writing to (or changing to) other directories +bool globaloption=false; + +bool globalwrite() {return globaloption || !safe;} + +const string suffix="asy"; +const string guisuffix="gui"; + +string initdir; +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; +} + +// The dictionaries of long options and short options. +class 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; + } +}; + +string GetEnv(string s, string Default) { + transform(s.begin(), s.end(), s.begin(), toupper); + string t=Getenv(("ASYMPTOTE_"+s).c_str(),msdos); + return t != "" ? string(t) : Default; +} + +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 String(T x) +{ + ostringstream buf; + buf << x; + return buf.str(); +} + +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, + Int defaultValue=(Int) CENTER) + : argumentSetting(name, code, argname, desc, + types::primInt(), (item)defaultValue) {} + + bool getOption() { + string str=optarg; + if (str == "C") + value=(Int) CENTER; + else if (str == "T") + value=(Int) TOP; + else if (str == "B") + value=(Int) BOTTOM; + else if (str == "Z") { + value=(Int) ZERO; + } else { + error("invalid argument for option"); + return false; + } + return true; + } +}; + +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) {} + bool getOption() { + *ref=true; + return true; + } + + 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 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 " << VERSION << SVN_REVISION + << " [(C) 2004 Andy Hammerlindl, John C. Bowman, Tom Prince]" + << endl; +} + +void usage(const char *program) +{ + version(); + cerr << "\t\t\t" << "http://asymptote.sourceforge.net/" + << 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 getOption() { + version(); + 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->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 + +void initSettings() { + static bool initialize=true; + if(initialize) { + queryRegistry(); + initialize=false; + } + + settingsModule=new types::dummyRecord(symbol::trans("settings")); + + 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("xformat", 0, "format", + "GUI deconstruction format","png")); + addOption(new stringSetting("outformat", 'f', "format", + "Convert each output file to specified format", + "")); + 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 realSetting("render", 0, "n", + "Render 3D graphics using n pixels per bp (-1=auto)", + haveglut ? -1.0 : 0.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(2048,2048))); + addOption(new pairSetting("maxtile", 0, "pair", + "Maximum rendering tile size",pair(0,0))); + 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("threads", 0, + "Use POSIX threads for 3D rendering", !msdos)); + 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 alignSetting("align", 'a', "C|B|T|Z", + "Center, Bottom, Top, or Zero page alignment [Center]")); + + addOption(new boolSetting("debug", 'd', "Enable debugging messages")); + addOption(new incrementSetting("verbose", 'v', + "Increase verbosity level", &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 stringSetting("tex", 0,"engine", + "latex|pdflatex|xelatex|tex|pdftex|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("inlineimage", 0, + "Generate inline embedded image")); + 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", + &globaloption, false)); + addSecureSetting(new stringSetting("outname", 'o', "name", + "Alternative output directory/filename", + "")); + addOption(new stringOption("cd", 0, "directory", "Set current directory", + &startpath)); + +#ifdef USEGC + addOption(new boolrefSetting("compact", 0, + "Conserve memory at the expense of speed", + (bool *) &GC_dont_expand)); + 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("wait", 0, + "Wait for child processes to finish before exiting")); + // Be interactive even in a pipe + addOption(new boolSetting("interactive", 0, "")); + addOption(new boolSetting("exitonEOF", 0, "Exit interactive mode on EOF", + true)); + + addOption(new boolSetting("quiet", 'q', + "Suppress welcome message")); + 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("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("paperwidth", 0, "bp", "")); + addOption(new realSetting("paperheight", 0, "bp", "")); + + addOption(new stringSetting("dvipsOptions", 0, "string", "", "")); + addOption(new stringSetting("convertOptions", 0, "string", "", "")); + addOption(new stringSetting("gsOptions", 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 envSetting("config","config."+suffix)); + addOption(new envSetting("pdfviewer", defaultPDFViewer)); + addOption(new envSetting("psviewer", defaultPSViewer)); + addOption(new envSetting("gs", defaultGhostscript)); + addOption(new envSetting("texpath", "")); + addOption(new envSetting("texcommand", "")); + addOption(new envSetting("texdvicommand", "")); + addOption(new envSetting("dvips", "dvips")); + addOption(new envSetting("convert", "convert")); + addOption(new envSetting("display", defaultDisplay)); + addOption(new envSetting("animate", "animate")); + addOption(new envSetting("python", defaultPython)); + addOption(new envSetting("xasy", defaultXasy)); + addOption(new envSetting("papertype", "letter")); + addOption(new envSetting("dir", "")); + addOption(new envSetting("sysdir", systemDir)); +} + +// 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<bool>("interactive"))) + interact::interactive=true; + + historyname=getSetting<bool>("localhistory") ? "."+suffix+"_history" + : (initdir+"/history"); +} + +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"); + return name.empty() ? "out" : name; +} + +void initDir() { + initdir=Getenv(HOME,msdos)+"/."+suffix; + mkdir(initdir.c_str(),0777); +} + +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)); + } + searchPath.push_back(initdir); + string sysdir=getSetting<string>("sysdir"); + if(sysdir == "") { + iopipestream pipe("kpsewhich --var-value=SELFAUTOPARENT"); + pipe >> sysdir; + size_t size=sysdir.size(); + if(size > 2) { + sysdir.erase(size-1,1); + sysdir.append(dirsep+"texmf/asymptote"); + Setting("sysdir")=sysdir; + } + } + if(sysdir != "") + searchPath.push_back(sysdir); +} + +void SetPageDimensions() { + string paperType=getSetting<string>("papertype"); + + if(paperType == "" && + 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 xelatex(const string& texengine) { + return texengine == "xelatex"; +} + +bool pdf(const string& texengine) { + return texengine == "pdflatex" || texengine == "pdftex" || xelatex(texengine); +} + +bool latex(const string& texengine) { + return texengine == "latex" || texengine == "pdflatex" || xelatex(texengine); +} + +string nativeformat() { + return pdf(getSetting<string>("tex")) ? "pdf" : "eps"; +} + +string defaultformat() { + string format=getSetting<string>("outformat"); + return (format == "") ? nativeformat() : format; +} + +// TeX special command to set up currentmatrix for typesetting labels. +const char *beginlabel(const string& texengine) { + if(pdf(texengine)) + return xelatex(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 xelatex(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}"; + else + return "\\picture"; +} + +// TeX macro to end picture +const char *endpicture(const string& texengine) { + if(latex(texengine)) + return "\\end{picture}%"; + else + return "\\endpicture%"; +} + +// Begin TeX special command. +const char *beginspecial(const string& texengine) { + if(pdf(texengine)) + return xelatex(texengine) ? "\\special{pdf:literal " : "\\special{pdf:"; + return "\\special{ps:"; +} + +// End TeX special command. +const char *endspecial() { + return "}%"; +} + +// Default TeX units. +const char *texunits(const string& texengine) +{ + return xelatex(texengine) ? "bp" : "pt"; +} + + +bool fataltex[]={false,true}; +const char *pdftexerrors[]={"! "," ==> Fatal error",NULL}; +const char *texerrors[]={"! ",NULL}; + +// Messages that signify a TeX error. +const char **texabort(const string& texengine) +{ + return settings::pdf(texengine) ? pdftexerrors : texerrors; +} + +string texcommand(bool ps) +{ + string command; + if(ps) { + command=getSetting<string>("texdvicommand"); + if(command == "") + command=latex(getSetting<string>("tex")) ? "latex" : "tex"; + } else + command=getSetting<string>("texcommand"); + return command.empty() ? getSetting<string>("tex") : command; +} + +string texprogram(bool ps) +{ + string path=getSetting<string>("texpath"); + string engine=texcommand(ps); + if(!path.empty()) engine=(string) (path+"/"+engine); + string program="'"+engine+"'"; + string dir=stripFile(outname()); + return dir.empty() ? program : (program+" -output-directory="+dir); +} + +Int getScroll() +{ + Int scroll=settings::getSetting<Int>("scroll"); +#ifdef HAVE_LIBCURSES + if(scroll < 0) { + char *terminal=getenv("TERM"); + if(terminal) { + setupterm(terminal,1,NULL); + scroll=lines > 2 ? lines-1 : 1; + } + } +#endif + return scroll; +} + +void setOptions(int argc, char *argv[]) +{ + argv0=argv[0]; + + cout.precision(DBL_DIG); + + // Make configuration and history directory + initDir(); + + // Build settings module. + initSettings(); + + // Read command-line options initially to obtain CONFIG and DIR. + getOptions(argc,argv); + + Int Verbose=verbose; + 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); + +#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(); +} + +} |