| 1 | /***** |
|---|
| 2 | * settings.cc |
|---|
| 3 | * Andy Hammerlindl 2004/05/10 |
|---|
| 4 | * |
|---|
| 5 | * Declares a list of global variables that act as settings in the system. |
|---|
| 6 | *****/ |
|---|
| 7 | |
|---|
| 8 | #include <iostream> |
|---|
| 9 | #include <iomanip> |
|---|
| 10 | #include <cstdlib> |
|---|
| 11 | #include <cerrno> |
|---|
| 12 | #include <vector> |
|---|
| 13 | #include <sys/stat.h> |
|---|
| 14 | |
|---|
| 15 | #ifdef HAVE_CONFIG_H |
|---|
| 16 | #include "config.h" |
|---|
| 17 | #endif |
|---|
| 18 | |
|---|
| 19 | #if HAVE_GNU_GETOPT_H |
|---|
| 20 | #include <getopt.h> |
|---|
| 21 | #else |
|---|
| 22 | #include "getopt.h" |
|---|
| 23 | #endif |
|---|
| 24 | |
|---|
| 25 | #include "util.h" |
|---|
| 26 | #include "settings.h" |
|---|
| 27 | #include "pen.h" |
|---|
| 28 | #include "interact.h" |
|---|
| 29 | #include "locate.h" |
|---|
| 30 | #include "lexical.h" |
|---|
| 31 | #include "memory.h" |
|---|
| 32 | #include "record.h" |
|---|
| 33 | #include "env.h" |
|---|
| 34 | #include "item.h" |
|---|
| 35 | #include "refaccess.h" |
|---|
| 36 | |
|---|
| 37 | using std::vector; |
|---|
| 38 | using vm::item; |
|---|
| 39 | |
|---|
| 40 | using trans::itemRefAccess; |
|---|
| 41 | using trans::refAccess; |
|---|
| 42 | using trans::varEntry; |
|---|
| 43 | |
|---|
| 44 | namespace loop { |
|---|
| 45 | void doConfig(string filename); |
|---|
| 46 | } |
|---|
| 47 | |
|---|
| 48 | namespace settings { |
|---|
| 49 | |
|---|
| 50 | #ifdef MSDOS |
|---|
| 51 | const bool msdos=true; |
|---|
| 52 | const char pathSeparator=';'; |
|---|
| 53 | const string defaultPSViewer= |
|---|
| 54 | "'c:\\Program Files\\Ghostgum\\gsview\\gsview32.exe'"; |
|---|
| 55 | const string defaultPDFViewer= |
|---|
| 56 | "'c:\\Program Files\\Adobe\\Acrobat 7.0\\Reader\\AcroRd32.exe'"; |
|---|
| 57 | const string defaultGhostscript= |
|---|
| 58 | "'c:\\Program Files\\gs\\gs8.51\\bin\\gswin32.exe'"; |
|---|
| 59 | const string defaultPython="'c:\\Python24\\python.exe'"; |
|---|
| 60 | const string defaultDisplay="imdisplay"; |
|---|
| 61 | #undef ASYMPTOTE_SYSDIR |
|---|
| 62 | #define ASYMPTOTE_SYSDIR "c:\\Program Files\\Asymptote" |
|---|
| 63 | const string docdir="."; |
|---|
| 64 | #else |
|---|
| 65 | const bool msdos=false; |
|---|
| 66 | const char pathSeparator=':'; |
|---|
| 67 | const string defaultPSViewer="gv"; |
|---|
| 68 | const string defaultPDFViewer="acroread"; |
|---|
| 69 | const string defaultGhostscript="gs"; |
|---|
| 70 | const string defaultDisplay="display"; |
|---|
| 71 | const string defaultPython=""; |
|---|
| 72 | const string docdir=ASYMPTOTE_DOCDIR; |
|---|
| 73 | #endif |
|---|
| 74 | |
|---|
| 75 | const char PROGRAM[]=PACKAGE_NAME; |
|---|
| 76 | const char VERSION[]=PACKAGE_VERSION; |
|---|
| 77 | const char BUGREPORT[]=PACKAGE_BUGREPORT; |
|---|
| 78 | |
|---|
| 79 | // The name of the program (as called). Used when displaying help info. |
|---|
| 80 | char *argv0; |
|---|
| 81 | |
|---|
| 82 | typedef ::option c_option; |
|---|
| 83 | |
|---|
| 84 | types::dummyRecord *settingsModule; |
|---|
| 85 | |
|---|
| 86 | types::record *getSettingsModule() { |
|---|
| 87 | return settingsModule; |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | // The dictionaries of long options and short options. |
|---|
| 91 | class option; |
|---|
| 92 | typedef mem::map<CONST mem::string, option *> optionsMap_t; |
|---|
| 93 | optionsMap_t optionsMap; |
|---|
| 94 | typedef mem::map<CONST char, option *> codeMap_t; |
|---|
| 95 | codeMap_t codeMap; |
|---|
| 96 | |
|---|
| 97 | struct option : public gc { |
|---|
| 98 | mem::string name; |
|---|
| 99 | char code; // Command line option, i.e. 'V' for -V. |
|---|
| 100 | bool argument; // If it takes an argument on the command line. This is set |
|---|
| 101 | // based on whether argname is empty. |
|---|
| 102 | |
|---|
| 103 | mem::string argname; // The argument name for printing the description. |
|---|
| 104 | mem::string desc; // One line description of what the option does. |
|---|
| 105 | |
|---|
| 106 | option(mem::string name, char code, mem::string argname, mem::string desc) |
|---|
| 107 | : name(name), code(code), argument(!argname.empty()), |
|---|
| 108 | argname(argname), desc(desc) {} |
|---|
| 109 | |
|---|
| 110 | virtual ~option() {} |
|---|
| 111 | |
|---|
| 112 | // Builds this option's contribution to the optstring argument of get_opt(). |
|---|
| 113 | virtual mem::string optstring() { |
|---|
| 114 | if (code) { |
|---|
| 115 | mem::string base; |
|---|
| 116 | base.push_back(code); |
|---|
| 117 | return argument ? base+":" : base; |
|---|
| 118 | } |
|---|
| 119 | else return ""; |
|---|
| 120 | } |
|---|
| 121 | |
|---|
| 122 | // Sets the contribution to the longopt array. |
|---|
| 123 | virtual void longopt(c_option &o) { |
|---|
| 124 | o.name=name.c_str(); |
|---|
| 125 | o.has_arg=argument ? 1 : 0; |
|---|
| 126 | o.flag=0; |
|---|
| 127 | o.val=0; |
|---|
| 128 | } |
|---|
| 129 | |
|---|
| 130 | // Add to the dictionaries of options. |
|---|
| 131 | virtual void add() { |
|---|
| 132 | optionsMap[name]=this; |
|---|
| 133 | if (code) |
|---|
| 134 | codeMap[code]=this; |
|---|
| 135 | } |
|---|
| 136 | |
|---|
| 137 | // Set the option from the command-line argument. Return true if the option |
|---|
| 138 | // was correctly parsed. |
|---|
| 139 | virtual bool getOption() = 0; |
|---|
| 140 | |
|---|
| 141 | void error(string msg) { |
|---|
| 142 | cerr << endl << argv0 << ": "; |
|---|
| 143 | if (code) |
|---|
| 144 | cerr << "-" << code << " "; |
|---|
| 145 | cerr << "(-" << name << ") " << msg << endl; |
|---|
| 146 | } |
|---|
| 147 | |
|---|
| 148 | // The "-f,-outformat format" part of the option. |
|---|
| 149 | virtual mem::string describeStart() { |
|---|
| 150 | ostringstream ss; |
|---|
| 151 | if (code) |
|---|
| 152 | ss << "-" << code << ","; |
|---|
| 153 | ss << "-" << name; |
|---|
| 154 | if (argument) |
|---|
| 155 | ss << " " << argname; |
|---|
| 156 | return ss.str(); |
|---|
| 157 | } |
|---|
| 158 | |
|---|
| 159 | // Outputs description of the command for the -help option. |
|---|
| 160 | virtual void describe() { |
|---|
| 161 | // Don't show the option if it has no desciption. |
|---|
| 162 | if (!desc.empty()) { |
|---|
| 163 | const unsigned int WIDTH=22; |
|---|
| 164 | mem::string start=describeStart(); |
|---|
| 165 | cerr << std::left << std::setw(WIDTH) << start; |
|---|
| 166 | if (start.size() >= WIDTH) { |
|---|
| 167 | cerr << endl; |
|---|
| 168 | cerr << std::left << std::setw(WIDTH) << ""; |
|---|
| 169 | } |
|---|
| 170 | cerr << desc << endl; |
|---|
| 171 | } |
|---|
| 172 | } |
|---|
| 173 | }; |
|---|
| 174 | |
|---|
| 175 | const mem::string noarg; |
|---|
| 176 | |
|---|
| 177 | struct setting : public option { |
|---|
| 178 | types::ty *t; |
|---|
| 179 | |
|---|
| 180 | setting(mem::string name, char code, mem::string argname, mem::string desc, |
|---|
| 181 | types::ty *t) |
|---|
| 182 | : option(name, code, argname, desc), t(t) {} |
|---|
| 183 | |
|---|
| 184 | virtual void reset() = 0; |
|---|
| 185 | |
|---|
| 186 | virtual trans::access *buildAccess() = 0; |
|---|
| 187 | |
|---|
| 188 | // Add to the dictionaries of options and to the settings module. |
|---|
| 189 | virtual void add() { |
|---|
| 190 | option::add(); |
|---|
| 191 | |
|---|
| 192 | settingsModule->e.addVar(symbol::trans(name), buildVarEntry()); |
|---|
| 193 | } |
|---|
| 194 | |
|---|
| 195 | varEntry *buildVarEntry() { |
|---|
| 196 | return new varEntry(t, buildAccess()); |
|---|
| 197 | } |
|---|
| 198 | }; |
|---|
| 199 | |
|---|
| 200 | struct itemSetting : public setting { |
|---|
| 201 | item defaultValue; |
|---|
| 202 | item value; |
|---|
| 203 | |
|---|
| 204 | itemSetting(mem::string name, char code, |
|---|
| 205 | mem::string argname, mem::string desc, |
|---|
| 206 | types::ty *t, item defaultValue) |
|---|
| 207 | : setting(name, code, argname, desc, t), defaultValue(defaultValue) { |
|---|
| 208 | reset(); |
|---|
| 209 | } |
|---|
| 210 | |
|---|
| 211 | void reset() { |
|---|
| 212 | value=defaultValue; |
|---|
| 213 | } |
|---|
| 214 | |
|---|
| 215 | trans::access *buildAccess() { |
|---|
| 216 | return new itemRefAccess(&(value)); |
|---|
| 217 | } |
|---|
| 218 | }; |
|---|
| 219 | |
|---|
| 220 | item& Setting(string name) { |
|---|
| 221 | itemSetting *s=dynamic_cast<itemSetting *>(optionsMap[name]); |
|---|
| 222 | assert(s); |
|---|
| 223 | return s->value; |
|---|
| 224 | } |
|---|
| 225 | |
|---|
| 226 | struct boolSetting : public itemSetting { |
|---|
| 227 | boolSetting(mem::string name, char code, mem::string desc, |
|---|
| 228 | bool defaultValue=false) |
|---|
| 229 | : itemSetting(name, code, noarg, desc, |
|---|
| 230 | types::primBoolean(), (item)defaultValue) {} |
|---|
| 231 | |
|---|
| 232 | bool getOption() { |
|---|
| 233 | value=(item)true; |
|---|
| 234 | return true; |
|---|
| 235 | } |
|---|
| 236 | |
|---|
| 237 | option *negation(mem::string name) { |
|---|
| 238 | struct negOption : public option { |
|---|
| 239 | boolSetting &base; |
|---|
| 240 | |
|---|
| 241 | negOption(boolSetting &base, mem::string name) |
|---|
| 242 | : option(name, 0, noarg, ""), base(base) {} |
|---|
| 243 | |
|---|
| 244 | bool getOption() { |
|---|
| 245 | base.value=(item)false; |
|---|
| 246 | return true; |
|---|
| 247 | } |
|---|
| 248 | }; |
|---|
| 249 | return new negOption(*this, name); |
|---|
| 250 | } |
|---|
| 251 | |
|---|
| 252 | void add() { |
|---|
| 253 | setting::add(); |
|---|
| 254 | negation("no"+name)->add(); |
|---|
| 255 | if (code) { |
|---|
| 256 | mem::string nocode="no"; nocode.push_back(code); |
|---|
| 257 | negation(nocode)->add(); |
|---|
| 258 | } |
|---|
| 259 | } |
|---|
| 260 | |
|---|
| 261 | // Set several related boolean options at once. Used for view and trap which |
|---|
| 262 | // have batch and interactive settings. |
|---|
| 263 | struct multiOption : public option { |
|---|
| 264 | typedef mem::list<boolSetting *> setlist; |
|---|
| 265 | setlist set; |
|---|
| 266 | multiOption(mem::string name, char code, mem::string desc) |
|---|
| 267 | : option(name, code, noarg, desc) {} |
|---|
| 268 | |
|---|
| 269 | void add(boolSetting *s) { |
|---|
| 270 | set.push_back(s); |
|---|
| 271 | } |
|---|
| 272 | |
|---|
| 273 | void setValue(bool value) { |
|---|
| 274 | for (setlist::iterator s=set.begin(); s!=set.end(); ++s) |
|---|
| 275 | (*s)->value=(item)value; |
|---|
| 276 | } |
|---|
| 277 | |
|---|
| 278 | bool getOption() { |
|---|
| 279 | setValue(true); |
|---|
| 280 | return true; |
|---|
| 281 | } |
|---|
| 282 | |
|---|
| 283 | option *negation(mem::string name) { |
|---|
| 284 | struct negOption : public option { |
|---|
| 285 | multiOption &base; |
|---|
| 286 | |
|---|
| 287 | negOption(multiOption &base, mem::string name) |
|---|
| 288 | : option(name, 0, noarg, ""), base(base) {} |
|---|
| 289 | |
|---|
| 290 | bool getOption() { |
|---|
| 291 | base.setValue(false); |
|---|
| 292 | return true; |
|---|
| 293 | } |
|---|
| 294 | }; |
|---|
| 295 | return new negOption(*this, name); |
|---|
| 296 | } |
|---|
| 297 | |
|---|
| 298 | void add() { |
|---|
| 299 | option::add(); |
|---|
| 300 | negation("no"+name)->add(); |
|---|
| 301 | if (code) { |
|---|
| 302 | mem::string nocode="no"; nocode.push_back(code); |
|---|
| 303 | negation(nocode)->add(); |
|---|
| 304 | } |
|---|
| 305 | |
|---|
| 306 | for (multiOption::setlist::iterator s=set.begin(); s!=set.end(); ++s) |
|---|
| 307 | (*s)->add(); |
|---|
| 308 | } |
|---|
| 309 | }; |
|---|
| 310 | }; |
|---|
| 311 | |
|---|
| 312 | typedef boolSetting::multiOption multiOption; |
|---|
| 313 | |
|---|
| 314 | struct argumentSetting : public itemSetting { |
|---|
| 315 | argumentSetting(mem::string name, char code, |
|---|
| 316 | mem::string argname, mem::string desc, |
|---|
| 317 | types::ty *t, item defaultValue) |
|---|
| 318 | : itemSetting(name, code, argname, desc, t, defaultValue) |
|---|
| 319 | { |
|---|
| 320 | assert(!argname.empty()); |
|---|
| 321 | } |
|---|
| 322 | }; |
|---|
| 323 | |
|---|
| 324 | struct stringSetting : public argumentSetting { |
|---|
| 325 | stringSetting(mem::string name, char code, |
|---|
| 326 | mem::string argname, mem::string desc, |
|---|
| 327 | mem::string defaultValue) |
|---|
| 328 | : argumentSetting(name, code, argname, desc, |
|---|
| 329 | types::primString(), (item)defaultValue) {} |
|---|
| 330 | |
|---|
| 331 | bool getOption() { |
|---|
| 332 | value=(item)(mem::string)optarg; |
|---|
| 333 | return true; |
|---|
| 334 | } |
|---|
| 335 | }; |
|---|
| 336 | |
|---|
| 337 | mem::string GetEnv(mem::string s, mem::string Default) { |
|---|
| 338 | transform(s.begin(), s.end(), s.begin(), toupper); |
|---|
| 339 | string t=Getenv(("ASYMPTOTE_"+s).c_str()); |
|---|
| 340 | return t != "" ? mem::string(t) : Default; |
|---|
| 341 | } |
|---|
| 342 | |
|---|
| 343 | struct envSetting : public stringSetting { |
|---|
| 344 | envSetting(mem::string name, mem::string Default) |
|---|
| 345 | : stringSetting(name, 0, " ", "", GetEnv(name,Default)) {} |
|---|
| 346 | }; |
|---|
| 347 | |
|---|
| 348 | struct realSetting : public argumentSetting { |
|---|
| 349 | realSetting(mem::string name, char code, |
|---|
| 350 | mem::string argname, mem::string desc, |
|---|
| 351 | double defaultValue) |
|---|
| 352 | : argumentSetting(name, code, argname, desc, |
|---|
| 353 | types::primReal(), (item)defaultValue) {} |
|---|
| 354 | |
|---|
| 355 | bool getOption() { |
|---|
| 356 | try { |
|---|
| 357 | value=(item)lexical::cast<double>(optarg); |
|---|
| 358 | } catch (lexical::bad_cast&) { |
|---|
| 359 | error("option requires a real number as an argument"); |
|---|
| 360 | return false; |
|---|
| 361 | } |
|---|
| 362 | return true; |
|---|
| 363 | } |
|---|
| 364 | }; |
|---|
| 365 | |
|---|
| 366 | struct pairSetting : public argumentSetting { |
|---|
| 367 | pairSetting(mem::string name, char code, |
|---|
| 368 | mem::string argname, mem::string desc, |
|---|
| 369 | camp::pair defaultValue=0.0) |
|---|
| 370 | : argumentSetting(name, code, argname, desc, |
|---|
| 371 | types::primPair(), (item)defaultValue) {} |
|---|
| 372 | |
|---|
| 373 | bool getOption() { |
|---|
| 374 | try { |
|---|
| 375 | value=(item)lexical::cast<camp::pair>(optarg); |
|---|
| 376 | } catch (lexical::bad_cast&) { |
|---|
| 377 | error("option requires a pair as an argument"); |
|---|
| 378 | return false; |
|---|
| 379 | } |
|---|
| 380 | return true; |
|---|
| 381 | } |
|---|
| 382 | }; |
|---|
| 383 | |
|---|
| 384 | // For setting the alignment of a figure on the page. |
|---|
| 385 | struct alignSetting : public argumentSetting { |
|---|
| 386 | alignSetting(mem::string name, char code, |
|---|
| 387 | mem::string argname, mem::string desc, |
|---|
| 388 | int defaultValue=CENTER) |
|---|
| 389 | : argumentSetting(name, code, argname, desc, |
|---|
| 390 | types::primInt(), (item)defaultValue) {} |
|---|
| 391 | |
|---|
| 392 | bool getOption() { |
|---|
| 393 | mem::string str=optarg; |
|---|
| 394 | if (str=="C") |
|---|
| 395 | value=(int)CENTER; |
|---|
| 396 | else if (str=="T") |
|---|
| 397 | value=(int)TOP; |
|---|
| 398 | else if (str=="B") |
|---|
| 399 | value=(int)BOTTOM; |
|---|
| 400 | else if (str=="Z") { |
|---|
| 401 | value=(int)ZERO; |
|---|
| 402 | Setting("tex")=false; |
|---|
| 403 | } |
|---|
| 404 | else { |
|---|
| 405 | error("invalid argument for option"); |
|---|
| 406 | return false; |
|---|
| 407 | } |
|---|
| 408 | return true; |
|---|
| 409 | } |
|---|
| 410 | }; |
|---|
| 411 | |
|---|
| 412 | template <class T> |
|---|
| 413 | struct refSetting : public setting { |
|---|
| 414 | T *ref; |
|---|
| 415 | T defaultValue; |
|---|
| 416 | |
|---|
| 417 | refSetting(mem::string name, char code, mem::string argname, |
|---|
| 418 | mem::string desc, types::ty *t, T *ref, T defaultValue) |
|---|
| 419 | : setting(name, code, argname, desc, t), |
|---|
| 420 | ref(ref), defaultValue(defaultValue) { |
|---|
| 421 | reset(); |
|---|
| 422 | } |
|---|
| 423 | |
|---|
| 424 | virtual void reset() { |
|---|
| 425 | *ref=defaultValue; |
|---|
| 426 | } |
|---|
| 427 | |
|---|
| 428 | trans::access *buildAccess() { |
|---|
| 429 | return new refAccess<T>(ref); |
|---|
| 430 | } |
|---|
| 431 | }; |
|---|
| 432 | |
|---|
| 433 | struct incrementSetting : public refSetting<int> { |
|---|
| 434 | incrementSetting(mem::string name, char code, mem::string desc, int *ref) |
|---|
| 435 | : refSetting<int>(name, code, noarg, desc, |
|---|
| 436 | types::primInt(), ref, 0) {} |
|---|
| 437 | |
|---|
| 438 | bool getOption() { |
|---|
| 439 | // Increment the value. |
|---|
| 440 | ++(*ref); |
|---|
| 441 | return true; |
|---|
| 442 | } |
|---|
| 443 | |
|---|
| 444 | option *negation(mem::string name) { |
|---|
| 445 | struct negOption : public option { |
|---|
| 446 | incrementSetting &base; |
|---|
| 447 | |
|---|
| 448 | negOption(incrementSetting &base, mem::string name) |
|---|
| 449 | : option(name, 0, noarg, ""), base(base) {} |
|---|
| 450 | |
|---|
| 451 | bool getOption() { |
|---|
| 452 | if(*base.ref) --(*base.ref); |
|---|
| 453 | return true; |
|---|
| 454 | } |
|---|
| 455 | }; |
|---|
| 456 | return new negOption(*this, name); |
|---|
| 457 | } |
|---|
| 458 | |
|---|
| 459 | void add() { |
|---|
| 460 | setting::add(); |
|---|
| 461 | negation("no"+name)->add(); |
|---|
| 462 | if (code) { |
|---|
| 463 | mem::string nocode="no"; nocode.push_back(code); |
|---|
| 464 | negation(nocode)->add(); |
|---|
| 465 | } |
|---|
| 466 | } |
|---|
| 467 | }; |
|---|
| 468 | |
|---|
| 469 | void addOption(option *o) { |
|---|
| 470 | o->add(); |
|---|
| 471 | } |
|---|
| 472 | |
|---|
| 473 | void usage(const char *program) |
|---|
| 474 | { |
|---|
| 475 | cerr << PROGRAM << " version " << VERSION |
|---|
| 476 | << " [(C) 2004 Andy Hammerlindl, John C. Bowman, Tom Prince]" |
|---|
| 477 | << endl |
|---|
| 478 | << "\t\t\t" << "http://asymptote.sourceforge.net/" |
|---|
| 479 | << endl |
|---|
| 480 | << "Usage: " << program << " [options] [file ...]" |
|---|
| 481 | << endl; |
|---|
| 482 | } |
|---|
| 483 | |
|---|
| 484 | void reportSyntax() { |
|---|
| 485 | cerr << endl; |
|---|
| 486 | usage(argv0); |
|---|
| 487 | cerr << endl << "Type '" << argv0 |
|---|
| 488 | << " -h' for a description of options." << endl; |
|---|
| 489 | exit(1); |
|---|
| 490 | } |
|---|
| 491 | |
|---|
| 492 | void displayOptions() |
|---|
| 493 | { |
|---|
| 494 | cerr << endl; |
|---|
| 495 | cerr << "Options: " << endl; |
|---|
| 496 | for (optionsMap_t::iterator opt=optionsMap.begin(); |
|---|
| 497 | opt!=optionsMap.end(); |
|---|
| 498 | ++opt) |
|---|
| 499 | opt->second->describe(); |
|---|
| 500 | } |
|---|
| 501 | |
|---|
| 502 | struct helpOption : public option { |
|---|
| 503 | helpOption(mem::string name, char code, mem::string desc) |
|---|
| 504 | : option(name, code, noarg, desc) {} |
|---|
| 505 | |
|---|
| 506 | bool getOption() { |
|---|
| 507 | usage(argv0); |
|---|
| 508 | displayOptions(); |
|---|
| 509 | cerr << endl; |
|---|
| 510 | exit(0); |
|---|
| 511 | |
|---|
| 512 | // Unreachable code. |
|---|
| 513 | return true; |
|---|
| 514 | } |
|---|
| 515 | }; |
|---|
| 516 | |
|---|
| 517 | // For security reasons, safe isn't a field of the settings module. |
|---|
| 518 | struct safeOption : public option { |
|---|
| 519 | bool value; |
|---|
| 520 | |
|---|
| 521 | safeOption(mem::string name, char code, mem::string desc, bool value) |
|---|
| 522 | : option(name, code, noarg, desc), value(value) {} |
|---|
| 523 | |
|---|
| 524 | bool getOption() { |
|---|
| 525 | safe=value; |
|---|
| 526 | return true; |
|---|
| 527 | } |
|---|
| 528 | }; |
|---|
| 529 | |
|---|
| 530 | |
|---|
| 531 | mem::string build_optstring() { |
|---|
| 532 | mem::string s; |
|---|
| 533 | for (codeMap_t::iterator p=codeMap.begin(); p !=codeMap.end(); ++p) |
|---|
| 534 | s +=p->second->optstring(); |
|---|
| 535 | |
|---|
| 536 | return s; |
|---|
| 537 | } |
|---|
| 538 | |
|---|
| 539 | c_option *build_longopts() { |
|---|
| 540 | size_t n=optionsMap.size(); |
|---|
| 541 | |
|---|
| 542 | #ifdef USEGC |
|---|
| 543 | c_option *longopts=new (GC) c_option[n]; |
|---|
| 544 | #else |
|---|
| 545 | c_option *longopts=new c_option[n]; |
|---|
| 546 | #endif |
|---|
| 547 | |
|---|
| 548 | int i=0; |
|---|
| 549 | for (optionsMap_t::iterator p=optionsMap.begin(); |
|---|
| 550 | p !=optionsMap.end(); |
|---|
| 551 | ++p, ++i) |
|---|
| 552 | p->second->longopt(longopts[i]); |
|---|
| 553 | |
|---|
| 554 | return longopts; |
|---|
| 555 | } |
|---|
| 556 | |
|---|
| 557 | void resetOptions() { |
|---|
| 558 | verbose=0; |
|---|
| 559 | } |
|---|
| 560 | |
|---|
| 561 | void getOptions(int argc, char *argv[]) |
|---|
| 562 | { |
|---|
| 563 | bool syntax=false; |
|---|
| 564 | optind=0; |
|---|
| 565 | |
|---|
| 566 | mem::string optstring=build_optstring(); |
|---|
| 567 | //cerr << "optstring: " << optstring << endl; |
|---|
| 568 | c_option *longopts=build_longopts(); |
|---|
| 569 | int long_index = 0; |
|---|
| 570 | |
|---|
| 571 | errno=0; |
|---|
| 572 | for(;;) { |
|---|
| 573 | int c = getopt_long_only(argc,argv, |
|---|
| 574 | optstring.c_str(), longopts, &long_index); |
|---|
| 575 | if (c == -1) |
|---|
| 576 | break; |
|---|
| 577 | |
|---|
| 578 | if (c == 0) { |
|---|
| 579 | const char *name=longopts[long_index].name; |
|---|
| 580 | //cerr << "long option: " << name << endl; |
|---|
| 581 | if (!optionsMap[name]->getOption()) |
|---|
| 582 | syntax=true; |
|---|
| 583 | } |
|---|
| 584 | else if (codeMap.find((char)c) != codeMap.end()) { |
|---|
| 585 | //cerr << "char option: " << (char)c << endl; |
|---|
| 586 | if (!codeMap[(char)c]->getOption()) |
|---|
| 587 | syntax=true; |
|---|
| 588 | } |
|---|
| 589 | else { |
|---|
| 590 | syntax=true; |
|---|
| 591 | } |
|---|
| 592 | |
|---|
| 593 | errno=0; |
|---|
| 594 | } |
|---|
| 595 | |
|---|
| 596 | if (syntax) |
|---|
| 597 | reportSyntax(); |
|---|
| 598 | } |
|---|
| 599 | |
|---|
| 600 | // The verbosity setting, a global variable. |
|---|
| 601 | int verbose; |
|---|
| 602 | |
|---|
| 603 | void initSettings() { |
|---|
| 604 | settingsModule=new types::dummyRecord(symbol::trans("settings")); |
|---|
| 605 | |
|---|
| 606 | multiOption *view=new multiOption("View", 'V', "View output files"); |
|---|
| 607 | view->add(new boolSetting("batchView", 0, |
|---|
| 608 | "View output files in batch mode", false)); |
|---|
| 609 | view->add(new boolSetting("interactiveView", 0, |
|---|
| 610 | "View output files in interactive mode", true)); |
|---|
| 611 | view->add(new boolSetting("oneFileView", 0, "", msdos)); |
|---|
| 612 | addOption(view); |
|---|
| 613 | |
|---|
| 614 | addOption(new realSetting("deconstruct", 'x', "X", |
|---|
| 615 | "Deconstruct into transparent GIF objects magnified by X", |
|---|
| 616 | 0.0)); |
|---|
| 617 | addOption(new boolSetting("clearGUI", 'c', "Clear GUI operations")); |
|---|
| 618 | addOption(new boolSetting("ignoreGUI", 'i', "Ignore GUI operations")); |
|---|
| 619 | addOption(new stringSetting("outformat", 'f', "format", |
|---|
| 620 | "Convert each output file to specified format", |
|---|
| 621 | "eps")); |
|---|
| 622 | addOption(new stringSetting("outname", 'o', "name", |
|---|
| 623 | "(First) output file name", "")); |
|---|
| 624 | addOption(new helpOption("help", 'h', "Show summary of options")); |
|---|
| 625 | |
|---|
| 626 | addOption(new pairSetting("offset", 'O', "pair", "PostScript offset")); |
|---|
| 627 | addOption(new alignSetting("align", 'a', "C|B|T|Z", |
|---|
| 628 | "Center, Bottom, Top or Zero page alignment; Z => -notex")); |
|---|
| 629 | |
|---|
| 630 | addOption(new boolSetting("debug", 'd', "Enable debugging messages")); |
|---|
| 631 | addOption(new incrementSetting("verbose", 'v', |
|---|
| 632 | "Increase verbosity level", &verbose)); |
|---|
| 633 | addOption(new boolSetting("keep", 'k', "Keep intermediate files")); |
|---|
| 634 | addOption(new boolSetting("tex", 0, |
|---|
| 635 | "Enable LaTeX label postprocessing (default)", |
|---|
| 636 | true)); |
|---|
| 637 | addOption(new boolSetting("inlinetex", 0, "")); |
|---|
| 638 | addOption(new boolSetting("parseonly", 'p', "Parse test")); |
|---|
| 639 | addOption(new boolSetting("translate", 's', "Translate test")); |
|---|
| 640 | addOption(new boolSetting("listvariables", 'l', |
|---|
| 641 | "List available global functions and variables")); |
|---|
| 642 | |
|---|
| 643 | multiOption *mask=new multiOption("mask", 'm', |
|---|
| 644 | "Mask fpu exceptions"); |
|---|
| 645 | mask->add(new boolSetting("batchMask", 0, |
|---|
| 646 | "Mask fpu exceptions in batch mode", false)); |
|---|
| 647 | mask->add(new boolSetting("interactiveMask", 0, |
|---|
| 648 | "Mask fpu exceptions in interactive mode", true)); |
|---|
| 649 | addOption(mask); |
|---|
| 650 | |
|---|
| 651 | addOption(new boolSetting("bw", 0, |
|---|
| 652 | "Convert all colors to black and white")); |
|---|
| 653 | addOption(new boolSetting("gray", 0, "Convert all colors to grayscale")); |
|---|
| 654 | addOption(new boolSetting("rgb", 0, "Convert cmyk colors to rgb")); |
|---|
| 655 | addOption(new boolSetting("cmyk", 0, "Convert rgb colors to cmyk")); |
|---|
| 656 | |
|---|
| 657 | addOption(new safeOption("safe", 0, |
|---|
| 658 | "Disable system call (default)", true)); |
|---|
| 659 | addOption(new safeOption("unsafe", 0, |
|---|
| 660 | "Enable system call", false)); |
|---|
| 661 | |
|---|
| 662 | addOption(new boolSetting("localhistory", 0, |
|---|
| 663 | "Use a local interactive history file")); |
|---|
| 664 | addOption(new boolSetting("autoplain", 0, |
|---|
| 665 | "Enable automatic importing of plain (default)", |
|---|
| 666 | true)); |
|---|
| 667 | |
|---|
| 668 | addOption(new envSetting("config",initdir+"/config.asy")); |
|---|
| 669 | addOption(new envSetting("pdfviewer", defaultPDFViewer)); |
|---|
| 670 | addOption(new envSetting("psviewer", defaultPSViewer)); |
|---|
| 671 | addOption(new envSetting("gs", defaultGhostscript)); |
|---|
| 672 | addOption(new envSetting("latex", "latex")); |
|---|
| 673 | addOption(new envSetting("dvips", "dvips")); |
|---|
| 674 | addOption(new envSetting("convert", "convert")); |
|---|
| 675 | addOption(new envSetting("display", defaultDisplay)); |
|---|
| 676 | addOption(new envSetting("animate", "animate")); |
|---|
| 677 | addOption(new envSetting("python", defaultPython)); |
|---|
| 678 | addOption(new envSetting("xasy", "xasy")); |
|---|
| 679 | addOption(new envSetting("papertype", "letter")); |
|---|
| 680 | addOption(new envSetting("dir", "")); |
|---|
| 681 | |
|---|
| 682 | } |
|---|
| 683 | |
|---|
| 684 | int safe=1; |
|---|
| 685 | int ShipoutNumber=0; |
|---|
| 686 | int scrollLines=0; |
|---|
| 687 | |
|---|
| 688 | const string suffix="asy"; |
|---|
| 689 | const string guisuffix="gui"; |
|---|
| 690 | |
|---|
| 691 | bool TeXinitialized=false; |
|---|
| 692 | string initdir; |
|---|
| 693 | |
|---|
| 694 | camp::pen defaultpen=camp::pen::startupdefaultpen(); |
|---|
| 695 | |
|---|
| 696 | // Local versions of the argument list. |
|---|
| 697 | int argCount = 0; |
|---|
| 698 | char **argList = 0; |
|---|
| 699 | |
|---|
| 700 | // Access the arguments once options have been parsed. |
|---|
| 701 | int numArgs() { return argCount; } |
|---|
| 702 | char *getArg(int n) { return argList[n]; } |
|---|
| 703 | |
|---|
| 704 | void setInteractive() { |
|---|
| 705 | if(numArgs() == 0 && !getSetting<bool>("listvariables")) |
|---|
| 706 | interact::interactive=true; |
|---|
| 707 | } |
|---|
| 708 | |
|---|
| 709 | bool view() { |
|---|
| 710 | if (interact::interactive) |
|---|
| 711 | return getSetting<bool>("interactiveView"); |
|---|
| 712 | else |
|---|
| 713 | return getSetting<bool>("batchView") || |
|---|
| 714 | (numArgs()==1 && getSetting<bool>("oneFileView")); |
|---|
| 715 | } |
|---|
| 716 | |
|---|
| 717 | bool trap() { |
|---|
| 718 | if (interact::interactive) |
|---|
| 719 | return !getSetting<bool>("interactiveMask"); |
|---|
| 720 | else |
|---|
| 721 | return !getSetting<bool>("batchMask"); |
|---|
| 722 | } |
|---|
| 723 | |
|---|
| 724 | void initDir() { |
|---|
| 725 | initdir=Getenv("HOME",false)+"/.asy"; |
|---|
| 726 | mkdir(initdir.c_str(),0xFFFF); |
|---|
| 727 | } |
|---|
| 728 | |
|---|
| 729 | void setPath() { |
|---|
| 730 | searchPath.push_back("."); |
|---|
| 731 | string asydir=getSetting<mem::string>("dir"); |
|---|
| 732 | if(asydir != "") { |
|---|
| 733 | size_t p,i=0; |
|---|
| 734 | while((p=asydir.find(pathSeparator,i)) < string::npos) { |
|---|
| 735 | if(p > i) searchPath.push_back(asydir.substr(i,p-i)); |
|---|
| 736 | i=p+1; |
|---|
| 737 | } |
|---|
| 738 | if(i < asydir.length()) searchPath.push_back(asydir.substr(i)); |
|---|
| 739 | } |
|---|
| 740 | #ifdef ASYMPTOTE_SYSDIR |
|---|
| 741 | searchPath.push_back(ASYMPTOTE_SYSDIR); |
|---|
| 742 | #endif |
|---|
| 743 | } |
|---|
| 744 | |
|---|
| 745 | void GetPageDimensions(double& pageWidth, double& pageHeight) { |
|---|
| 746 | string paperType=getSetting<mem::string>("papertype"); |
|---|
| 747 | |
|---|
| 748 | if(paperType == "letter") { |
|---|
| 749 | pageWidth=72.0*8.5; |
|---|
| 750 | pageHeight=72.0*11.0; |
|---|
| 751 | } else { |
|---|
| 752 | pageWidth=72.0*21.0/2.54; |
|---|
| 753 | pageHeight=72.0*29.7/2.54; |
|---|
| 754 | if(paperType != "a4") { |
|---|
| 755 | cerr << "Unknown paper size \'" << paperType << "\'; assuming a4." |
|---|
| 756 | << endl; |
|---|
| 757 | Setting("papertype")=mem::string("a4"); |
|---|
| 758 | } |
|---|
| 759 | } |
|---|
| 760 | } |
|---|
| 761 | |
|---|
| 762 | void setOptions(int argc, char *argv[]) |
|---|
| 763 | { |
|---|
| 764 | argv0=argv[0]; |
|---|
| 765 | |
|---|
| 766 | // Make configuration and history directory |
|---|
| 767 | initDir(); |
|---|
| 768 | |
|---|
| 769 | // Build settings module. |
|---|
| 770 | initSettings(); |
|---|
| 771 | |
|---|
| 772 | // Read command-line options initially to obtain CONFIG and DIR. |
|---|
| 773 | getOptions(argc,argv); |
|---|
| 774 | resetOptions(); |
|---|
| 775 | |
|---|
| 776 | // Read user configuration file. |
|---|
| 777 | setPath(); |
|---|
| 778 | loop::doConfig(getSetting<mem::string>("config")); |
|---|
| 779 | |
|---|
| 780 | // Read command-line options again to override configuration file defaults. |
|---|
| 781 | getOptions(argc,argv); |
|---|
| 782 | |
|---|
| 783 | // Set variables for the normal arguments. |
|---|
| 784 | argCount = argc - optind; |
|---|
| 785 | argList = argv + optind; |
|---|
| 786 | |
|---|
| 787 | setInteractive(); |
|---|
| 788 | } |
|---|
| 789 | |
|---|
| 790 | } |
|---|