/*
** Astrolog (Version 4.00) File: driver.c
**
** IMPORTANT NOTICE: the graphics database and chart display routines
** used in this program are Copyright (C) 1991-1993 by Walter D. Pullen
** (cruiser1@stein.u.washington.edu). Permission is granted to freely
** use and distribute these routines provided one doesn't sell,
** restrict, or profit from them in any way. Modification is allowed
** provided these notices remain with any altered or edited versions of
** the program.
**
** The main planetary calculation routines used in this program have
** been Copyrighted and the core of this program is basically a
** conversion to C of the routines created by James Neely as listed in
** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
** available from Matrix Software. The copyright gives us permission to
** use the routines for personal use but not to sell them or profit from
** them in any way.
**
** The PostScript code within the core graphics routines are programmed
** and Copyright (C) 1992-1993 by Brian D. Willoughby
** (brianw@sounds.wa.com). Conditions are identical to those above.
**
** The extended accurate ephemeris databases and formulas are from the
** calculation routines in the program "Placalc" and are programmed and
** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
** (alois@azur.ch). The use of that source code is subject to
** regulations made by Astrodienst Zurich, and the code is not in the
** public domain. This copyright notice must not be changed or removed
** by any user of this program.
**
** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
** X Window graphics initially programmed 10/23-29/1991.
** PostScript graphics initially programmed 11/29-30/1992.
** Last code change made 12/31/1993.
*/

#include "astrolog.h"

char *filenamescreen = NULL, *filenameout, **extralines;
int prog = FALSE, extracount = 0;


/*
******************************************************************************
** Table Display Routines.
******************************************************************************
*/

/* A subprocedure of the credit displayed below, this prints out one line */
/* of credit information on the screen. Given a string, it's displayed    */
/* centered with left and right borders around it, in the given color.    */

#define CREDITWIDTH 74

void PrintW(string, col)
char *string;
int col;
{
  int i;

  if (!string) {

    /* Null string means print the top, bottom, or a separator row. */

    if (col < 0)
      AnsiColor(RED);
    printc(col ? (col > 0 ? BOXSW : BOXNW) : BOXJE);
    PrintTab(BOXH, CREDITWIDTH);
    printc(col ? (col > 0 ? BOXSE : BOXNE) : BOXJW);
  } else {
    i = StringLen(string);
    printc(BOXV);
    PrintTab(' ', (CREDITWIDTH-i)/2 + (i&1));
    AnsiColor(col);
    fprintf(S, "%s", string);
    PrintTab(' ', (CREDITWIDTH-i)/2);
    AnsiColor(RED);
    printc(BOXV);
  }
  printl();
}


/* Display a list of credits showing those who helped create the various  */
/* parts of Astrolog, as well as important copyright and version info, as */
/* displayed with the -Hc switch.                                         */

void DisplayCredits()
{
  char string[STRING];

  PrintW(NULL, -1);
  sprintf(string, "%s version %s", appname, VERSION);
  PrintW(string, WHITE);
  sprintf(string, "As of %s", DATE);
  PrintW(string, LTGRAY);
  PrintW("By Walter D. Pullen (cruiser1@stein.u.washington.edu)", CYAN);
  PrintW(NULL, 0);
  PrintW("Main planetary calculation formulas were converted from", GREEN);
  PrintW(
    "routines by James Neely, as listed in 'Manual of Computer Programming",
    GREEN);
  PrintW(
    "for Astrologers' by Michael Erlewine, available from Matrix Software.",
    GREEN);
  PrintW("PostScript graphics routines by Brian D. Willoughby", YELLOW);
  PrintW(
    "Extended ephemeris calculation and formulas are by Alois Treindl,",
    MAGENTA);
  PrintW(
    "as in the package 'Placalc', available from Astrodienst AG.", MAGENTA);
  PrintW(
    "IMPORTANT: Astrolog is 'freeware', but is copyrighted and not in public",
    LTGRAY);
  PrintW(
    "domain. Permission is granted to freely use and distribute these",
    LTGRAY);
  PrintW(
    "routines provided one does not sell, restrict, or profit from the",
    LTGRAY);
  PrintW(
    "program or its output in any way. Modification is allowed provided",
    LTGRAY);
  PrintW(
    "these exact notices remain with any altered or edited versions of the",
    LTGRAY);
  PrintW(
    "program. These conditions are true of both the program in whole and of",
    LTGRAY);
  PrintW(
    "all parts by any individual author. Violators are subject to copyright",
    LTGRAY);
  PrintW(
    "law penalties, and negative karmic debts to aforementioned contributors.",
    LTGRAY);
  PrintW(NULL, 0);
  PrintW(
    "Special thanks to all those unmentioned, seen and unseen, who have",
     BLUE);
  PrintW(
    "pointed out problems, suggested featues, and sent many positive vibes!",
    BLUE);
  PrintW(NULL, 1);
  AnsiColor(DEFAULT);
}


/* Print out a command switch or keypress info line to the screen, as done  */
/* with the -H switch or 'H' key in a graphic window. This is just printing */
/* out the string, except in Ansi mode we set the proper colors: Red for    */
/* header lines, Green for individual switches or keys, and White for the   */
/* rest of the line telling what it does. We also prefix each switch with   */
/* either Unix's '-' or PC's '/', whichever is appropriate for the system.  */

void Prints(string)
char *string;
{
  int dash;
  char c;

  dash = string[1];
  if (*string != ' ')
    AnsiColor(RED);
  else if (dash != ' ')
    AnsiColor(dash == 'P' || string[3] == ' ' || string[3] == ':' ?
      GREEN : DKGREEN);
  else
    AnsiColor(DEFAULT);
  while ((c = *string) && c != ':' &&
    (dash != 'P' || (c != ' ' || *(string+1) != 't'))) {
    if (c != '_')
      printc(c);
    else
      printc(DASH);
    string++;
  }
  if (*string)
    printc(*string++);
  AnsiColor(DEFAULT);
  while (c = *string) {
    if (c != '_')
      printc(c);
    else
      printc(DASH);
    string++;
  }
  printl();
}


/* Print a list of every command switch that can be passed to the program, */
/* and a description of what it does. This is what the -H switch prints.   */

void DisplaySwitches()
{
  char string[STRING];

  sprintf(string, "%s (version %s) command switches:", appname, VERSION);
  Prints(string);
  Prints(" _H: Display this help list.");
  Prints(" _Hc: Display program credits and copyrights.");
  Prints(" _H0: Display names of zodiac signs and houses.");
  Prints(" _O: Display available planets and other celestial objects.");
  Prints(" _O0: Like _O but ignore object restrictions.");
  Prints(" _A: Display available aspects, their angles, and present orbs.");
#ifdef INTERPRET
  Prints(" _I0: Display meanings of signs, houses, planets, and aspects.");
#endif
  Prints(" _Q: Prompt for more command switches after display finished.");
#ifdef SWITCHES
  Prints(" _Q0: Like _Q but prompt for additional switches on startup.");
#endif
  Prints("\nSwitches which determine the type of chart to display:");
  Prints(" _v: Display list of object positions (chosen by default).");
  Prints(" _v0: Like _v but express velocities relative to average speed.");
  Prints(" _w [<rows>]: Display chart in a graphic house wheel format.");
  Prints(" _w0 [..]: Like _w but reverse order of objects in houses 4..9.");
  Prints(" _g: Display aspect and midpoint grid among planets.");
  Prints(" _g0: Like _g but flag aspect configurations (e.g. Yod's) too.");
  Prints(" _g0: For comparison charts, show midpoints instead of aspects.");
  Prints(" _ga: Like _g but indicate applying instead of difference orbs.");
  Prints(" _m: Display all object midpoints in sorted zodiac order.");
  Prints(" _m0: Like _m but list aspects ordered by influence instead.");
  Prints(" _m[0]a: Like _m0 but indicate applying and separating orbs.");
  Prints(" _Z: Display planet locations with respect to the local horizon.");
#ifdef GRAPH
  Prints(" _Z0: For graphics charts, like _Z but have a polar center.");
#endif
  Prints(" _Zd: Search day for object local rising and setting times.");
  Prints(" _S: Display x,y,z coordinate positions of planets in space.");
  Prints(" _j: Display astrological influences of each object in chart.");
  Prints(" _j0: Like _j but include influences of each zodiac sign as well.");
  Prints(" _L [<step>]: Display astro-graph locations of planetary angles.");
  Prints(" _L0 [..]: Like _L but display list of latitude crossings too.");
  Prints(" _K: Display a calendar for given month.");
  Prints(" _Ky: Like _K but display a calendar for the entire year.");
  Prints(" _d: Print all aspects and changes occurring in a day.");
  Prints(" _dm: Like _d but print all aspects for the entire month.");
  Prints(" _dp <month> <year>: Print aspects within progressed chart.");
  Prints(" _dpy <year>: Like _dp but search for aspects within entire year.");
  Prints(" _D: Like _d but display aspects by influence instead of time.");
  Prints(" _E: Display planetary ephemeris for given month.");
  Prints(" _Ey: Display planetary ephemeris for the entire year.");
  Prints(" _e: Print all charts together (i.e. _v_w_g0_m_Z_S_j0_L0_K_d_D_E).");
  Prints(
    " _t <month> <year>: Compute all transits to natal planets in month.");
  Prints(
    " _tp <month> <year>: Compute progressions in month for chart.");
  Prints(" _t[p]y: <year>: Compute transits/progressions for entire year.");
#ifdef TIME
  Prints(" _t[py]n: Compute transits to natal planets for current time now.");
#endif
  Prints(" _T <month> <day> <year>: Display transits ordered by influence.");
  Prints(" _Tp <month> <day> <year>: Print progressions instead of transits.");
#ifdef TIME
  Prints(" _T[p]n: Display transits ordered by influence for current date.");
#endif
#ifdef INTERPRET
  Prints(" _I [<columns>]: Print interpretation of selected charts.");
#endif
  Prints("\nSwitches which affect how the chart parameters are obtained:");
#ifdef TIME
  Prints(" _n: Compute chart for this exact moment using current time.");
  Prints(" _n[d,m,y]: Compute chart for start of current day, month, year.");
#endif
  Prints(" _a <month> <date> <year> <time> <zone> <long> <lat>:");
  Prints("     Compute chart automatically given specified data.");
  Prints(" _z: Assume Daylight time (change default zone appropriately).");
  Prints(" _z <zone>: Change the default time zone (for _d_q_T_E options).");
  Prints(" _l <long> <lat>: Change the default longitude & latitude.");
  Prints(" _q <month> <date> <year> <time>: Compute chart with defaults.");
  Prints(" _qd <month> <date> <year>: Compute chart for noon on date.");
  Prints(" _qm <month> <year>: Compute chart for first of month.");
  Prints(" _qy <year>: Compute chart for first day of year.");
  Prints(" _qj <day>: Compute chart for time of specified Julian day.");
  Prints(" _i <file>: Compute chart based on info in file.");
  Prints(" _o <file> [..]: Write parameters of current chart to file.");
  Prints(" _o0 <file> [..]: Like _o but output planet/house positions.");
  Prints(" _os <file>: Redirect output of text charts to file.");
  Prints("\nSwitches which affect what information is used in a chart:");
  Prints(" _R [<obj1> [<obj2> ..]]: Restrict specific bodies from displays.");
  Prints(" _R0 [<obj1> ..]: Like _R but restrict everything first.");
  Prints(" _R1 [<obj1> ..]: Like _R0 but unrestrict and show all objects.");
  Prints(" _R[C,u,U]: Restrict all minor cusps, all uranians, or stars.");
  Prints(" _RT[0,1,C,u,U] [..]: Restrict transiting planets in _T lists.");
  Prints(" _C: Include non-angular house cusps in charts.");
  Prints(" _u: Include transneptunian/uranian bodies in charts.");
  Prints(" _U: Include locations of fixed background stars in charts.");
  Prints(" _U[z,l,n,b]: Order by azimuth, altitude, name, or brightness.");
  Prints(" _A <0-18>: Specify the number of aspects to use in charts.");
  Prints(" _Ao <aspect> <orb>: Specify maximum orb for an aspect.");
  Prints(" _Am <planet> <orb>: Specify maximum orb allowed to a planet.");
  Prints(" _Ad <planet> <orb>: Specify orb addition given to a planet.");
  Prints("\nSwitches which affect how a chart is computed:");
#ifdef PLACALC
  Prints(" _b: Use ephemeris files for more accurate location computations.");
  Prints(" _b0: Like _b but display locations to the nearest second too.");
#endif
  Prints(" _c <value>: Select a different default system of houses.");
  Prints("     (0 = Placidus, 1 = Koch, 2 = Equal, 3 = Campanus,");
  Prints("     4 = Meridian, 5 = Regiomontanus, 6 = Porphyry, 7 = Morinus,");
  Prints("     8 = Topocentric, 9 = None.)");
  Prints(" _s: Compute a sidereal instead of the normal tropical chart.");
  Prints(" _s0: Display locations as right ascension instead of degrees.");
  Prints(" _h [<objnum>]: Compute positions centered on specified object.");
  Prints(" _p <month> <day> <year>: Cast 2ndary progressed chart for date.");
  Prints(" _p0 <month> <day> <year>: Cast solar arc chart for date.");
#ifdef TIME
  Prints(" _p[0]n: Cast progressed chart based on current date now.");
#endif
  Prints(" _pd <days>: Set no. of days to progress / day (default 365.25).");
  Prints(" _x <1-360>: Cast harmonic chart based on specified factor.");
  Prints(" _1 [<objnum>]: Cast chart with specified object on Ascendant.");
  Prints(" _2 [<objnum>]: Cast chart with specified object on Midheaven.");
  Prints(" _3: Display objects in their zodiac decan positions.");
  Prints(" _f: Display houses as sign positions (flip them).");
  Prints(" _G: Compute houses based on geographic location only.");
  Prints(" _F <objnum> <sign> <deg>: Force object's position to be value.");
  Prints(" _+ [<days>]: Cast chart for specified no. of days in the future.");
  Prints(" _- [<days>]: Cast chart for specified no. of days in the past.");
  Prints(" _+[m,y] [<value>]: Cast chart for no. of months/years in future.");
  Prints("\nSwitches for relationship and comparison charts:");
  Prints(" _r <file1> <file2>: Compute a relationship synastry chart.");
  Prints(" _rc <file1> <file2>: Compute a composite chart.");
  Prints(" _rm <file1> <file2>: Compute a time space midpoint chart.");
  Prints(" _rd <file1> <file2>: Print time span between files' dates.");
#ifdef BIORHYTHM
  Prints(" _rb <file1> <file2>: Display biorhythm for file1 at time file2.");
#endif
  Prints(" _r0 <file1> <file2>: Keep the charts separate in comparison.");
  Prints(" _rp <file1> <file2>: Like _r0 but do file1 with progr. to file2.");
#ifdef TIME
  Prints(" _y <file>: Display current house transits for particular chart.");
#ifdef BIORHYTHM
  Prints(" _y[b,d,p] <file>: Print biorhythm/datediff for current time now.");
#endif
#endif /* TIME */
  Prints("\nSwitches to access graphics options:");
  Prints(" _k: Display text charts using Ansi characters and color.");
#ifdef MSG
  Prints(" _V: <25,43,50>: Start up with text mode set to number of rows.");
#endif

  /* If graphics features are compiled in, call an additional procedure to */
  /* display the command switches offered dealing with the graphics stuff. */

#ifdef GRAPH
  XDisplaySwitches();
#endif
}


/* Print out a list of the various objects - planets, asteroids, house     */
/* cusps, stars - recognized by the program, and their index values. This  */
/* is displayed when the -O switch is invoked. For some objects, display   */
/* additional information, e.g. ruling signs for planets, brightnesses and */
/* positions in the sky for fixed stars, etc.                              */

void PrintObjects(all)
int all;
{
  int i, j;
  real Off;

  if (!(operation & DASHC))
    for (i = C_LO; i <= C_HI; i++)    /* Set up restrictions properly: Minor */
      ignore[i] = TRUE;               /* cusps and uranians included only if */
  if (!(operation & DASHu))           /* -C and -u switches are in effect.   */
    for (i = U_LO; i <= U_HI; i++)
      ignore[i] = TRUE;
  fprintf(S, "%s planets and objects:\n", appname);
  fprintf(S, "No. Name       Rule Co-Rule Fall Co-Fall Exalt Debilitate\n\n");
  for (i = 1; i <= BASE; i++) if (all || !ignore[i]) {
    AnsiColor(objectansi[i]);
    fprintf(S, "%2d %-12s", i, objectname[i]);
    if (i <= OBJECTS) {                      /* Print rulerships, etc */
      if (ruler1[i]) {                       /* for the planets.      */
        j = ruler2[i];
        fprintf(S, "%c%c%c  %c%c%c     ", SIGNAM(ruler1[i]),
          j ? signname[j][0] : ' ', j ? signname[j][1] : ' ',
          j ? signname[j][2] : ' ');
        fprintf(S, "%c%c%c  %c%c%c     ", SIGNAM(Mod12(ruler1[i]+6)),
          j ? signname[Mod12(j+6)][0] : ' ',
          j ? signname[Mod12(j+6)][1] : ' ',
          j ? signname[Mod12(j+6)][2] : ' ');
        fprintf(S, "%c%c%c   %c%c%c", SIGNAM(exalt[i]),
          SIGNAM(Mod12(exalt[i]+6)));
      }
    } else {
      if (ruler1[i]) {
        fprintf(S, "%c%c%c          %c%c%c", SIGNAM(ruler1[i]),
          SIGNAM(Mod12(ruler1[i]+6)));
        fprintf(S, "          %c%c%c   %c%c%c", SIGNAM(exalt[i]),
          SIGNAM(Mod12(exalt[i]+6)));
      }
      if (i <= C_HI)
        fprintf(S, "  Minor House Cusp #%d", i-OBJECTS);
      else
        fprintf(S, "  Uranian #%d", i-U_LO+1);
    }
    printl();
  }

  /* Now, if -U in effect, read in and display stars in specified order. */

  if (all || universe) {
    Off = ProcessInput(TRUE);
    ComputeStars(operation & DASHs ? 0.0 : -Off);
    for (i = S_LO; i <= S_HI; i++) if (all | !ignore[i]) {
      j = BASE+starname[i-BASE];
      AnsiColor(objectansi[j]);
      fprintf(S, "%2d %-12s", i, objectname[j]);
      fprintf(S, "Star #%2d   ", i-BASE);
      PrintZodiac(planet[j]);
      fprintf(S, "    ");
      PrintAltitude(planetalt[j]);
      fprintf(S, " %5.2f\n", starbright[j-BASE]);
    }
  }
  AnsiColor(DEFAULT);
}


/* Print out a list of all the aspects recognized by the program, and info  */
/* about them: their names, index numbers, degree angles, present orbs, and */
/* the description of their glyph. This gets displayed when the -A switch   */
/* is invoked (without any argument).                                       */

void PrintAspects()
{
  int i;

  fprintf(S, "%s aspects:\nNo. Name         Abbrev. Angle    Orb", appname);
  fprintf(S, "          Description of glyph\n\n");
  for (i = 1; i <= ASPECTS; i++) {
    AnsiColor(aspectansi[i]);
    fprintf(S, "%2d %-15s(%s) %6.2f +/- %1.0f degrees - %s\n",
      i, aspectname[i], aspectabbrev[i],
      aspectangle[i], aspectorb[i], aspectglyph[i]);
  }
  AnsiColor(DEFAULT);
}


/* Print out a list of the 12 signs and houses of the zodiac, and their    */
/* standard and traditional names, as done when the -H0 switch is invoked. */

void PrintSigns()
{
  int i;

  fprintf(S, "%s signs and houses:\n", appname);
  fprintf(S, "Sign        English name      House Traditional name\n\n");
  for (i = 1; i <= SIGNS; i++) {
    AnsiColor(signansi(i));
    fprintf(S, "%-12sthe %-14s%2d%s  House of %s\n",
      signname[i], signenglish[i], i, post[i], housetradition[i]);
  }
  AnsiColor(DEFAULT);
}


/*
******************************************************************************
** File IO Routines.
******************************************************************************
*/

/* Print an error message signifying that a particular option in the        */
/* defaults file is invalid. This is a subprocedure of InputDefaults below. */

void BadDef(option)
char *option;
{
  char string[STRING];

  sprintf(string, "Bad default %s in %s.", option, DEFAULT_INFOFILE);
  PrintError(string);
}


/* Read in a set of default program values used in the program, such as */
/* present location, time zone, the system of houses to use, the number */
/* of aspects and what orbs to use, and so on. These values are always  */
/* read in at the beginning of program execution.                       */

/* The NEXTDEFAULT macro means to skip all comments in the file until we   */
/* reach the beginning of the next set of data, delimited with a '=' sign. */

#define NEXTDEFAULT while(getc(data) != '=');

bool InputDefaults()
{
  FILE *data;
  char name[STRING];
  int i, j;

  filename = DEFAULT_INFOFILE;     /* First lets open the info file.      */
  data = fopen(filename, "r");     /* Look for file in current directory. */
  if (data == NULL) {
    sprintf(name, "%s%s", DEFAULT_DIR, filename);   /* Look for file in   */
    data = fopen(name, "r");                        /* default directory. */
    if (data == NULL)          /* If file not found anywhere, then forget */
      return FALSE;            /* it and use the compile time defaults.   */
  }
  NEXTDEFAULT; fscanf(data, "%s", name);
  if (StringCmp(name, VERSION) != 0) {
    sprintf(name, "%s: Bad information in default parameter file '%s'.",
      appname, filename);
    PrintWarning(name);
    PrintWarning(
      "Delete this file or obtain one compatible with current version.");
    Terminate(_ERROR);
    return FALSE;
  }
  NEXTDEFAULT; fscanf(data, "%lf", &defzone);        /* Time zone    */
  if (!IsValidZon(defzone))
    BadDef("Time Zone");
  NEXTDEFAULT; fscanf(data, "%lf", &deflong);        /* Longitude    */
  if (!IsValidLon(deflong))
    BadDef("Longitude");
  NEXTDEFAULT; fscanf(data, "%lf", &deflat);         /* Latitude     */
  if (!IsValidLat(deflat))
    BadDef("Latitude");
  NEXTDEFAULT; fscanf(data, "%d",  &aspects);        /* # of aspects */
  if (!IsValidAspect(aspects))
    BadDef("Aspect Number");
  NEXTDEFAULT; fscanf(data, "%d",  &housesystem);    /* House type   */
  if (!IsValidSystem(housesystem))
    BadDef("House System");
  NEXTDEFAULT; fscanf(data, "%d",  &ansi);           /* Ansi text?     */
  NEXTDEFAULT; fscanf(data, "%d",  &divisions);      /* For -d and -T  */
  if (!IsValidDivision(divisions))
    BadDef("Searching Divisions");
  NEXTDEFAULT; fscanf(data, "%d",  &placalc);        /* Use ephemeris  */
  NEXTDEFAULT; fscanf(data, "%d",  &seconds);        /* Zodiac seconds */
  seconds = seconds != 0;
  NEXTDEFAULT; fscanf(data, "%d",  &wheelrows);      /* For -w charts  */
  if (!IsValidWheel(wheelrows))
    BadDef("Wheel Rows");
  NEXTDEFAULT; fscanf(data, "%d",  &screenwidth);    /* For -I charts  */
  if (!IsValidScreen(screenwidth))
    BadDef("Screen Width");
  NEXTDEFAULT; fscanf(data, "%d",  &eurodate);       /* D/M/Y vs. M/D/Y?     */
  NEXTDEFAULT; fscanf(data, "%d",  &eurotime);       /* 24hr vs. 12hr clock? */
  NEXTDEFAULT; fscanf(data, "%d",  &smartcusp);      /* Logical -C displays? */
  NEXTDEFAULT; fscanf(data, "%d",  &column80);       /* Clip text at col 80? */
  NEXTDEFAULT;
  for (i = 1; i <= BASE; i++) {            /* Object restrictions         */
    fscanf(data, "%d", &j);
    ignore[i] = j > 0;
  }
  NEXTDEFAULT;
  for (i = 1; i <= BASE; i++) {            /* Transit object restrictions */
    fscanf(data, "%d", &j);
    ignore2[i] = j > 0;
  }
  NEXTDEFAULT;
  fscanf(data, "%d", &j); ignore[0]  = j > 0;    /* Restrict sign changes */
  NEXTDEFAULT;
  fscanf(data, "%d", &j); ignore2[0] = j > 0;    /* Restrict dir. changes */
  NEXTDEFAULT;
  for (i = 1; i <= ASPECTS; i++)           /* Orbs for aspects  */
    fscanf(data, "%lf", &aspectorb[i]);
  NEXTDEFAULT;
  for (i = 1; i <= BASE; i++)              /* Orbs for planets  */
    fscanf(data, "%lf", &planetorb[i]);
  NEXTDEFAULT;
  for (i = 1; i <= BASE; i++)              /* Extra planet orbs */
    fscanf(data, "%lf", &planetadd[i]);
  NEXTDEFAULT; fscanf(data, "%lf", &objectinf[BASE+1]);     /* Rules sign  */
  NEXTDEFAULT; fscanf(data, "%lf", &objectinf[BASE+2]);     /* Exalts in   */
  NEXTDEFAULT; fscanf(data, "%lf",  &houseinf[SIGNS+1]);    /* Rules house */
  NEXTDEFAULT; fscanf(data, "%lf",  &houseinf[SIGNS+2]);    /* Exalts in   */
  NEXTDEFAULT;
  for (i = 1; i <= BASE; i++)
    fscanf(data, "%lf", &objectinf[i]);    /* Influence of each object */
  for (i = 1; i <= SIGNS; i++)
    fscanf(data, "%lf", &houseinf[i]);     /* Influence of each house  */
  for (i = 1; i <= ASPECTS; i++)
    fscanf(data, "%lf", &aspectinf[i]);    /* Influence of each aspect */
  NEXTDEFAULT;
  for (i = 1; i <= BASE; i++)
    fscanf(data, "%lf", &transitinf[i]);   /* Each object when transiting */

  /* Graphics defaults begin here. These are only read in with certain     */
  /* compile options. They need to be read in last for file compatibility. */

#ifdef GRAPH
  NEXTDEFAULT; fscanf(data, "%d", &chartx);       /* Horizontal graph size */
  if (!IsValidGraphx(chartx))
    BadDef("Horizontal Bitmap Size");
  NEXTDEFAULT; fscanf(data, "%d", &charty);       /* Vertical graph size   */
  if (!IsValidGraphx(chartx))
    BadDef("Vertical Bitmap Size");
  NEXTDEFAULT; fscanf(data, "%d", &gridobjects);  /* Aspect grid cells     */
  if (!IsValidGrid(gridobjects))
    BadDef("Aspect Grid Cells");
  NEXTDEFAULT;
  do {
    bitmapmode = getc(data);
  } while (bitmapmode <= ' ');
  if (!IsValidBmpmode(bitmapmode))                /* Bitmap file mode        */
    BadDef("Bitmap File Mode");
  NEXTDEFAULT; fscanf(data, "%d", &xfont);        /* Font simulation flag    */
#ifdef MSG
  NEXTDEFAULT; fscanf(data, "%d", &hiresmode);    /* Normal graphics mode    */
  if (!IsValidResmode(hiresmode))
    BadDef("High Resolution Size");
  NEXTDEFAULT; fscanf(data, "%d", &loresmode);    /* Animation graphics mode */
  if (!IsValidResmode(loresmode))
    BadDef("Low Resolution Size");
#endif
#endif /* GRAPH */
  fclose(data);
  return TRUE;
}


/* Take the current chart information, and write it out to the file   */
/* as indicated by the -o switch. This is only executed at the end of */
/* program execution if the -o switch is in effect.                   */

bool OutputData()
{
  char string[STRING];
  FILE *data;
  int i, j;
  real k;

  data = fopen(filenameout, "w");    /* Create and open the file for output. */
  if (data == NULL) {
    sprintf(string, "File %s can not be created.", filenameout);
    PrintError(string);
    return FALSE;
  }
  if (!(operation & DASHo0)) {

    /* Write the chart information to the file. */

    if (Mon < 1) {
      fclose(data);
      PrintError("Can't output chart with no time/space to file.");
      return FALSE;
    }
    fprintf(data, "%d\n%d\n%d\n%.2f\n%.2f\n%.2f\n%.2f\n",
      Mon, Day, Yea, Tim, Zon, Lon, Lat);
  } else {

    /* However, if the -o0 switch is in effect, then write the actual */
    /* positions of the planets and houses to the file instead.       */

    for (i = 1; i <= BASE; i++) {
      j = (int) planet[i];
      fprintf(data, "%c%c%c: %2d %2d %10.7f\n", OBJNAM(i),
        j%30, j/30+1, FRACT(planet[i])*60.0);                /* Position */
      k = planetalt[i];
      fprintf(data, "[%c]: %3d %12.8f\n",                    /* Altitude */
        ret[i] >= 0.0 ? 'D' : 'R', (int)(Sgn(k)*
        floor(dabs(k))), (k-(real)(int)k)*60.0);          /* Retrograde? */
      if (i == OBJECTS) {
        if (operation & DASHu)    /* Skip minor cusps to write uranians  */
          i = C_HI;
        else
          i = total;
      }
    }
    for (i = 1; i <= SIGNS/2; i++) {   /* Write first six cusp positions */ 
      j = (int) house[i];
      fprintf(data, "H_%c: %2d %2d %10.7f\n",
        'a'+i-1, j%30, j/30+1, FRACT(house[i])*60.0);
    }
  }

  /* Now write any extra strings that were on the command line after the -o */
  /* specification but before the next switch, to the file as comments.     */

  for (i = 1; i < extracount; i++) {
    extralines++;
    fprintf(data, "%s\n", extralines[1]);
  }
  fclose(data);
  return TRUE;
}


/*
******************************************************************************
** Program Dispatch Procedures.
******************************************************************************
*/

/* Initialize an Ansi color array with the color to print each object in. */

void InitColors()
{
  int i;

  objectansi[0] = elemansi[_EAR];
  for (i = 1; i <= 10; i++)
    objectansi[i] = signansi(ruler1[i]);
  for (i = 11; i <= 15; i++)
    objectansi[i] = MAGENTA;
  for (i = 16; i <= 20; i++)
    objectansi[i] = DKCYAN;
  objectansi[_MC] = elemansi[_EAR]; objectansi[_ASC] = elemansi[_FIR];
  objectansi[21] = elemansi[_AIR]; objectansi[22] = elemansi[_WAT];
  objectansi[23] = elemansi[_EAR]; objectansi[24] = elemansi[_AIR];
  for (i = U_LO; i <= U_HI; i++)
    objectansi[i] = PURPLE;
  for (i = S_LO; i <= S_HI; i++)
    objectansi[i] = starbright[i-BASE] < 1.0 ? ORANGE : MAROON;
}


/* This is the dispatch procedure for all the generic table information      */
/* routines, such as those displaying the -H switch list, the list of signs, */
/* objects, default interpretations, and so on not requiring a date or time. */

int PrintTables()
{
  if (andisplay < 2)
    return FALSE;
  if (andisplay & DASHHc) {
    DisplayCredits();
    if (andisplay - (andisplay & DASHHc*2-1))
      printl2();
  }
  if (andisplay & DASHH) {
    DisplaySwitches();
    if (andisplay - (andisplay & DASHH*2-1))
      printl2();
  }
  if (andisplay & DASHH0) {
    PrintSigns();
    if (andisplay - (andisplay & DASHH0*2-1))
      printl2();
  }
  if (andisplay & DASHO) {
    PrintObjects((andisplay & DASHO0) > 0);
    if (andisplay - (andisplay & DASHO*2-1))
      printl2();
  }
  if (andisplay & DASHA) {
    PrintAspects();
    if (andisplay - (andisplay & DASHA*2-1))
      printl2();
  }
#ifdef INTERPRET
  if (andisplay & DASHI0) {
    InterpretGeneral();
    InterpretAspectGeneral();
  }
#endif

  /* If we also already have enough information to generate a chart,    */
  /* then go on and do so, else exit. (So things like "-O -i file" will */
  /* work, but things like just "-H" will print and exit right away.)   */

  if (autom)
    printl2();
  return !autom;
}


/* This is the dispatch procedure for the entire program. After all the   */
/* command switches have been processed, this routine is called to        */
/* actually call the various routines to generate and display the charts. */

void Action()
{
  char string[STRING];
  int i;

  AnsiColor(DEFAULT);
  InitColors();

  /* First let's adjust the restriction status of the minor cusps, uranians, */
  /* and fixed stars based on whether -C, -u, and -U switches are in effect. */

  if (!(operation & DASHC))
    for (i = C_LO; i <= C_HI; i++)
      ignore[i] = ignore2[i] = TRUE;
  if (!(operation & DASHu))
    for (i = U_LO; i <= U_HI; i++)
      ignore[i] = ignore2[i] = TRUE;
  if (!universe)
    for (i = S_LO; i <= S_HI; i++)
      ignore[i] = ignore2[i] = TRUE;

  /* If the -os switch is in effect, open a file and set a global to */
  /* internally 'redirect' all screen output to.                     */

  if (filenamescreen) {
    S = fopen(filenamescreen, "w");
    if (S == NULL) {
      sprintf(string, "File %s can not be created.", filenamescreen);
      PrintError(string);
      S = stdout;
    }
  } else
    S = stdout;

  if (PrintTables())    /* Print out any generic tables specified.        */
    return;             /* If nothing else to do, we can exit right away. */

  /* If -+ or -- switches in effect, then add the specified delta value to */
  /* the date and use that as a new date before proceeding to make chart.  */

  if (Delta != 0) {
    JD = (real)MdyToJulian(MM, DD+Delta, YY);
    JulianToMdy(JD, &MM, &DD, &YY);
  }

  /* Here we either do a normal chart or some kind of relationship chart. */

  if (!relation) {
    if (!autom && !InputData("tty"))  /* If chart info not in mem yet, then */
      return;                         /* prompt the user for the time, etc. */
    SetMain(MM, DD, YY, TT, ZZ, OO, AA);
    CastChart(TRUE);
  } else
    CastRelation(TRUE);
  SetSave(Mon, Day, Yea, Tim, Zon, Lon, Lat);

#ifdef GRAPH
  if (operation & DASHX)    /* If any of the X window switches in effect, */
    XAction();              /* then go make a graphics chart...           */
  else
#endif
    PrintChart(prog);       /* Otherwise print chart on text screen.      */

  if (operation & DASHo)    /* If -o switch in effect, then write */
    OutputData();           /* the chart information to a file.   */

  if (S != stdout)    /* If we were internally directing chart display to a */
    fclose(S);        /* file as with the -os switch, close it here.        */
}


/* Reset a few variables to their default values they have upon startup of */
/* the program. We don't reset all variables, just the most volatile ones. */
/* This is called when in the -Q loop to reset things like which charts to */
/* display, but leave setups such as object restrictions and orbs alone.   */

void InitVariables()
{
  filenamescreen = NULL;
  relation = 0;
  todisplay = exdisplay = andisplay = operation = 0x0;
  interpret = progress = autom = FALSE;
}


/* This routine is called by the main program to actually prompt the user    */
/* for command switches and parameters, entered in the same format as they   */
/* would be on a Unix command line. This is only executed for certain non-   */
/* Unix systems which don't allow passing of a command line to the program,  */
/* or when -Q is in effect. The result of this routine is passed back to the */
/* main program which then processes it just like in a Unix system.          */

#define MAXSWITCHES 30

int InputSwitches(line, argv)
char *line, *argv[MAXSWITCHES];
{
  FILE *data;
  int argc = 1, i = 0, j = 1;
  char *c = line;

  data = S; S = stdout;
  AnsiColor(WHITE);
  fprintf(S, "** %s version %s ", appname, VERSION);
  fprintf(S, "(See '%cHc' switch for copyrights and credits.) **\n", DASH);
  AnsiColor(DEFAULT);
  fprintf(S, "Enter all parameter options below. ");
  fprintf(S, "(Enter '%cH' for help. Enter '.' to exit.)\n", DASH);
  S = data;
  InputString("Input command line", line);
  argv[0] = APPNAME;

  /* Split the entered line up into its individual switch strings. */
  while (*c) {
    if (*c == ' ') {
      if (j)
        ;           /* Skip over the current run of spaces between strings. */
      else {
        *c = 0;     /* First space after a string, end it here. */
        j = TRUE;
      }
    } else {
      if (j) {
        argv[argc++] = c;    /* First char after spaces, begin it here. */
        j = FALSE;
      } else
        ;                    /* Skip over the current string. */
    }
    c++;
  }
  argv[argc] = NULL;    /* Set last string in switch array to Null. */
  printl();
  return argc;
}


/*
******************************************************************************
** Main Program.
******************************************************************************
*/

/* Process a command line switch passed to the program. Read each entry in */
/* the argument list and set all the program modes and charts to display.  */

bool ProcessSwitches(argc, argv)
int argc;
char **argv;
{
  int pos, i;
  real k;
  char string[STRING], cpos, *c;

  argc--; argv++;
  while (argc) {
    pos  = 1 + (argv[0][0] == '-' || argv[0][0] == '/');  /* Leading dash? */
    cpos = argv[0][pos];
    switch (argv[0][pos-1]) {

    case 'H':
      if (cpos == 'c')
        andisplay ^= DASHHc;
      else if (cpos == '0')
        andisplay ^= DASHH0;
      else
        andisplay ^= DASHH;
      break;

    case 'O':
      if (cpos == '0')
        andisplay ^= DASHO0;
      andisplay ^= DASHO;
      break;

    case 'Q':
      if (cpos == '0')
        operation ^= DASHQ0;
      operation ^= DASHQ;
      break;

    /* Switches which determine the type of chart to display: */

    case 'v':
      if (cpos == '0')
        exdisplay ^= DASHv0;
      todisplay ^= DASHv;
      break;

    case 'w':
      if (cpos == '0')
        exdisplay ^= DASHw0;
      if (argc > 1 && (i = atoi(argv[1]))) {
        wheelrows = i;
        argc--; argv++;
      }
      if (!IsValidWheel(wheelrows)) {
        BadVal("w", wheelrows);
        return FALSE;
      }
      todisplay ^= DASHw;
      break;

    case 'g':
      if (cpos == '0')
        exdisplay ^= DASHg0;
      else if (cpos == 'a') {
        exdisplay ^= DASHga;
        if (argv[0][pos+1] == '0')
          exdisplay ^= DASHg0;
      }
#ifdef X11
      else if (cpos == 'e') {
        if (argc <= 1) {
          TooFew("geometry");
          return FALSE;
        }
        chartx = atoi(argv[1]);
        if (argc > 2 && (charty = atoi(argv[2]))) {
          argc--; argv++;
        } else
          charty = chartx;
        if (!IsValidGraphx(chartx)) {
          BadVal("geometry", chartx);
          return FALSE;
        }
        if (!IsValidGraphy(charty)) {
          BadVal("geometry", charty);
          return FALSE;
        }
        argc--; argv++;
        break;
      }
#endif
      todisplay ^= DASHg;
      break;

    case 'm':
      if (cpos == '0') {
        exdisplay ^= DASHm0;
        if (argv[0][pos+1] == 'a')
          exdisplay ^= DASHga;
      } else if (cpos == 'a')
        exdisplay ^= DASHm0 | DASHga;
      todisplay ^= DASHm;
      break;

    case 'Z':
      if (cpos == '0')
        exdisplay ^= DASHZ0;
      else if (cpos == 'd')
        exdisplay ^= DASHZd;
      todisplay ^= DASHZ;
      break;

    case 'S':
      todisplay ^= DASHS;
      break;

    case 'j':
      if (cpos == '0')
        exdisplay ^= DASHj0;
      todisplay ^= DASHj;
      break;

    case 'L':
      if (cpos == '0')
        exdisplay ^= DASHL0;
      if (argc > 1 && (i = atoi(argv[1]))) {
        graphstep = i;
        argc--; argv++;
      }
      if (graphstep < 1 || 160%graphstep > 0) {
        BadVal("L", graphstep);
        return FALSE;
      }
      todisplay ^= DASHL;
      break;

    case 'K':
      if (cpos == 'y')
        exdisplay ^= DASHKy;
      todisplay ^= DASHK;
      break;

    case 'd':
      if (cpos == 'p') {
        i = (argv[0][pos+1] == 'y');
        if (argc <= 2-i) {
          TooFew("dp");
          return FALSE;
        }
        prog = TRUE;
        exdisplay |= DASHdm;
        if (i) {
          Mon2 = 0;
          Yea2 = atoi(argv[1]);
        } else {
          Mon2 = atoi(argv[1]);
          Yea2 = atoi(argv[2]);
          if (!IsValidMon(Mon2)) {
            BadVal2("dp", Mon2);
            return FALSE;
          }
        }
        if (!IsValidYea(Yea2)) {
          BadVal2("dp", Yea2);
          return FALSE;
        }
        argc -= 2-i; argv += 2-i;
      } else if (cpos == 'm')
        exdisplay ^= DASHdm;
#ifdef X11
      else if (cpos == 'i') {    /* -display switch for X */
        if (argc <= 1) {
          TooFew("display");
          return FALSE;
        }
        dispname = argv[1];
        argc--; argv++;
      }
#endif
      todisplay ^= DASHd;
      break;

    case 'D':
      todisplay ^= DASHD;
      break;

    case 'E':
      if (cpos == 'y')
        exdisplay ^= DASHEy;
      todisplay ^= DASHE;
      break;

    case 'e':
      todisplay ^= DASHe;
      exdisplay ^= DASHg0 | DASHj0 | DASHL0;
      break;

    case 't':
      todisplay ^= DASHt;
      Zon2 = defzone; Lon2 = deflong; Lat2 = deflat;
      if (cpos == 'p') {
        prog = TRUE;
        cpos = argv[0][++pos];
      }
      if (i = (cpos == 'y'))
        cpos = argv[0][++pos];
#ifdef TIME
      if (cpos == 'n') {
        GetTimeNow(&Mon2, &Day2, &Yea2, &Tim2, Zon2);
        if (i)
          Mon2 = 0;
        break;
      }
#endif
      if (argc <= 2-i) {
        TooFew("t");
        return FALSE;
      }
      if (i)
        Mon2 = 0;
      else {
        Mon2 = atoi(argv[1]);
        if (!IsValidMon(Mon2)) {
          BadVal2("t", Mon2);
          return FALSE;
        }
      }
      Yea2 = atoi(argv[2-i]);
      argc -= 2-i; argv += 2-i;
      break;

    case 'T':
      todisplay ^= DASHT;
      Zon2 = defzone; Lon2 = deflong; Lat2 = deflat;
      if (cpos == 'p') {
        prog = TRUE;
        cpos = argv[0][++pos];
      }
#ifdef TIME
      if (cpos == 'n') {
        GetTimeNow(&Mon2, &Day2, &Yea2, &Tim2, Zon2);
        break;
      }
#endif
      if (argc <= 3) {
        TooFew("T");
        return FALSE;
      }
      Mon2 = atoi(argv[1]);
      Day2 = atoi(argv[2]);
      Yea2 = atoi(argv[3]);
      if (!IsValidMon(Mon2)) {
        BadVal2("T", Mon2);
        return FALSE;
      } else if (!IsValidDay(Day2, Mon2, Yea2)) {
        BadVal2("T", Day2);
        return FALSE;
      } else if (!IsValidYea(Yea2)) {
        BadVal2("T", Yea2);
        return FALSE;
      }
      argc -= 3; argv += 3;
      break;

#ifdef INTERPRET
    case 'I':
      if (argc > 1 && (screenwidth = atoi(argv[1]))) {
        argc--; argv++;
      } else
        screenwidth = SCREENWIDTH;
      if (!IsValidScreen(screenwidth)) {
        BadVal("I", screenwidth);
        return FALSE;
      }
      if (cpos == '0') {
        andisplay ^= DASHI0;
        break;
      }
      interpret = !interpret;
      break;
#endif

    /* Switches which affect how the chart parameters are obtained: */

#ifdef TIME
    case 'n':
      InputData("now");
      if (cpos == 'd')
        TT = 0.0;
      else if (cpos == 'm') {
        DD = 1; TT = 0.0;
      } else if (cpos == 'y') {
        MM = DD = 1; TT = 0.0;
      }
      break;
#endif

    case 'a':
      if (argc <= 7) {
        TooFew("a");
        return FALSE;
      }
      autom = TRUE;
      SetCore(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]),
        atof(argv[4]), atof(argv[5]), atof(argv[6]), atof(argv[7]));
      if (!IsValidMon(MM)) {
        BadVal("a", MM);
        return FALSE;
      } else if (!IsValidYea(YY)) {
        BadVal("a", YY);
        return FALSE;
      } else if (!IsValidDay(DD, MM, YY)) {
        BadVal("a", DD);
        return FALSE;
      } else if (!IsValidTim(TT)) {
        BadVal2("a", TT);
        return FALSE;
      } else if (!IsValidZon(ZZ)) {
        BadVal2("a", ZZ);
        return FALSE;
      } else if (!IsValidLon(OO)) {
        BadVal2("a", OO);
        return FALSE;
      } else if (!IsValidLat(AA)) {
        BadVal2("a", AA);
        return FALSE;
      }
      argc -= 7; argv += 7;
      break;

    case 'z':
      if (argc <= 1 || (atoi(argv[1]) == 0 && argv[1][0] != '0'))
        defzone -= 1.0;
      else {
        defzone = atof(argv[1]);
        if (!IsValidZon(defzone)) {
          BadVal2("z", defzone);
          return FALSE;
        }
        argc--; argv++;
      }
      break;

    case 'l':
      if (argc <= 2) {
        TooFew("l");
        return FALSE;
      }
      deflong = atof(argv[1]);
      deflat  = atof(argv[2]);
      if (!IsValidLon(deflong)) {
        BadVal2("l", deflong);
        return FALSE;
      } else if (!IsValidLat(deflat)) {
        BadVal2("l", deflat);
        return FALSE;
      }
      argc -= 2; argv += 2;
      break;

    case 'q':
      i = (cpos == 'd') + 2*(cpos == 'm') + 3*(cpos == 'y' || cpos == 'j');
      if (argc <= 4-i) {
        TooFew("q");
        return FALSE;
      }
      autom = TRUE;
      if (cpos == 'j') {
        JD = atof(argv[1])+ROUND;
        TT = FRACT(JD);
        JulianToMdy(JD-TT, &MM, &DD, &YY);
        TT *= 24.0; ZZ = 0.0;
        TT = DegToDec(TT);
      } else {
        MM = i > 2 ? 1 : atoi(argv[1]);
        DD = i > 1 ? 1 : atoi(argv[2-(i>2)]); YY = atoi(argv[4-i-(i<1)]);
        TT = i == 0 ? atof(argv[4]) : (i > 1 ? 0.0 : 12.0); ZZ = defzone;
        if (!IsValidMon(MM)) {
          BadVal("q", MM);
          return FALSE;
        } else if (!IsValidDay(DD, MM, YY)) {
          BadVal("q", DD);
          return FALSE;
        } else if (!IsValidYea(YY)) {
          BadVal("q", YY);
          return FALSE;
        } else if (TT < -2.0 || TT > 24.0) {
          BadVal2("q", TT);
          return FALSE;
        }
      }
      OO = deflong; AA = deflat;
      argc -= 4-i; argv += 4-i;
      break;

    case 'i':
      if (argc <= 1) {
        TooFew("i");
        return FALSE;
      }
      if (!InputData(argv[1]))
        return FALSE;
      argc--; argv++;
      break;

    case 'o':
      if (argc <= 1) {
        TooFew("o");
        return FALSE;
      }
      if (cpos == 's') {
        filenamescreen = argv[1];
        argc--; argv++;
        break;
      } else if (cpos == '0')
        operation ^= DASHo0;
      operation ^= DASHo;
      filenameout = argv[1];
      extralines = argv;
      do {
        argc--; argv++;
        extracount++;
      } while (argc > 1 && argv[1][0] != '-' && argv[1][0] != '/');
      break;

    /* Switches which affect what information is used in a chart: */

    case 'R':
      if (cpos == 'T') {
        c = (char *)ignore2;
        cpos = argv[0][++pos];
      } else
        c = (char *)ignore;
      if (cpos == '0')
        for (i = 0; i <= total; i++)
          c[i] = TRUE;
      else if (cpos == '1') {
        for (i = 0; i <= total; i++)
          c[i] = FALSE;
        operation |= DASHC | DASHu;
        universe = TRUE;
      } else if (cpos == 'C')
        for (i = C_LO; i <= C_HI; i++)
          c[i] = !c[i];
      else if (cpos == 'u')
        for (i = U_LO; i <= U_HI; i++)
          c[i] = !c[i];
      else if (cpos == 'U')
        for (i = S_LO; i <= S_HI; i++)
          c[i] = !c[i];
      else if (argc <= 1 || (!atoi(argv[1]))) {
        for (i = 11; i <= 15; i++)
          c[i] = !c[i];
        c[_FOR] = !c[_FOR]; c[_VTX] = !c[_VTX];
      }
      while (argc > 1 && (i = atoi(argv[1])))
        if (!IsItem(i)) {
          BadVal("R", i);
          return FALSE;
        } else {
          c[i] = !c[i];
          argc--; argv++;
        }
      break;

    case 'C':
      operation ^= DASHC;
      break;

    case 'u':
      operation ^= DASHu;
      break;

    case 'U':
      if (cpos == 'n' || cpos == 'b' || cpos == 'z' || cpos == 'l')
        universe = cpos;
      else
        universe = !universe;
      break;

    case 'A':
      if (argc <= 1 || atoi(argv[1]) == 0) {
        andisplay ^= DASHA;
        break;
      }
      if (cpos != 'o' && cpos != 'm' && cpos != 'd') {
        aspects = atoi(argv[1]);
        if (!IsValidAspect(aspects)) {
          BadVal("A", aspects);
          return FALSE;
        }
        argc--; argv++;
      } else {
        if (argc <= 2) {
          TooFew("A");
          return FALSE;
        }
        i = atoi(argv[1]);
        if (i < 1 || i > (cpos == 'o' ? ASPECTS : BASE)) {
          BadVal("A", i);
          return FALSE;
        }
        k = atof(argv[2]);
        if (k < -DEGREES || k > DEGREES) {
          BadVal2("A", k);
          return FALSE;
        }
        if (cpos == 'm')
          planetorb[i] = k;
        else if (cpos == 'd')
          planetadd[i] = k;
        else
          aspectorb[i] = k;
        argc -= 2; argv += 2;
      }
      break;

    /* Switches which affect how a chart is computed: */

    case 'b':
      if (cpos == '0')
        seconds = !seconds;
      placalc = !placalc;
      break;

    case 'c':
      if (argc <= 1) {
        TooFew("c");
        return FALSE;
      }
      housesystem = atoi(argv[1]);
      if (!IsValidSystem(housesystem)) {
        BadVal("c", housesystem);
        return FALSE;
      }
      argc--; argv++;
      break;

    case 's':
      if (cpos != '0')
        operation ^= DASHs;
      else
        operation ^= DASHs0;
      break;

    case 'h':
      if (argc > 1 && (centerplanet = atoi(argv[1]))) {
        argc--; argv++;
      } else
        centerplanet = 1;
      if (centerplanet < 0 || centerplanet == _MOO ||
        !IsObject(centerplanet) || centerplanet > U_HI) {
        BadVal("h", centerplanet);
        return FALSE;
      }
      c = objectname[0];
      objectname[0] = objectname[centerplanet];
      objectname[centerplanet] = c;
      if (centerplanet < _MOO)
        centerplanet = 1-centerplanet;
      break;

    case 'p':
      if (cpos == '0') {
        operation |= DASHp0;
        cpos = (argv[0][++pos]);
      }
      progress = TRUE;
#ifdef TIME
      if (cpos == 'n') {
        GetTimeNow(&Mon, &Day, &Yea, &Tim, defzone);
        Jdp = (real)MdyToJulian(Mon, Day, Yea) + Tim / 24.0;
        break;
      }
#endif
      if (cpos == 'd') {
        if (argc <= 1) {
          TooFew("pd");
          return FALSE;
        }
        progday = atof(argv[1]);
        if (progday == 0.0) {
          BadVal2("pd", progday);
          return FALSE;
        }
        argc--; argv++;
        break;
      }
      if (argc <= 3) {
        TooFew("p");
        return FALSE;
      }
      Mon = atoi(argv[1]);
      Day = atoi(argv[2]);
      Yea = atoi(argv[3]);
      if (!IsValidMon(Mon)) {
        BadVal2("p", Mon);
        return FALSE;
      } else if (!IsValidDay(Day, Mon, Yea)) {
        BadVal2("p", Day);
        return FALSE;
      } else if (!IsValidYea(Yea)) {
        BadVal2("p", Yea);
        return FALSE;
      }
      Jdp = (real)MdyToJulian(Mon, Day, Yea) + defzone / 24.0;
      argc -= 3; argv += 3;
      break;

    case 'x':
      if (argc <= 1) {
        TooFew("x");
        return FALSE;
      }
      multiplyfactor = atoi(argv[1]);
      if (multiplyfactor < 1 || multiplyfactor > DEGREES) {
        BadVal("x", multiplyfactor);
        return FALSE;
      }
      argc--; argv++;
      break;

    case '1':
      if (argc > 1 && (onasc = atoi(argv[1]))) {
        argc--; argv++;
      } else
        onasc = 1;
      if (onasc < 1 || onasc > total) {
        BadVal("1", onasc);
        return FALSE;
      }
      break;

    case '2':
      if (argc > 1 && (onasc = atoi(argv[1]))) {
        argc--; argv++;
      } else
        onasc = 1;
      if (onasc < 1 || onasc > total) {
        BadVal("2", onasc);
        return FALSE;
      }
      onasc = -onasc;
      break;

    case '3':
      operation ^= DASH3;
      break;

    case 'f':
      operation ^= DASHf;
      break;

    case 'G':
      operation ^= DASHG;
      break;

    case 'F':
      if (argc <= 3) {
        TooFew("F");
        return FALSE;
      }
      i = atoi(argv[1]);
      if (!IsItem(i)) {
        BadVal("F", i);
        return FALSE;
      }
      force[i] = (atof(argv[2])-1.0)*30.0+DecToDeg(atof(argv[3]));
      if (force[i] < 0.0 || force[i] >= DEGREES) {
        BadVal2("F", force[i]);
        return FALSE;
      } else
        force[i] += DEGREES;
      argc -= 3; argv += 3;
      break;

    case '+':
      if (argc > 1 && (i = atoi(argv[1])) != 0) {
        argc--; argv++;
      } else
        i = 1;
      Delta += i * (cpos == 'y' ? 365 : (cpos == 'm' ? 30 : 1));
      break;

    case '-': case '\0':
      if (argc > 1 && (i = atoi(argv[1])) != 0) {
        argc--; argv++;
      } else
        i = 1;
      Delta -= i * (cpos == 'y' ? 365 : (cpos == 'm' ? 30 : 1));
      break;

    /* Switches for relationship and comparison charts: */

    case 'r':
      if (argc <= 2) {
        TooFew("r");
        return FALSE;
      }
      if (cpos == 'c')
        relation = DASHrc;
      else if (cpos == 'm')
        relation = DASHrm;
      else if (cpos == 'd')
        relation = DASHrd;
#ifdef BIORHYTHM
      else if (cpos == 'b')
        relation = DASHrb;
#endif
      else if (cpos == '0')
        relation = DASHr0;
      else if (cpos == 'p')
        relation = DASHrp;
      else
        relation = DASHr;
      filename = argv[1]; filename2 = argv[2];
      argc -= 2; argv += 2;
      break;

#ifdef TIME
    case 'y':
      if (argc <= 1) {
        TooFew("y");
        return FALSE;
      }
      if (cpos == 'd')
        relation = DASHrd;
#ifdef BIORHYTHM
      else if (cpos == 'b')
        relation = DASHrb;
#endif
      else if (cpos == 'p')
        relation = DASHrp;
      else
        relation = DASHr0;
      filename = argv[1]; filename2 = "now";
      argc--; argv++;
      break;
#endif

    /* Switches to access graphics options: */

    case 'k':
      ansi = !ansi;
      break;

#ifdef MSG
    case 'V':
      if (argc <= 1) {
        TooFew("V");
        return FALSE;
      }
      textrows = atoi(argv[1]);
      if (!IsValidTextrows(textrows)) {
        BadVal("V", textrows);
        return FALSE;
      }
      argc--; argv++;
      break;
#endif

#ifdef GRAPH
    case 'X':
      i = XProcessSwitches(argc, argv, pos);
      if (i < 0)
        return FALSE;
      operation |= DASHX;
      argc -= i; argv += i;
      break;
#endif

    case '.':               /* "-." is usually used to exit the -Q loop. */
      Terminate(_FORCE);

    case 'B':          /* For no useful reason, -B will sound a beep. */
      printc(BELL);
      break;

    default:
      sprintf(string, "Unknown switch '%s'.", argv[0]);
      PrintError(string);
      return FALSE;
    }
    argc--; argv++;
  }
  return TRUE;
}


/* The main program, the starting point for Astrolog, follows. This routine */
/* basically consists of a loop, inside which we read a command line, and   */
/* go process it, before actually calling a routine to do the neat stuff.   */

#ifdef SWITCHES
void main(argc, argv)
int argc;
char **argv;
{
#else
void main()
{
  int argc;
  char **argv;
#endif
  char commandline[256];
  char *pointers[MAXSWITCHES];

  InputDefaults();    /* Read in info from the astrolog.dat file. */
Begin:
#ifdef MSG
  if (textrows > 0) {
    _settextrows(textrows);
    textrows = -textrows;
  }
#endif
  if (noswitches) {                                 /* Go prompt for    */
    argc = InputSwitches(commandline, pointers);    /* switches if we   */
    argv = pointers;                                /* don't have them. */
  }
  progname = ProcessProgname(argv[0]);
  if (ProcessSwitches(argc, argv)) {
    if (!noswitches && (operation & DASHQ0)) {
      noswitches = TRUE;
      goto Begin;
    }
#ifdef MSG
    if (textrows > 0) {
      _settextrows(textrows);
      textrows = -textrows;
    }
#endif
    Action();
  }
  if (operation & DASHQ) {    /* If -Q in effect, loop back and get switch */
    printl2();                /* information for another chart to display. */
    InitVariables();
    operation |= DASHQ;
    noswitches = TRUE;
    goto Begin;
  }
  Terminate(_OK);    /* The only standard place to exit Astrolog is here. */
}

/* driver.c */
