[comp.sources.misc] v07i010: astronomical ephemeris - 2 of 3

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (06/04/89)

Posting-number: Volume 7, Issue 10
Submitted-by: ecd@ncs-med.UUCP (Elwood C. Downey)
Archive-name: ephem/part02

#!/bin/sh
echo extracting main.c
cat > main.c << 'xXx'
/* main program. 
 */

#include <stdio.h>
#include <math.h>
#include "astro.h"
#include "circum.h"
#include "screen.h"

extern char *strchr(), *malloc();

static char *cfgfile = "ephem.cfg";	/* default config filename */

/* value for standard and my adaptive rise/set refraction model.
 */
#define	STDREF	degrad(50.0/60.0)	/* 34(ref)+16(semi-diam) arc mins */

static float dis = STDREF; /* sun displacement for rise/set refraction */
static Now now;		/* where and when, right now */
static float epoch;	/* ra/dec display precession epoch, or EOD */
static float tminc;	/* hrs to inc time by each loop; RTC means use clock */
static int newtm;	/* when op sets his own time don't auto inc first step*/
static int nstep;	/* steps to go before stopping */
static int ops, opm;	/* print options flags; 1 if want it */
static int optwi, opsrs, opmrs;
static int oppl[PLUTO+1];

/* info about the misc obj to be displayed at the bottom line */
static int opobj;	/* 1 while wanting to use object */
static float obj_ra, obj_dec, obj_epoch;	/* location of object */
static char obj_name[C_RA-C_OBJ];

/* shorthands into now */
#define mjd	now.n_mjd
#define lat	now.n_lat
#define lng	now.n_lng
#define tz	now.n_tz
#define temp	now.n_temp
#define pressure	now.n_pressure
#define height	now.n_height
#define tznm	now.n_tznm

main (ac, av)
int ac;
char *av[];
{
	static char ssrun[] = "Updating...";
	static char freerun[] =
	    "Running... press any key to stop to make changes.";
	static char prmpt[] =
"Move to another field, RETURN to change this field, ? for help, or ESC to run";
	static char hlp[] =
	"arrow keys move to field; any key stops running; ^d exits; ^l redraws";
	int curr = R_NSTEP, curc = C_NSTEPV;	/* must start somewhere */
	int sflag = 0;
	int i;
	int one = 1;	/* use a variable so masscomp optimizer not disabled */

	while ((--ac > 0) && (**++av == '-')) {
	    char *s;
	    for (s = *av+1; *s != '\0'; s++)
		switch (*s) {
		case 's': /* no credits "silent" (don't publish this) */
		    sflag++;
		    break;
		case 'c': /* set name of config file to use */
		    if (--ac <= 0) usage();
		    cfgfile = *++av;
		    break;
		default:
		    usage();
		}
	}
	if (ac > 0)
	    usage();

	/* unbuffered stdout; avoid fflush(stdout) hassle. */
	setbuf (stdout, (char *)0);

	/* make sure we can read the config file. try adding .cfg too. */
	if (access (cfgfile, 4) < 0) {
	    if (strchr (cfgfile, '.') == 0) {
		/* no . so try it with .cfg suffix */
		char *cf = malloc (strlen(cfgfile)+4+1); /* .cfg + 0 */
		sprintf (cf, "%s.cfg", cfgfile);
		cfgfile = cf;
	    }
	    if (access (cfgfile, 4) < 0) {
		printf ("Can not read config file: %s\n", cfgfile);
		exit (1);
	    }
	}

	/* init the screen and all the globals */
	if (!sflag)
	    credits();
	pr_erase();
	pr_labels();
	borders();
	read_cfgfile (cfgfile);
	newtm = 0;

	/* update screen forever (until QUIT) */
	while (one) {
	    if (nstep <= 1)
		pr_prompt (ssrun);
	    /* print all the time-related fields */
	    pr_now (&now);

	    /* print solar system body info */
	    if (opsrs) pr_sunrs (&now, dis);
	    if (opmrs) pr_moonrs (&now);
	    if (optwi) pr_twilight (&now);
	    if (ops) pr_sun (&now, epoch);
	    if (opm) pr_moon (&now, epoch);
	    for (i = MERCURY; i <= PLUTO; i++)
		if (oppl[i]) pr_planet (i, &now, epoch);

	    /* print the misc obj */
	    if (opobj) pr_obj (obj_ra, obj_dec, obj_epoch, &now, epoch);

	    /* now everything is up-to-date; decrement nstep */
	    pr_newcir(0);
	    plot();
	    if (nstep > 0) nstep -= 1;
	    prnstep ();

	    /* change parameters after steps are done or when op hits a key.
	     */
	    if (nstep == 0 || (chk_char()==0 && read_char()!=0)) {
		if (nstep == 0) {
		    nstep = 1;
		    prnstep ();
		}
		while (1) {
		    int fld = sel_fld (curr, curc, F_VIS|F_CHG, prmpt, hlp);
		    if (fld == 0)
			break;
		    chg_fld ((char *)0, fld);
		    pr_now (&now);
		    curr = unpackr (fld);
		    curc = unpackc (fld);
		}
		if (nstep > 1)
		    pr_prompt (freerun);
	    }

	    /* increment time if op didn't enter his own */
	    if (newtm)
		newtm = 0;
	    else
		inc_mjd (&now, tminc);
	}

	return (0);
}

/* clean up and exit
 * TODO: ask "are you sure?" ?
 */
bye()
{
	pr_erase();
	byetty();
	exit (0);
}

static
usage()
{
	/* don't advertise -s (silent) option */
	printf ("usage: [-c <configfile>]\n");
	exit (1);
}

/* read cfg file, fn, if present */
static
read_cfgfile(fn)
char *fn;
{
	char buf[256];
	FILE *fp;

	fp = fopen (fn, "r");
	if (!fp)
	    return;

	while (fgets (buf, sizeof(buf), fp)) {
	    buf[strlen(buf)-1] = '\0';	/* no trailing \n */
	    if (strncmp ("SITE", buf, 4) == 0)
		pr_string (R_TITLE, C_TITLE-strlen(buf+5)/2, buf+5);
	    else if (strncmp ("LAT", buf, 3) == 0)
		chg_fld (buf+4, rcfpack (R_LAT,C_LATV,0));
	    else if (strncmp ("LONG", buf, 4) == 0)
		chg_fld (buf+5, rcfpack (R_LONG,C_LONGV,0));
	    else if (strncmp ("UT", buf, 2) == 0)
		chg_fld (buf+3, rcfpack (R_UT,C_UTV,0));
	    else if (strncmp ("UD", buf, 2) == 0)
		chg_fld (buf+3, rcfpack (R_UD,C_UD,0));
	    else if (strncmp ("TZONE", buf, 5) == 0)
		chg_fld (buf+6, rcfpack (R_TZONE,C_TZONEV,0));
	    else if (strncmp ("TZNAME", buf, 6) == 0)
		chg_fld (buf+7, rcfpack (R_TZN,C_TZN,0));
	    else if (strncmp ("HEIGHT", buf, 6) == 0)
		chg_fld (buf+7, rcfpack (R_HEIGHT,C_HEIGHTV,0));
	    else if (strncmp ("NSTEP", buf, 5) == 0)
		chg_fld (buf+6, rcfpack (R_NSTEP,C_NSTEPV,0));
	    else if (strncmp ("STPSZ", buf, 5) == 0)
		chg_fld (buf+6, rcfpack (R_STPSZ,C_STPSZV,0));
	    else if (strncmp ("TEMP", buf, 4) == 0)
		chg_fld (buf+5, rcfpack (R_TEMP,C_TEMPV,0));
	    else if (strncmp ("PRES", buf, 4) == 0)
		chg_fld (buf+5, rcfpack (R_PRES,C_PRESV,0));
	    else if (strncmp ("EPOCH", buf, 5) == 0)
		chg_fld (buf+6, rcfpack (R_EPOCH,C_EPOCH,0));
	    else if (strncmp ("OBJN", buf, 4) == 0)
		chg_fld (buf+5, rcfpack (R_OBJ,C_OBJ,0)); /*must be first*/
	    else if (strncmp ("OBJRA", buf, 5) == 0)
		chg_fld (buf+6, rcfpack (R_OBJ,C_RA,0));
	    else if (strncmp ("OBJDEC", buf, 6) == 0)
		chg_fld (buf+7, rcfpack (R_OBJ,C_DEC,0));
	    else if (strncmp ("PROPTS", buf, 6) == 0) {
		char *bp = buf+7;
		while (*bp)
		    switch (*bp++) {
		    case 'T': optwi = 1; break;
		    case 'S': ops = opsrs = 1; break;
		    case 'M': opm = opmrs = 1; break;
		    case 'e': oppl[MERCURY] = 1; break;
		    case 'v': oppl[VENUS] = 1; break;
		    case 'a': oppl[MARS] = 1; break;
		    case 'j': oppl[JUPITER] = 1; break;
		    case 's': oppl[SATURN] = 1; break;
		    case 'u': oppl[URANUS] = 1; break;
		    case 'n': oppl[NEPTUNE] = 1; break;
		    case 'p': oppl[PLUTO] = 1; break;
		    }
	    }
	}
	fclose (fp);
}

/* change the field at rcpk according to the optional string input at bp.
 * if bp is != 0 use it, else issue read_line() and use buffer.
 * then sscanf the buffer and update the corresponding (global) variable(s)
 * or do whatever a pick at that field should do.
 */
static
chg_fld (bp, rcpk)
char *bp;
int rcpk;
{
	char buf[NC];
	int deghrs = 0, mins = 0, secs = 0;

	/* switch on just the row/col portion */
	switch (rcpk & ((1<<F_SHFT)-1)) {
	case rcfpack (R_UD, C_UD, 0):
	    if (!bp) {
		static char p[] = "utc date (m/d/y, or NOW): ";
		pr_prompt (p);
		if (read_line (buf, PW-sizeof(p)) <= 0)
		    return;
		bp = buf;
	    }
	    if (bp[0] == 'n' || bp[0] == 'N')
		time_fromsys (&now);
	    else {
		float fday, newmjd0;
		int month, day, year;
		mjd_cal ((float)mjd, &month, &fday, &year); /* init with now */
		day = (int)fday;	/* ignore partial days */
		sscansex (bp, &month, &day, &year);
		cal_mjd (month, (float)day, year, &newmjd0);
		mjd = newmjd0 + mjd_hr(mjd)/24.0;
	    }
	    newtm = 1;
	    set_t0 (&now);
	    pr_newcir(1);
	    break;
	case rcfpack (R_UT, C_UTV, 0):
	    if (!bp) {
		static char p[] = "utc time (h:m:s, or NOW): ";
		pr_prompt (p);
		if (read_line (buf, PW-sizeof(p)) <= 0)
		    return;
		bp = buf;
	    }
	    if (bp[0] == 'n' || bp[0] == 'N')
		time_fromsys (&now);
	    else {
		float newutc = (mjd-mjd_day(mjd)) * 24.0;
		dec_sexsign (newutc, &deghrs, &mins, &secs);
		sscansex (bp, &deghrs, &mins, &secs);
		sex_dec (deghrs, mins, secs, &newutc);
		mjd = mjd_day(mjd) + newutc/24.0;
	    }
	    newtm = 1;
	    set_t0 (&now);
	    pr_newcir(1);
	    break;
	case rcfpack (R_LD, C_LD, 0):
	    if (!bp) {
		static char p[] = "local date (m/d/y, or NOW): ";
		pr_prompt (p);
		if (read_line (buf, PW-sizeof(p)) <= 0)
		    return;
		bp = buf;
	    }
	    if (bp[0] == 'n' || bp[0] == 'N')
		time_fromsys (&now);
	    else {
		float fday, newlmjd0;
		int month, day, year;
		mjd_cal ((float)(mjd-tz/24.0), &month, &fday, &year); /* now */
		day = (int)fday;	/* ignore partial days */
		sscansex (bp, &month, &day, &year);
		cal_mjd (month, (float)day, year, &newlmjd0);
		mjd = newlmjd0 + mjd_hr(mjd)/24.0;
		mjd += newlmjd0 - mjd_day(mjd-tz/24.0);
	    }
	    newtm = 1;
	    set_t0 (&now);
	    pr_newcir(1);
	    break;
	case rcfpack (R_LT, C_LT, 0):
	    if (!bp) {
		static char p[] = "local time (h:m:s, or NOW): ";
		pr_prompt (p);
		if (read_line (buf, PW-sizeof(p)) <= 0)
		    return;
		bp = buf;
	    }
	    if (bp[0] == 'n' || bp[0] == 'N')
		time_fromsys (&now);
	    else {
		float newlt = (mjd-mjd_day(mjd)) * 24.0 - tz;
		range (&newlt, 24.0);
		dec_sexsign (newlt, &deghrs, &mins, &secs);
		sscansex (bp, &deghrs, &mins, &secs);
		sex_dec (deghrs, mins, secs, &newlt);
		mjd = mjd_day(mjd-tz/24.0) + (newlt + tz)/24.0;
	    }
	    newtm = 1;
	    set_t0 (&now);
	    pr_newcir(1);
	    break;
	case rcfpack (R_TZN, C_TZN, 0):
	    if (!bp) {
		static char p[] = "timezone abbreviation (3 char max): ";
		pr_prompt (p);
		if (read_line (buf, 3) <= 0)
		    return;
		bp = buf;
	    }
	    strcpy (tznm, bp);
	    break;
	case rcfpack (R_TZONE, C_TZONEV, 0):
	    if (!bp) {
		static char p[] = "hours behind utc: ";
		pr_prompt (p);
		if (read_line (buf, PW-sizeof(p)) <= 0)
		    return;
		bp = buf;
	    }
	    dec_sexsign (tz, &deghrs, &mins, &secs);
	    sscansex (bp, &deghrs, &mins, &secs);
	    sex_dec (deghrs, mins, secs, &tz);
	    pr_newcir(1);
	    break;
	case rcfpack (R_LONG, C_LONGV, 0):
	    if (!bp) {
		static char p[] = "longitude (+ west) (d:m:s): ";
		pr_prompt (p);
		if (read_line (buf, PW-sizeof(p)) <= 0)
		    return;
		bp = buf;
	    }
	    dec_sexsign (-raddeg(lng), &deghrs, &mins, &secs);
	    sscansex (bp, &deghrs, &mins, &secs);
	    sex_dec (deghrs, mins, secs, &lng);
	    lng = degrad (-lng); 		/* want - radians west */
	    pr_newcir(1);
	    break;
	case rcfpack (R_LAT, C_LATV, 0):
	    if (!bp) {
		static char p[] = "latitude (+ north) (d:m:s): ";
		pr_prompt (p);
		if (read_line (buf, PW-sizeof(p)) <= 0)
		    return;
		bp = buf;
	    }
	    dec_sexsign (raddeg(lat), &deghrs, &mins, &secs);
	    sscansex (bp, &deghrs, &mins, &secs);
	    sex_dec (deghrs, mins, secs, &lat);
	    lat = degrad (lat);
	    pr_newcir(1);
	    break;
	case rcfpack (R_HEIGHT, C_HEIGHTV, 0):
	    if (!bp) {
		static char p[] = "height above sea level (ft): ";
		pr_prompt (p);
		if (read_line (buf, PW-sizeof(p)) <= 0)
		    return;
		bp = buf;
	    }
	    sscanf (bp, "%f", &height);
	    sprintf (buf, "%5g ft", height);
	    pr_string (R_HEIGHT, C_HEIGHTV, buf);
	    height /= 2.093e7; /* convert ft to earth radii above sea level */
	    pr_newcir(1);
	    break;
	case rcfpack (R_NSTEP, C_NSTEPV, 0):
	    if (!bp) {
		static char p[] = "number of steps to run: ";
		pr_prompt (p);
		if (read_line (buf, 8) <= 0)
		    return;
		bp = buf;
	    }
	    sscanf (bp, "%d", &nstep);
	    prnstep ();
	    break;
	case rcfpack (R_TEMP, C_TEMPV, 0):
	    if (!bp) {
		static char p[] = "temperatue (deg.F): ";
		pr_prompt (p);
		if (read_line (buf, PW-sizeof(p)) <= 0)
		    return;
		bp = buf;
	    }
	    sscanf (bp, "%f", &temp);
	    sprintf (buf, "%6g F", temp);
	    pr_string (R_TEMP, C_TEMPV, buf);
	    temp = 5./9.*(temp - 32.0);	/* want degs C */
	    pr_newcir(1);
	    break;
	case rcfpack (R_PRES, C_PRESV, 0):
	    if (!bp) {
		static char p[] =
		    "atmos pressure (in. Hg; 0 for no refraction correction): ";
		pr_prompt (p);
		if (read_line (buf, PW-sizeof(p)) <= 0)
		    return;
		bp = buf;
	    }
	    sscanf (bp, "%f", &pressure);
	    sprintf (buf, "%5.2f in", pressure);
	    pr_string (R_PRES, C_PRESV, buf);
	    pressure *= 33.86;		/* want mBar */
	    pr_newcir(1);
	    break;
	case rcfpack (R_EPOCH, C_EPOCH, 0):
	    if (!bp) {
		static char p[] = "epoch (year, or EOD for no precession): ";
		pr_prompt (p);
		if (read_line (buf, PW-strlen(p)) <= 0)
		    return;
		bp = buf;
	    }
	    if (bp[0] == 'e' || bp[0] == 'E') {
		epoch = EOD;
		sprintf (buf, "(Epoch of date)");
	    } else {
		float e;
		sscanf (bp, "%f", &e);
		sprintf (buf, "(Epoch %6.1f) ", e);
		cal_mjd (1, 1.0, (int)e, &epoch);	/* convert to mjd */
		epoch += (e - (int)e)*365.24;
	    }
	    pr_string (R_EPOCH, C_EPOCH, buf);
	    pr_newcir(1);
	    break;
	case rcfpack (R_STPSZ, C_STPSZV, 0):
	    if (!bp) {
		static char p[] =
		    "step size increment (h:m:s, or <x>D, or RTC): ";
		pr_prompt (p);
		if (read_line (buf, PW-sizeof(p)) <= 0)
		    return;
		bp = buf;
	    }
	    if (bp[0] == 'r' || bp[0] == 'R') {
		pr_string (R_STPSZ, C_STPSZV, "RT CLOCK");
		tminc = RTC;
	    } else {
		int last = strlen (bp) - 1;
		if (bp[last] == 'd' || bp[last] == 'D') {
		    /* ends in d so treat as decimal number of days */
		    float x;
		    sscanf (bp, "%g", &x);
		    tminc = x * 24.0;
		    pr_float (R_STPSZ, C_STPSZV, "%5g dy", x);
		} else {
		    if (tminc == RTC)
			deghrs = mins = secs = 0;
		    else
			dec_sexsign (tminc, &deghrs, &mins, &secs);
		    sscansex (bp, &deghrs, &mins, &secs);
		    sex_dec (deghrs, mins, secs, &tminc);
		    pr_time (R_STPSZ, C_STPSZV, tminc);
		}
	    }
	    set_t0 (&now);
	    break;
	case rcfpack (R_PLOT, C_PLOT, 0):
	    plt_pk_label();
	    break;
	case rcfpack (R_PLOT, C_PLOTV, 0):
	    plt_pk_onoff();
	    break;
	case rcfpack (R_DAWN, C_DAWN, 0):
	case rcfpack (R_DUSK, C_DUSK, 0):
	case rcfpack (R_LON, C_LON, 0):
	    if (optwi ^= 1)
		pr_twilight (&now);
	    else {
		pr_blanks (R_DAWN, C_DAWNV, 5);
		pr_blanks (R_DUSK, C_DUSKV, 5);
		pr_blanks (R_LON, C_LONV, 5);
	    }
	    break;
	case rcfpack (R_SUNR, C_SUNR, 0):
	case rcfpack (R_SUNS, C_SUNS, 0):
	case rcfpack (R_LOD, C_LOD, 0):
	    if (opsrs ^= 1) {
		if (!bp) {
		    static char p[] =
			"standard or adaptive refraction model (s/a)? ";
		    do {
			pr_prompt (p);
			if (read_line (buf, PW-sizeof(p)) < 0)
			    return;
		    } while (*buf != 's' && *buf != 'a');
		    bp = buf;
		}
		dis = (*bp == 'a') ? ADPREF : STDREF;
		pr_sunrs (&now, dis);
	    } else {
		pr_blanks (R_SUNR, C_SUNRT, 14);
		pr_blanks (R_SUNS, C_SUNST, 14);
		pr_blanks (R_LOD, C_LODV, 5);
	    }
	    break;
	case rcfpack (R_MOONR, C_MOONR, 0):
	case rcfpack (R_MOONS, C_MOONS, 0):
	    if (opmrs ^= 1) 
		pr_moonrs (&now);
	    else {
		pr_blanks (R_MOONR, C_MOONRT, 14);
		pr_blanks (R_MOONS, C_MOONST, 14);
	    }
	    break;
	case rcfpack (R_SUN, C_OBJ, 0):
	    if (ops ^= 1)
		pr_sun (&now, epoch);
	    else
		pr_noplanet (R_SUN);
	    break;
	case rcfpack (R_MOON, C_OBJ, 0):
	    if (opm ^= 1)
		pr_moon (&now, epoch);
	    else
		pr_noplanet (R_MOON);
	    break;
	case rcfpack (R_MERCURY, C_OBJ, 0):
	    if (oppl[MERCURY] ^= 1)
		pr_planet (MERCURY, &now, epoch);
	    else
		pr_noplanet (R_MERCURY);
	    break;
	case rcfpack (R_VENUS, C_OBJ, 0):
	    if (oppl[VENUS] ^= 1)
		pr_planet (VENUS, &now, epoch);
	    else
		pr_noplanet (R_VENUS);
	    break;
	case rcfpack (R_MARS, C_OBJ, 0):
	    if (oppl[MARS] ^= 1)
		pr_planet (MARS, &now, epoch);
	    else
		pr_noplanet (R_MARS);
	    break;
	case rcfpack (R_JUPITER, C_OBJ, 0):
	    if (oppl[JUPITER] ^= 1)
		pr_planet (JUPITER, &now, epoch);
	    else
		pr_noplanet (R_JUPITER);
	    break;
	case rcfpack (R_SATURN, C_OBJ, 0):
	    if (oppl[SATURN] ^= 1)
		pr_planet (SATURN, &now, epoch);
	    else
		pr_noplanet (R_SATURN);
	    break;
	case rcfpack (R_URANUS, C_OBJ, 0):
	    if (oppl[URANUS] ^= 1)
		pr_planet (URANUS, &now, epoch);
	    else
		pr_noplanet (R_URANUS);
	    break;
	case rcfpack (R_NEPTUNE, C_OBJ, 0):
	    if (oppl[NEPTUNE] ^= 1)
		pr_planet (NEPTUNE, &now, epoch);
	    else
		pr_noplanet (R_NEPTUNE);
	    break;
	case rcfpack (R_PLUTO, C_OBJ, 0):
	    if (oppl[PLUTO] ^= 1)
		pr_planet (PLUTO, &now, epoch);
	    else
		pr_noplanet (R_PLUTO);
	    break;
	case rcfpack (R_OBJ, C_OBJ, 0):
	    if (!bp) {
		static char p[] = "object name (or RETURN for none): ";
		pr_prompt (p);
		if (read_line (buf, sizeof(obj_name)-1) < 0)
		    return;
		bp = buf;
	    } else
		bp[sizeof(obj_name)-1] = '\0';
	    if (bp[0] == '\0') {
		opobj = 0;
		pr_blanks (R_OBJ, C_OBJ, sizeof(obj_name)-1);
		/* pr_noplanet (R_OBJ); NO: writes on low-right of screen */
		pr_blanks (R_OBJ, C_RA, 80-1-C_RA+1);
	    } else {
		opobj = 1;
		pr_blanks (R_OBJ, C_OBJ, sizeof(obj_name)-1);
		strncpy (obj_name, bp, sizeof(obj_name)-1);
		pr_string (R_OBJ, C_OBJ, bp);
		obj_epoch = 0.0;
		obj_ra = 0.0;
		obj_dec = 0.0;
	    }
	    break;
	case rcfpack (R_OBJ, C_RA, 0):
	    if (!opobj)
		break;
	    if (!bp) {
		static char p[] = "ra (current epoch, h:m:s): ";
		pr_prompt (p);
		if (read_line (buf, PW-sizeof(p)) <= 0)
		    return;
		bp = buf;
	    }
	    dec_sexsign (radhr(obj_ra), &deghrs, &mins, &secs);
	    sscansex (bp, &deghrs, &mins, &secs);
	    sex_dec (deghrs, mins, secs, &obj_ra);
	    pr_ra (R_OBJ, C_RA, obj_ra);
	    obj_ra = hrrad (obj_ra);
	    obj_epoch = epoch == EOD ? mjd : epoch;
	    pr_obj (obj_ra, obj_dec, obj_epoch, &now, epoch);
	    break;
	case rcfpack (R_OBJ, C_DEC, 0):
	    if (!opobj)
		break;
	    if (!bp) {
		static char p[] = "dec (current epoch, d:m:s): ";
		pr_prompt (p);
		if (read_line (buf, PW-sizeof(p)) <= 0)
		    return;
		bp = buf;
	    }
	    dec_sexsign (raddeg(obj_dec), &deghrs, &mins, &secs);
	    sscansex (bp, &deghrs, &mins, &secs);
	    sex_dec (deghrs, mins, secs, &obj_dec);
	    obj_dec = degrad (obj_dec);
	    obj_epoch = epoch == EOD ? mjd : epoch;
	    pr_obj (obj_ra, obj_dec, obj_epoch, &now, epoch);
	    break;
	}
}

static
prnstep()
{
	char buf[16];
	sprintf (buf, "%8d", nstep);
	pr_string (R_NSTEP, C_NSTEPV, buf);
}

/* crack a line of the form X:X:X or X/X/X into its components.
 * only change those fields that are specified:
 *   eg:  ::10	only changes *s
 *        10    only changes *d
 *        10:0  changes *d and *m
 * if see '-' anywhere, first non-zero component will be made negative.
 */
static
sscansex (bp, d, m, s)
char *bp;
int *d, *m, *s;
{
	char c;
	register int *p = d;
	int *nonzp = 0;
	int sawneg = 0;
	int innum = 0;

	while (c = *bp++)
	    switch (c) {
	    case '0': case '1': case '2': case '3': case '4':
	    case '5': case '6': case '7': case '8': case '9':
		if (!innum) {
		    *p = 0;
		    innum = 1;
		}
		*p = *p*10 + (c - '0');
		if (*p && !nonzp)
		    nonzp = p;
		break;
	    case ':': case '/':
		/* advance to next component */
		p = (p == d) ? m : s;
		innum = 0;
		break;
	    case '-':
		sawneg = 1;
		break;
	    }

	if (sawneg && nonzp)
	    *nonzp = -*nonzp;
}

/* just like dec_sex() but makes the first non-zero element negative if
 * x is negative (instead of returning a sign flag).
 */
static
dec_sexsign (x, h, m, s)
float x;
int *h, *m, *s;
{
	int n;
	dec_sex (x, h, m, s, &n);
	if (n) {
	    if (*h)
		*h = -*h;
	    else if (*m)
		*m = -*m;
	    else
		*s = -*s;
	}
}
xXx
echo extracting plot.c
cat > plot.c << 'xXx'
/* code to support the plotting capabilities. */

#include <stdio.h>
#include "screen.h"

extern errno;
extern char *sys_errlist[];

#define	UNDEFFL	1e38	/* magic float value to mean undefined */

/* number of simultaneous lines we can track/plot */
#define	MAXPLTLINES	4
#define	FNLEN		(14+1)	/* longest filename; plus 1 for \0 */

static char plt_filename[FNLEN] = "ephem.plt";
static FILE *plt_fp;	/* == 0 means don't plot too */

/* a PlotField is a field location and a value stored there.
 * a PlotLine is a label and two or three PlotFields:
 *    [0] is the x coord, [1] the y, and [2], if not UNDEFFL/blank, is z.
 */
typedef struct {
    int pf_rcpack;
    float pf_val;
} PlotField;
typedef struct {
    char pl_label;
    PlotField pl_x, pl_y, pl_z;
} PlotLine;
static PlotLine plotline[MAXPLTLINES];
static int npltlines;	/* actual number of plotline[]s in use */

/* picked the Plot label:
 * if on, select fields to plot.
 * if off, select name of file to plot.
 */
plt_pk_label()
{
	if (plt_fp)
	    plt_select_fields();
	else
	    plt_file();
}

/* pick the plot on/off field:
 * if on, turn off.
 * if off, turn on, using current set of plot fields.
 */
plt_pk_onoff()
{
	if (plt_fp)
	    plt_turn_off();
	else
	    plt_turn_on();
}

/* save value for r/c, if plot file open and r/c is in plotfield[].
 * don't quit if see one since a field could be used more than once; time
 *   is a frequent example.
 */
plt_val (r, c, value)
int r, c;
float value;
{
	PlotLine *plp;
	int rcp;

	if (plt_fp) {
	    plp = &plotline[npltlines];
	    rcp = rcfpack (r, c, 0);
	    while (--plp >= plotline) {
		if (plp->pl_x.pf_rcpack == rcp)
		    plp->pl_x.pf_val = value;
		if (plp->pl_y.pf_rcpack == rcp)
		    plp->pl_y.pf_val = value;
		if (plp->pl_z.pf_rcpack == rcp)
		    plp->pl_z.pf_val = value;
	    }
	}
}

/* write the active plotfields to the current plot file, if one is open. */
plot ()
{
	PlotLine *plp;

	if (plt_fp)
	    for (plp = &plotline[npltlines]; --plp >= plotline; ) {
		fprintf (plt_fp, "%c,%g,%g", plp->pl_label,
					    plp->pl_x.pf_val, plp->pl_y.pf_val);
		if (plp->pl_z.pf_val != UNDEFFL)
		    fprintf (plt_fp, ",%g", plp->pl_z.pf_val);
		fprintf (plt_fp, "\n");
	    }
}

static
plt_init()
{
	PlotLine *plp = &plotline[MAXPLTLINES];

	while (--plp >= plotline) {
	    plp->pl_x.pf_rcpack = plp->pl_y.pf_rcpack = 0;
	    plp->pl_x.pf_val = plp->pl_y.pf_val = 0.0;
	    plp->pl_z.pf_val = UNDEFFL;
	}
	npltlines = 0;
}

static
plt_select_fields()
{
	static char hlp[] = "use arrow keys to select variable, or ESC to quit";
	static int pltr = R_UT, pltc = C_UTV; /* start somewhere... */
	int i;

	plt_init();
	for (i = 0; i < MAXPLTLINES; i++) {
	    char buf[64];
	    int fld;

	    sprintf (buf, "select x field for line %d", i+1);
	    fld = sel_fld (pltr, pltc, F_VIS|F_PLT, buf, hlp);
	    pltr = unpackr (fld); pltc = unpackc (fld);
	    if (!fld)
		break;
	    plotline[i].pl_x.pf_rcpack = fld;

	    sprintf (buf, "select y field for line %d", i+1);
	    fld = sel_fld (pltr, pltc, F_VIS|F_PLT, buf, hlp);
	    pltr = unpackr (fld); pltc = unpackc (fld);
	    if (!fld)
		break;
	    plotline[i].pl_y.pf_rcpack = fld;

	    sprintf (buf, "select z field for line %d", i+1);
	    fld = sel_fld (pltr, pltc, F_VIS|F_PLT, buf, hlp);
	    pltr = unpackr (fld); pltc = unpackc (fld);
	    if (fld)
		plotline[i].pl_z.pf_rcpack = fld;

	    do {
		sprintf (buf, "select one-character label for line %d: ", i+1);
		pr_prompt (buf);
		fld = read_line (buf, 1);
	    } while (fld != 1);
	    plotline[i].pl_label = *buf;
	}
	npltlines = i;
}

static
plt_turn_off ()
{
	fclose (plt_fp);
	plt_fp = 0;
	pr_string (R_PLOT, C_PLOTV, "off");
}

static
plt_turn_on ()
{
	char fn[FNLEN], fnq[64];
	char *optype;
	int n;

	/* prompt for file name, giving current as default */
	sprintf (fnq, "file to write <%s>: ", plt_filename);
	pr_prompt (fnq);
	n = read_line (fn, sizeof(fn)-1);

	/* leave plotting off if type ESC.
	 * reuse same fn if just type \n
	 */
	if (n < 0)
	    return;
	if (n > 0)
	    strcpy (plt_filename, fn);

	/* give option to append if file already exists */
	optype = "w";
	if (access (plt_filename, 2) == 0) {
	    while (1) {
		pr_prompt ("append or overwrite (a/o)?: ");
		n = read_line (fn, 1);
		if (n < 0)
		    return;
		if (fn[0] == 'a') {
		    optype = "a";
		    break;
		}
		if (fn[0] == 'o')
		    break;
	    }
	}

	/* plotting is on if file opens ok */
	plt_fp = fopen (plt_filename, optype);
	if (plt_fp)
	    pr_string (R_PLOT, C_PLOTV, "on ");
	else {
	    char buf[NC];
	    sprintf(buf,"can not open %s: %s",plt_filename,sys_errlist[errno]);
	    pr_prompt (buf);
	    (void)read_char();
	}
}

static
plt_file ()
{
	char fn[FNLEN], fnq[64];
	FILE *pfp;
	int n;

	/* prompt for file name, giving current as default */
	sprintf (fnq, "file to read <%s>: ", plt_filename);
	pr_prompt (fnq);
	n = read_line (fn, sizeof(fn)-1);

	/* forget it if type ESC.
	 * reuse same fn if just type \n
	 */
	if (n < 0)
	    return;
	if (n > 0)
	    strcpy (plt_filename, fn);

	/* do the plot if file opens ok */
	pfp = fopen (plt_filename, "r");
	if (pfp) {
	    plot_it (pfp);
	    fclose (pfp);
	} else {
	    char buf[NC];
	    sprintf(buf,"can not open %s: %s",plt_filename,sys_errlist[errno]);
	    pr_prompt (buf);
	    (void)read_char();
	}
}

/* TODO: add z somehow
 * N.B. DON'T use pr_X() since they will be remembered over screen.
 */
static
plot_it (pfp)
FILE *pfp;
{
	static char fmt[] = "%c,%g,%g";
	float x, y;	/* N.B. most sscanf("%g")'s need ptrs to double */
	float minx, maxx, miny, maxy;
	char buf[128];
	int first = 1;
	char c;

	/* find ranges and number of points */
	while (fgets (buf, sizeof(buf), pfp)) {
	    sscanf (buf, fmt, &c, &x, &y);
	    if (first) {
		maxx = minx = x;
		maxy = miny = y;
		first = 0;
	    } else {
		if (x > maxx) maxx = x;
		else if (x < minx) minx = x;
		if (y > maxy) maxy = y;
		else if (y < miny) miny = y;
	    }
	}

#define	SMALL	(1e-10)
	if (first == 1 || fabs(minx-maxx) < SMALL || fabs(miny-maxy) < SMALL) {
	    c_erase();
	    c_pos (1,1); printf ("Nothing in file or range too small...");
	} else {
	    /* read file again, this time plotting */
	    rewind (pfp);
	    c_erase();
	    while (fgets (buf, sizeof(buf), pfp)) {
		int row, col;
		sscanf (buf, fmt, &c, &x, &y);
		row = NR-(int)((NR-1)*(y-miny)/(maxy-miny)+0.5);
		col =  1+(int)((NC-1)*(x-minx)/(maxx-minx)+0.5);
		if (row == NR && col == NC)
		    col--;	/* avoid lower right scrolling corner */
		c_pos (row, col);
		putchar (c);
	    }

	    /* label axes */
	    c_pos (1,1); printf ("%.2g", maxy);
	    c_pos (NR-1,1); printf ("%.2g", miny);
	    c_pos (NR,1); printf ("%.2g", minx);
	    c_pos (NR,NC-10); printf ("%.2g", maxx);
	}

	/* hit any key to resume... */
	(void) read_char();
	pr_redraw();
}
xXx
echo extracting pr.c
cat > pr.c << 'xXx'
#include <stdio.h>
#include <math.h>
#include "astro.h"
#include "circum.h"
#include "screen.h"

/* shorthands into np */
#define mjd	np->n_mjd
#define lat	np->n_lat
#define lng	np->n_lng
#define tz	np->n_tz
#define temp	np->n_temp
#define pressure	np->n_pressure
#define height	np->n_height
#define tznm	np->n_tznm

/* display once-only labels. */
pr_labels()
{
	pr_string (R_PLOT,	C_PLOT,		"Plot");
	pr_string (R_PLOT,	C_PLOTV,	"off");
	pr_string (R_JD,	C_JD,		"JD");
	pr_string (R_LST,	C_LST,		"LST");
	pr_string (R_TZN,	C_TZN,		"LT");
	pr_string (R_UT,	C_UT,		"UTC");
	pr_string (R_TZONE,	C_TZONE,	"TZ");
	pr_string (R_LAT,	C_LAT,		"Lat");
	pr_string (R_LONG,	C_LONG,		"Long");
	pr_string (R_TEMP,	C_TEMP,		"Temp");
	pr_string (R_PRES,	C_PRES,		"AtmPr");
	pr_string (R_LOD,	C_LOD,		"DayLn");
	pr_string (R_LON,	C_LON,		"NiteLn");
	pr_string (R_NSTEP,	C_NSTEP,	"NStep");
	pr_string (R_STPSZ,	C_STPSZ,	"StpSz");
	pr_string (R_HEIGHT,	C_HEIGHT,	"Elev");
	pr_string (R_DUSK,	C_DUSK,		"Dusk");
	pr_string (R_SUNR,	C_SUNR,		"SRis");
	pr_string (R_MOONR,	C_MOONR,	"MRis");
	pr_string (R_DAWN,	C_DAWN,		"Dawn");
	pr_string (R_SUNS,	C_SUNS,		"SSet");
	pr_string (R_MOONS,	C_MOONS,	"MSet");

	/* planet column headings */
	pr_string (R_PLANTAB,	C_OBJ,	"Ob");
	pr_string (R_PLANTAB,	C_RA,	"R.A.");
	pr_string (R_PLANTAB,	C_DEC,	"Dec");
	pr_string (R_PLANTAB,	C_HLONG,"Helio");
	pr_string (R_PLANTAB+1,	C_HLONG,"Long");
	pr_string (R_PLANTAB,	C_HLAT,	"Helio");
	pr_string (R_PLANTAB+1,	C_HLAT,	"Lat");
	pr_string (R_PLANTAB,	C_AZ,	"Az");
	pr_string (R_PLANTAB+1,	C_AZ,	"Deg E");
	pr_string (R_PLANTAB,	C_ALT,	"Alt");
	pr_string (R_PLANTAB+1,	C_ALT,	"Deg Up");
	pr_string (R_PLANTAB,	C_EDIST,"Ea Dst");
	pr_string (R_PLANTAB+1,	C_EDIST,"AU(mi)");
	pr_string (R_PLANTAB,	C_SDIST,"Sn Dst");
	pr_string (R_PLANTAB+1,	C_SDIST,"AU");
	pr_string (R_PLANTAB,	C_ELONG,"Elong");
	pr_string (R_PLANTAB+1,	C_ELONG,"Deg E");
	pr_string (R_PLANTAB,	C_SIZE,	"Size");
	pr_string (R_PLANTAB+1,	C_SIZE,	"ArcS");
	pr_string (R_PLANTAB,	C_MAG,	"VMag");
	pr_string (R_PLANTAB,	C_PHASE,"Phs");
	pr_char (R_PLANTAB+1,	C_PHASE,'%');

	/* object names */
	pr_string (R_SUN,	C_OBJ,	"Su");
	pr_string (R_MOON,	C_OBJ,	"Mo");
	pr_string (R_MERCURY,	C_OBJ,	"Me");
	pr_string (R_VENUS,	C_OBJ,	"Ve");
	pr_string (R_MARS,	C_OBJ,	"Ma");
	pr_string (R_JUPITER,	C_OBJ,	"Ju");
	pr_string (R_SATURN,	C_OBJ,	"Sa");
	pr_string (R_URANUS,	C_OBJ,	"Ur");
	pr_string (R_NEPTUNE,	C_OBJ,	"Ne");
	pr_string (R_PLUTO,	C_OBJ,	"Pl");
}

/* display dawn/dusk times
 */
pr_twilight (np)
Now *np;
{
	float dusk, dawn;
	float tmp;
	int status;

	twilight_cir (np, &dawn, &dusk, &status);
	switch (status) {
	case -1:	/* sun never sets today */
	case  1:	/* sun never rises today */
	case  2:	/* can not find where sun is! */
	    pr_blanks (R_DAWN, C_DAWNV, 5);
	    pr_blanks (R_DUSK, C_DUSKV, 5);
	    pr_blanks (R_LON, C_LONV, 5);
	    return;
	default:	/* all ok */
	    ;
	}

	/* print times in local tz */
	tmp = dawn - tz; range (&tmp, 24.0);
	pr_mtime (R_DAWN, C_DAWNV, tmp);
	tmp = dusk - tz; range (&tmp, 24.0);
	pr_mtime (R_DUSK, C_DUSKV, tmp);
	tmp = dawn - dusk; range (&tmp, 24.0);
	pr_mtime (R_LON, C_LONV, tmp);
}

/* display sun's rise/set times, and length of day.
 */
pr_sunrs (np, dis)
Now *np;
float dis;
{
	float utcr, utcs, azr, azs;
	float tmp;
	int status;

	sunrs_cir (np, dis, &utcr, &utcs, &azr, &azs, &status);
	switch (status) {
	case -1:	/* sun never sets today */
	    pr_string (R_SUNR, C_SUNRT, "Circumpolar           ");
	    pr_blanks (R_SUNS, C_SUNST, 14);
	    pr_blanks (R_LOD, C_LODV, 5);
	    return;
	case  1:	/* sun never rises today */
	    pr_string (R_SUNR, C_SUNRT, "Never rises           ");
	    pr_blanks (R_SUNS, C_SUNST, 14);
	    pr_blanks (R_LOD, C_LODV, 5);
	    return;
	case  2:	/* can not find where sun is! */
	    pr_string (R_SUNR, C_SUNRT, "?Error?               ");
	    pr_blanks (R_SUNS, C_SUNST, 14);
	    pr_blanks (R_LOD, C_LODV, 5);
	    return;
	default:	/* all ok */
	    ;
	}

	/* use local tz */
	tmp = utcr - tz; range (&tmp, 24.0);
	pr_mtime (R_SUNR, C_SUNRT, tmp);
	/* possible sunrise error near utc midnight if status is -2 */
	pr_char (R_SUNR, C_SUNRT+5, status==-2 ? '?' : ' ');
	pr_char (R_SUNR, C_SUNRT+6, '@');
	pr_angle (R_SUNR, C_SUNRAZ, azr);

	tmp = utcs - tz; range (&tmp, 24.0);
	pr_mtime (R_SUNS, C_SUNST, tmp);
	/* possible sunset error near utc midnight if status is -3 */
	pr_char (R_SUNS, C_SUNST+5, status==-3 ? '?' : ' ');
	pr_char (R_SUNS, C_SUNST+6, '@');
	pr_angle (R_SUNS, C_SUNSAZ, azs);

	pr_mtime (R_LOD, C_LODV, utcs - utcr);
}

/* display moon's rise/set times
 */
pr_moonrs (np)
Now *np;
{
	float utcr, utcs, azr, azs;
	float tmp;
	int status;

	moonrs_cir (np, &utcr, &utcs, &azr, &azs, &status);
	switch (status) {
	case -1:	/* never sets (circumpolar) */
	    pr_string (R_MOONR, C_MOONRT, "Circumpolar           ");
	    pr_blanks (R_MOONS, C_MOONST, 14);
	    return;
	case  1:	/* moon never rises today */
	    pr_string (R_MOONR, C_MOONRT, "Never rises           ");
	    pr_blanks (R_MOONS, C_MOONST, 14);
	    return;
	case  2:	/* can not find where moon is! */
	    pr_string (R_MOONR, C_MOONRT, "?Error?               ");
	    pr_blanks (R_MOONS, C_MOONST, 14);
	    return;
	default:	/* all ok */
	    ;
	}

	/* use local tz */
	tmp = utcr - tz; range (&tmp, 24.0);
	pr_mtime (R_MOONR, C_MOONRT, tmp);
	/* possible moonrise error near midnight if status is -2 */
	pr_char (R_MOONR, C_MOONRT+5, status==-2 ? '?' : ' ');
	pr_char (R_MOONR, C_MOONRT+6, '@');
	pr_angle (R_MOONR, C_MOONRAZ, azr);

	tmp = utcs - tz; range (&tmp, 24.0);
	pr_mtime (R_MOONS, C_MOONST, tmp);
	/* possible moonset error near midnight if status is -3 */
	pr_char (R_MOONS, C_MOONST+5, status==-3 ? '?' : ' ');
	pr_char (R_MOONS, C_MOONST+6, '@');
	pr_angle (R_MOONS, C_MOONSAZ, azs);
}

/* print sun's info now */
pr_sun (np, epoch)
Now *np;
float epoch;
{
	Sky sky;

	sun_cir (np, &sky);

	if (epoch != EOD)
	    precess ((float)mjd, epoch, &sky.s_ra, &sky.s_dec);
	pr_ra (R_SUN, C_RA, sky.s_ra);
	pr_angle (R_SUN, C_DEC, sky.s_dec);
	pr_angle (R_SUN, C_HLONG, sky.s_hlong);
	pr_angle (R_SUN, C_HLAT, sky.s_hlat);
	pr_angle (R_SUN, C_AZ, sky.s_az);
	pr_angle (R_SUN, C_ALT, sky.s_alt);

	pr_float (R_SUN, C_EDIST, "%6.4f", sky.s_edist);
	pr_float (R_SUN, C_SIZE, "%4.0f", sky.s_size);
	pr_float (R_SUN, C_MAG, "%4.0f", sky.s_mag);
}

/* print moon's info now */
pr_moon (np, epoch)
Now *np;
float epoch;
{
	Sky sky;

	moon_cir (np, &sky);

	if (epoch != EOD)
	    precess ((float)mjd, epoch, &sky.s_ra, &sky.s_dec);
	pr_ra (R_MOON, C_RA, sky.s_ra);
	pr_angle (R_MOON, C_DEC, sky.s_dec);
	pr_angle (R_MOON, C_AZ, sky.s_az);
	pr_angle (R_MOON, C_ALT, sky.s_alt);

	pr_float (R_MOON, C_EDIST, "%6.0f", sky.s_edist/1.609344); /* km->m */
	pr_float (R_MOON, C_SDIST, "%6.4f", sky.s_sdist);
	pr_float (R_MOON, C_ELONG, "%6.1f", sky.s_elong);
	pr_float (R_MOON, C_SIZE, "%4.0f", sky.s_size);
	pr_float (R_MOON, C_MAG, "%4.0f", sky.s_mag);
	pr_float (R_MOON, C_PHASE, "%3.0f", sky.s_phase);

}

pr_planet (p, np, epoch)
int p;
Now *np;
float epoch;
{
	Sky sky;
	int row = R_PLANTAB+4 + p;

	planet_cir (p, np, &sky);

	if (epoch != EOD)
	    precess ((float)mjd, epoch, &sky.s_ra, &sky.s_dec);
	pr_ra (row, C_RA, sky.s_ra);
	pr_angle (row, C_DEC, sky.s_dec);
	pr_angle (row, C_HLONG, sky.s_hlong);
	pr_angle (row, C_HLAT, sky.s_hlat);
	pr_angle (row, C_AZ, sky.s_az);
	pr_angle (row, C_ALT, sky.s_alt);

	pr_float (row, C_EDIST,(sky.s_edist>=10.0)?"%6.3f":"%6.4f",sky.s_edist);
	pr_float (row, C_SDIST,(sky.s_sdist>=10.0)?"%6.3f":"%6.4f",sky.s_sdist);
	pr_float (row, C_ELONG, "%6.1f", sky.s_elong);
	pr_float (row, C_SIZE, "%4.1f", sky.s_size);
	pr_float (row, C_MAG, "%4.1f", sky.s_mag);
	pr_float (row, C_PHASE, "%3.0f", sky.s_phase);
}

/* print all the time/date/where related stuff */
pr_now (np)
Now *np;
{
	char str[32];
	double lmjd = mjd - tz/24.0;
	float lst;

	sprintf (str, "%14.5f", (double)mjd + 2415020L);
	pr_string (R_JD, C_JDV, str);

	pr_time (R_UT, C_UTV, (float)mjd_hr(mjd));
	pr_date (R_UD, C_UD, (float)mjd_day(mjd));

	pr_time (R_TZONE, C_TZONEV, tz);
	sprintf (str, "%-3.3s", tznm); pr_string (R_TZN, C_TZN, str);
	pr_time (R_LT, C_LT, (float)mjd_hr(lmjd));
	pr_date (R_LD, C_LD, (float)mjd_day(lmjd));

	now_lst (np, &lst);
	pr_time (R_LST, C_LSTV, lst);
	pr_gangle (R_LONG, C_LONGV, -lng);	/* + west */
	pr_gangle (R_LAT, C_LATV, lat);

	/* print the calendar for local day, if new month/year.  */
	pr_calendar ((float)mjd_day(mjd-tz/24.0));
}

static
pr_calendar (jd)
float jd;
{
	static char *mnames[] = {
	    "January", "February", "March", "April", "May", "June",
	    "July", "August", "September", "October", "November", "December"
	};
	static int last_m, last_y;
	char str[64];
	int m, y;
	float d;
	int f, nd;
	int r;
	float jd0;

	/* get m/d/y. do nothing if still same month */
	mjd_cal (jd, &m, &d, &y);
	if (m == last_m && y == last_y)
	    return;
	last_m = m;
	last_y = y;

	/* find day of week of first day of month */
	cal_mjd (m, 1.0, y, &jd0);
	mjd_dow (jd0, &f);
	if (f < 0) {
	    /* can't figure it out - too hard before Gregorian */
	    int i;
	    for (i = 8; --i >= 0; )
		pr_string (R_CAL+i, C_CAL, "                    ");
	    return;
	}

	/* print header */
	pr_blanks (R_CAL, C_CAL, 20);
	sprintf (str, "%s %4d", mnames[m-1], y);
	pr_string (R_CAL, C_CAL + (20 - (strlen(mnames[m-1]) + 5))/2, str);
	pr_string (R_CAL+1, C_CAL, "Su Mo Tu We Th Fr Sa");

	/* find number of days in this month */
	mjd_dpm (jd0, &nd);

	/* print the calendar */
	for (r = 0; r < 6; r++) {
	    char row[7*3+1], *rp = row;
	    int c;
	    for (c = 0; c < 7; c++) {
		int i = r*7+c;
		if (i < f || i >= f + nd)
		    sprintf (rp, "   ");
		else
		    sprintf (rp, "%2d ", i-f+1);
		rp += 3;
	    }
	    pr_string (R_CAL+2+r, C_CAL, row);
	}

	/* over print the new and full moons for this month.
	 * TODO: don't really know which dates to use here (see moonnf())
	 *   so try several to be fairly safe. have to go back to 4/29/1988
	 *   to find the full moon on 5/1 for example.
	 */
	pr_nfmoon (jd0-3, m, f);
	pr_nfmoon (jd0+15, m, f);
}

static
pr_nfmoon (jd, m, f)
float jd;
int m, f;
{
	static char nm[] = "NM", fm[] = "FM";
	float dm;
	int mm, ym;
	float jdn, jdf;
	int di;

	moonnf (jd, &jdn, &jdf);
	mjd_cal (jdn, &mm, &dm, &ym);
	if (m == mm) {
	    di = dm + f - 1;
	    pr_string (R_CAL+2+di/7, C_CAL+3*(di%7), nm);
	}
	mjd_cal (jdf, &mm, &dm, &ym);
	if (m == mm) {
	    di = dm + f - 1;
	    pr_string (R_CAL+2+di/7, C_CAL+3*(di%7), fm);
	}
}


/* print info about object */
pr_obj(ra, dec, e, np, epoch)
float ra, dec, e;/* object'a ra, dec, epoch */
Now *np;	/* now info */
float epoch;	/* desired print epoch */
{
	Sky sky;

	/* fill sky as much as possible for object at ra/dec@EOD now */
	obj_cir (ra, dec, e, np, &sky);

	if (epoch != EOD)
	    precess ((float)mjd, epoch, &sky.s_ra, &sky.s_dec);
	pr_ra (R_OBJ, C_RA, sky.s_ra);
	pr_angle (R_OBJ, C_DEC, sky.s_dec);
	pr_angle (R_OBJ, C_ALT, sky.s_alt);
	pr_angle (R_OBJ, C_AZ, sky.s_az);
}
xXx
echo extracting pr0.c
cat > pr0.c << 'xXx'
/* basic print routines.
 */

#include <stdio.h>
#include <math.h>
#include "astro.h"
#include "screen.h"

/* the pr_ functions draw on the screen and in here so we can redraw
 * the screen via pr_redraw.
 */
static char screen_shadow[NR][NC];


pr_newcir (y)
int y;
{
	static char ncmsg[] = "NEW CIRCUMSTANCES";
	static char nomsg[] = "                 ";
	static int last_y = -1;

	if (y != last_y) {
	    pr_string (R_NEWCIR, C_NEWCIR, y ? ncmsg : nomsg);
	    last_y = y;
	}
}

/* draw n blanks at the given cursor position.  */
pr_blanks (r, c, n)
int r, c, n;
{
	char bl[NC+1];
	sprintf (bl, "%*s", n, "");
	pr_string (r, c, bl);
}

/* erase the planet info on the given row */
pr_noplanet (r)
int r;
{
	pr_blanks (r, C_RA, 80-C_RA+1);
}

/* print the given value, v, in "sexadecimal" format at [r,c]
 * ie, in the form A:m.P, where A is a digits wide, P is p digits.
 * if p == 0, then no decimal point either.
 */
pr_sexad (r, c, a, p, mod, v)
int r, c;
int a, p;	/* left space, min precision */
int mod;	/* don't let whole portion get this big */
float v;
{
	char astr[32], str[32];
	int dec;
	float frac;
	int visneg;

	plt_val (r, c, v);
	if (v >= 0.0)
	    visneg = 0;
	else {
	    visneg = 1;
	    v = -v;
	}

	dec = v;
	frac = (v - dec)*60.0;
	sprintf (str, "59.%.*s5", p, "999999999");
	if (frac >= atof (str)) {
	    dec += 1;
	    frac = 0.0;
	}
	dec %= mod;
	if (dec == 0 && visneg)
	    strcpy (str, "-0");
	else
	    sprintf (str, "%d", visneg ? -dec : dec);

	sprintf (astr, "%*s:%0*.*f", a, str, p == 0 ? 2 : p+3, p, frac);
	pr_string (r, c, astr);
}

/* print the given value, t, in sexagesimal format at [r,c]
 * ie, in the form T:mm:ss, where T is nd digits wide.
 * N.B. we assume nd >= 2.
 */
pr_sexag (r, c, nd, t)
int r, c, nd;
float t;
{
	char tstr[32];
	int h, m, s;
	int tisneg;
	
	plt_val (r, c, t);
	dec_sex (t, &h, &m, &s, &tisneg);
	if (h == 0 && tisneg)
	    sprintf (tstr, "%*s-0:%02d:%02d", nd-2, "", m, s);
	else
	    sprintf (tstr, "%*d:%02d:%02d", nd, tisneg ? -h : h, m, s);
	pr_string (r, c, tstr);
}

/* print angle ra, in radians, in ra hours as hh:mm.m at [r,c]
 * N.B. we assume ra is >= 0.
 */
pr_ra (r, c, ra)
int r, c;
float ra;
{
	pr_sexad (r, c, 2, 1, 24, radhr(ra));
}

/* print time, t, as hh:mm:ss */
pr_time (r, c, t)
int r, c;
float t;
{
	pr_sexag (r, c, 2, t);
}

/* print time, t, as hh:mm */
pr_mtime (r, c, t)
int r, c;
float t;
{
	pr_sexad (r, c, 2, 0, 24, t);
}

/* print angle, a, in rads, as degress at [r,c] in form ddd:mm */
pr_angle(r, c, a)
int r, c;
float a;
{
	pr_sexad (r, c, 3, 0, 360, raddeg(a));
}

/* print angle, a, in rads, as degress at [r,c] in form dddd:mm:ss */
pr_gangle(r, c, a)
int r, c;
float a;
{
	pr_sexag (r, c, 4, raddeg(a));
}

/* print the given modified Julian date, jd, as the starting date at [r,c]
 * in the form mm/dd/yyyy.
 */
pr_date (r, c, jd)
int r, c;
float jd;
{
	char dstr[32];
	int m, y;
	float d;

	mjd_cal (jd, &m, &d, &y);

	/* shadow to the plot subsystem as years
	 * TODO: make this monotonically increasing
	 */
	plt_val (r, c, y + (m-1 + (d-1)/30.4)/12.0);

	sprintf (dstr, "%2d/%02d/%04d", m, (int)(d), y);
	pr_string (r, c, dstr);
}

pr_char (row, col, c)
int row, col;
char c;
{
	c_pos (row, col);
	putchar (c);
	screen_shadow[row-1][col-1] = c;
}

pr_string (r, c, s)
int r, c;
char *s;
{
	c_pos (r, c);
	fputs (s, stdout);
	strncpy (&screen_shadow[r-1][c-1], s, strlen(s));
}

pr_float (r, c, fmt, f)
int r, c;
char *fmt;
float f;
{
	char str[80];
	sprintf (str, fmt, f);
	pr_string (r, c, str);
	plt_val (r, c, f);
}

pr_erase()
{
	int r, c;
	char *rp;

	c_erase();
	for (r = 0; r < NR; r++) {
	    rp = screen_shadow[r];
	    for (c = 0; c < NC; c++)
		rp[c] = ' ';
	}
}

/* redraw entire screen from the screen_shadow
 * N.B. might have '\0's in array; print them as ' '
 * N.B. don't write in lower right corner of screen to avoid scroll.
 */
pr_redraw()
{
	int r, c;
	char ch;
	int nc;
	char *rp;

	c_erase();
	for (r = 0; r < NR; r++) {
	    rp = screen_shadow[r];
	    c_pos (r+1,1);
	    /* set nc <= index of last non-blank char */
	    for (nc = NC; --nc >= 0; ) {
		ch = rp[nc];
		if (ch != ' ' && ch != '\0')
		    break;
	    }
	    /* draw chars with index 0..nc */
	    for (c = 0; c <= nc; c++) {
		ch = *rp++;
		if (ch == '\0')
		    ch = ' ';
		putchar (ch);
	    }
	}
}

pr_prompt (p)
char *p;
{
	int c;

	c_pos (R_PROMPT, C_PROMPT);
	c_eol ();
	for (c = C_PROMPT-1; c < NC; c++)
	    screen_shadow[R_PROMPT-1][c] = ' ';

	pr_string (R_PROMPT, C_PROMPT, p);
}
xXx
echo extracting screen.h
cat > screen.h << 'xXx'
/* screen layout details */

/* size of screen */
#define	NR	24
#define	NC	80

#define	LGAP	5	/* gap between field name and value in left column */
#define	GAP	6	/* gap between field name and value in other columns */

/* location of the various fields */
#define	R_TITLE		1
#define	C_TITLE		(NC/2)
#define	R_PROMPT	2
#define	C_PROMPT	1
#define	R_NEWCIR	3
#define	C_NEWCIR	((NC-17)/2)	/* 17 is length of the message */

#define	R_JD	4
#define	C_JD	1
#define	C_JDV	(C_JD+LGAP)
#define	R_LST	4
#define	C_LST	28
#define	C_LSTV	(C_LST+GAP)
#define	R_UT	5
#define	C_UT	1
#define	C_UTV	(C_UT+LGAP)
#define	R_UD	R_UT
#define	C_UD	(C_UT+14)
#define	R_TZN	6
#define	C_TZN	1
#define	R_LT	R_TZN
#define	C_LT	(C_TZN+LGAP)
#define	R_LD	R_TZN
#define	C_LD	(C_TZN+14)

#define	R_LAT	5
#define	C_LAT	28
#define	C_LATV	(C_LAT+4)
#define	R_LONG	5
#define	C_LONG	44
#define	C_LONGV	(C_LONG+4)
#define	R_TZONE	4
#define	C_TZONE	44
#define	C_TZONEV (C_TZONE+GAP)

#define	R_HEIGHT 8
#define	C_HEIGHT 28
#define	C_HEIGHTV (C_HEIGHT+GAP)
#define	R_TEMP	8
#define	C_TEMP	44
#define	C_TEMPV	(C_TEMP+GAP)
#define	R_PRES	9
#define	C_PRES	28
#define	C_PRESV	(C_PRES+GAP)
#define	R_NSTEP 7
#define	C_NSTEP	44
#define	C_NSTEPV (C_NSTEP+GAP)
#define	R_STPSZ	7
#define	C_STPSZ	28
#define	C_STPSZV (C_STPSZ+GAP)
#define	R_LOD	9
#define	C_LOD	44
#define	C_LODV	(C_LOD+GAP+3)
#define	R_LON	10
#define	C_LON	44
#define	C_LONV	(C_LON+GAP+3)
#define	R_PLOT	10
#define	C_PLOT	28
#define	C_PLOTV	(C_PLOT+GAP)

#define	R_CAL	3
#define	C_CAL   60

#define	RS_TGAP	(LGAP+3)
#define	RS_AZGAP 16
#define	R_SUNR	7
#define	C_SUNR	1
#define	C_SUNRT	(C_SUNR+RS_TGAP)
#define	C_SUNRAZ (C_SUNR+RS_AZGAP)
#define	R_SUNS	8
#define	C_SUNS	1
#define	C_SUNST (C_SUNS+RS_TGAP)
#define	C_SUNSAZ (C_SUNS+RS_AZGAP)

#define	R_MOONR	9
#define	C_MOONR	1
#define	C_MOONRT (C_MOONR+RS_TGAP)
#define	C_MOONRAZ (C_MOONR+RS_AZGAP)
#define	R_MOONS	10
#define	C_MOONS	1
#define	C_MOONST (C_MOONS+RS_TGAP)
#define	C_MOONSAZ (C_MOONS+RS_AZGAP)

#define	R_DAWN	6
#define	C_DAWN	28
#define	C_DAWNV	(C_DAWN+GAP+3)
#define	R_DUSK	6
#define	C_DUSK	44
#define	C_DUSKV	(C_DUSK+GAP+3)

/* planet info table */
#define	R_PLANTAB	12
#define	R_EPOCH		(R_PLANTAB+1)
#define	C_EPOCH		C_RA
#define	R_SUN		(R_PLANTAB+2)
#define	R_MOON		(R_PLANTAB+3)
#define	R_MERCURY	(R_PLANTAB+4)
#define	R_VENUS		(R_PLANTAB+5)
#define	R_MARS		(R_PLANTAB+6)
#define	R_JUPITER	(R_PLANTAB+7)
#define	R_SATURN	(R_PLANTAB+8)
#define	R_URANUS	(R_PLANTAB+9)
#define	R_NEPTUNE	(R_PLANTAB+10)
#define	R_PLUTO		(R_PLANTAB+11)
#define	R_OBJ		(R_PLANTAB+12)
#define	C_OBJ	1
#define	C_RA	4
#define	C_DEC	12
#define	C_HLONG	19
#define	C_HLAT	26
#define	C_AZ	33
#define	C_ALT	40
#define	C_EDIST	47
#define C_SDIST 54
#define	C_ELONG	61
#define	C_SIZE	68
#define	C_MAG	73
#define	C_PHASE	78

#define	PW	(NC-C_PROMPT+1)	/* total prompt line width */

#define	F_SHFT	12		/* shift to flags fields */
#define	F_CHG	(1<<F_SHFT)	/* field may be picked for changing */
#define	F_PLT	(2<<F_SHFT)	/* field may be picked for plotting */
#define	F_VIS	(4<<F_SHFT)	/* field is visible (may be picked period) */
#define	rcfpack(r,c,f)	((f) | ((r) << 7) | (c))
#define	unpackr(p)	(((p)>>7)&0x1f)
#define	unpackc(p)	((p)&0x7f)
#define	tstpackf(p,f)	(((p)&(f))==(f))
xXx
echo extracting sel_lfd.c
cat > sel_fld.c << 'xXx'
#include "screen.h"

#define	cntrl(x)	((x) & 037)
#define	ESC		cntrl('[')	/* char to exit input mode */
#define	QUIT		cntrl('d')	/* char to exit program */
#define	HELP		'?'		/* char to give help message */
#define	REDRAW		cntrl('l')	/* char to redraw (like vi) */
#define	VERSION		cntrl('v')	/* char to display version number */

/* table of the fields pickable for changing or plotting */
int fields[] = {
    rcfpack (R_DAWN, C_DAWN, F_VIS|F_CHG),
    rcfpack (R_DAWN, C_DAWNV, F_VIS|F_PLT),
    rcfpack (R_DUSK, C_DUSK, F_VIS|F_CHG),
    rcfpack (R_DUSK, C_DUSKV, F_VIS|F_PLT),
    rcfpack (R_EPOCH, C_EPOCH, F_VIS|F_CHG|F_PLT),
    rcfpack (R_HEIGHT, C_HEIGHTV, F_VIS|F_CHG|F_PLT),
    rcfpack (R_JUPITER, C_ALT, F_VIS|F_PLT),
    rcfpack (R_JUPITER, C_AZ, F_VIS|F_PLT),
    rcfpack (R_JUPITER, C_DEC, F_VIS|F_PLT),
    rcfpack (R_JUPITER, C_EDIST, F_VIS|F_PLT),
    rcfpack (R_JUPITER, C_ELONG, F_VIS|F_PLT),
    rcfpack (R_JUPITER, C_HLAT, F_VIS|F_PLT),
    rcfpack (R_JUPITER, C_HLONG, F_VIS|F_PLT),
    rcfpack (R_JUPITER, C_MAG, F_VIS|F_PLT),
    rcfpack (R_JUPITER, C_OBJ, F_VIS|F_CHG),
    rcfpack (R_JUPITER, C_PHASE, F_VIS|F_PLT),
    rcfpack (R_JUPITER, C_RA, F_VIS|F_PLT),
    rcfpack (R_JUPITER, C_SDIST, F_VIS|F_PLT),
    rcfpack (R_JUPITER, C_SIZE, F_VIS|F_PLT),
    rcfpack (R_LAT, C_LATV, F_VIS|F_CHG|F_PLT),
    rcfpack (R_LD, C_LD, F_VIS|F_PLT|F_CHG),
    rcfpack (R_LOD, C_LODV, F_VIS|F_CHG|F_PLT),
    rcfpack (R_LON, C_LONV, F_VIS|F_CHG|F_PLT),
    rcfpack (R_LONG, C_LONGV, F_VIS|F_CHG|F_PLT),
    rcfpack (R_LT, C_LT, F_VIS|F_CHG|F_PLT),
    rcfpack (R_MARS, C_ALT, F_VIS|F_PLT),
    rcfpack (R_MARS, C_AZ, F_VIS|F_PLT),
    rcfpack (R_MARS, C_DEC, F_VIS|F_PLT),
    rcfpack (R_MARS, C_EDIST, F_VIS|F_PLT),
    rcfpack (R_MARS, C_ELONG, F_VIS|F_PLT),
    rcfpack (R_MARS, C_HLAT, F_VIS|F_PLT),
    rcfpack (R_MARS, C_HLONG, F_VIS|F_PLT),
    rcfpack (R_MARS, C_MAG, F_VIS|F_PLT),
    rcfpack (R_MARS, C_OBJ, F_VIS|F_CHG),
    rcfpack (R_MARS, C_PHASE, F_VIS|F_PLT),
    rcfpack (R_MARS, C_RA, F_VIS|F_PLT),
    rcfpack (R_MARS, C_SDIST, F_VIS|F_PLT),
    rcfpack (R_MARS, C_SIZE, F_VIS|F_PLT),
    rcfpack (R_MERCURY, C_ALT, F_VIS|F_PLT),
    rcfpack (R_MERCURY, C_AZ, F_VIS|F_PLT),
    rcfpack (R_MERCURY, C_DEC, F_VIS|F_PLT),
    rcfpack (R_MERCURY, C_EDIST, F_VIS|F_PLT),
    rcfpack (R_MERCURY, C_ELONG, F_VIS|F_PLT),
    rcfpack (R_MERCURY, C_HLAT, F_VIS|F_PLT),
    rcfpack (R_MERCURY, C_HLONG, F_VIS|F_PLT),
    rcfpack (R_MERCURY, C_MAG, F_VIS|F_PLT),
    rcfpack (R_MERCURY, C_OBJ, F_VIS|F_CHG),
    rcfpack (R_MERCURY, C_PHASE, F_VIS|F_PLT),
    rcfpack (R_MERCURY, C_RA, F_VIS|F_PLT),
    rcfpack (R_MERCURY, C_SDIST, F_VIS|F_PLT),
    rcfpack (R_MERCURY, C_SIZE, F_VIS|F_PLT),
    rcfpack (R_MOON, C_ALT, F_VIS|F_PLT),
    rcfpack (R_MOON, C_AZ, F_VIS|F_PLT),
    rcfpack (R_MOON, C_DEC, F_VIS|F_PLT),
    rcfpack (R_MOON, C_EDIST, F_VIS|F_PLT),
    rcfpack (R_MOON, C_ELONG, F_VIS|F_PLT),
    rcfpack (R_MOON, C_MAG, F_VIS|F_PLT),
    rcfpack (R_MOON, C_OBJ, F_VIS|F_CHG),
    rcfpack (R_MOON, C_PHASE, F_VIS|F_PLT),
    rcfpack (R_MOON, C_RA, F_VIS|F_PLT),
    rcfpack (R_MOON, C_SDIST, F_VIS|F_PLT),
    rcfpack (R_MOON, C_SIZE, F_VIS|F_PLT),
    rcfpack (R_MOONR, C_MOONR, F_VIS|F_CHG),
    rcfpack (R_MOONR, C_MOONRAZ, F_VIS|F_PLT),
    rcfpack (R_MOONR, C_MOONRT, F_VIS|F_PLT),
    rcfpack (R_MOONS, C_MOONS, F_VIS|F_CHG),
    rcfpack (R_MOONS, C_MOONSAZ, F_VIS|F_PLT),
    rcfpack (R_MOONS, C_MOONST, F_VIS|F_PLT),
    rcfpack (R_NEPTUNE, C_ALT, F_VIS|F_PLT),
    rcfpack (R_NEPTUNE, C_AZ, F_VIS|F_PLT),
    rcfpack (R_NEPTUNE, C_DEC, F_VIS|F_PLT),
    rcfpack (R_NEPTUNE, C_EDIST, F_VIS|F_PLT),
    rcfpack (R_NEPTUNE, C_ELONG, F_VIS|F_PLT),
    rcfpack (R_NEPTUNE, C_HLAT, F_VIS|F_PLT),
    rcfpack (R_NEPTUNE, C_HLONG, F_VIS|F_PLT),
    rcfpack (R_NEPTUNE, C_MAG, F_VIS|F_PLT),
    rcfpack (R_NEPTUNE, C_OBJ, F_VIS|F_CHG),
    rcfpack (R_NEPTUNE, C_PHASE, F_VIS|F_PLT),
    rcfpack (R_NEPTUNE, C_RA, F_VIS|F_PLT),
    rcfpack (R_NEPTUNE, C_SDIST, F_VIS|F_PLT),
    rcfpack (R_NEPTUNE, C_SIZE, F_VIS|F_PLT),
    rcfpack (R_NSTEP, C_NSTEPV, F_VIS|F_CHG),
    rcfpack (R_OBJ, C_ALT, F_VIS|F_PLT),
    rcfpack (R_OBJ, C_AZ, F_VIS|F_PLT),
    rcfpack (R_OBJ, C_DEC, F_VIS|F_CHG|F_PLT),
    rcfpack (R_OBJ, C_OBJ, F_VIS|F_CHG),
    rcfpack (R_OBJ, C_RA, F_VIS|F_CHG|F_PLT),
    rcfpack (R_PLOT, C_PLOT, F_VIS|F_CHG),
    rcfpack (R_PLOT, C_PLOTV, F_VIS|F_CHG),
    rcfpack (R_PLUTO, C_ALT, F_VIS|F_PLT),
    rcfpack (R_PLUTO, C_AZ, F_VIS|F_PLT),
    rcfpack (R_PLUTO, C_DEC, F_VIS|F_PLT),
    rcfpack (R_PLUTO, C_EDIST, F_VIS|F_PLT),
    rcfpack (R_PLUTO, C_ELONG, F_VIS|F_PLT),
    rcfpack (R_PLUTO, C_HLAT, F_VIS|F_PLT),
    rcfpack (R_PLUTO, C_HLONG, F_VIS|F_PLT),
    rcfpack (R_PLUTO, C_MAG, F_VIS|F_PLT),
    rcfpack (R_PLUTO, C_OBJ, F_VIS|F_CHG),
    rcfpack (R_PLUTO, C_PHASE, F_VIS|F_PLT),
    rcfpack (R_PLUTO, C_RA, F_VIS|F_PLT),
    rcfpack (R_PLUTO, C_SDIST, F_VIS|F_PLT),
    rcfpack (R_PLUTO, C_SIZE, F_VIS|F_PLT),
    rcfpack (R_PRES, C_PRESV, F_VIS|F_CHG|F_PLT),
    rcfpack (R_SATURN, C_ALT, F_VIS|F_PLT),
    rcfpack (R_SATURN, C_AZ, F_VIS|F_PLT),
    rcfpack (R_SATURN, C_DEC, F_VIS|F_PLT),
    rcfpack (R_SATURN, C_EDIST, F_VIS|F_PLT),
    rcfpack (R_SATURN, C_ELONG, F_VIS|F_PLT),
    rcfpack (R_SATURN, C_HLAT, F_VIS|F_PLT),
    rcfpack (R_SATURN, C_HLONG, F_VIS|F_PLT),
    rcfpack (R_SATURN, C_MAG, F_VIS|F_PLT),
    rcfpack (R_SATURN, C_OBJ, F_VIS|F_CHG),
    rcfpack (R_SATURN, C_PHASE, F_VIS|F_PLT),
    rcfpack (R_SATURN, C_RA, F_VIS|F_PLT),
    rcfpack (R_SATURN, C_SDIST, F_VIS|F_PLT),
    rcfpack (R_SATURN, C_SIZE, F_VIS|F_PLT),
    rcfpack (R_STPSZ, C_STPSZV, F_VIS|F_CHG),
    rcfpack (R_SUN, C_ALT, F_VIS|F_PLT),
    rcfpack (R_SUN, C_AZ, F_VIS|F_PLT),
    rcfpack (R_SUN, C_DEC, F_VIS|F_PLT),
    rcfpack (R_SUN, C_EDIST, F_VIS|F_PLT),
    rcfpack (R_SUN, C_HLAT, F_VIS|F_PLT),
    rcfpack (R_SUN, C_HLONG, F_VIS|F_PLT),
    rcfpack (R_SUN, C_MAG, F_VIS|F_PLT),
    rcfpack (R_SUN, C_OBJ, F_VIS|F_CHG),
    rcfpack (R_SUN, C_RA, F_VIS|F_PLT),
    rcfpack (R_SUN, C_SIZE, F_VIS|F_PLT),
    rcfpack (R_SUNR, C_SUNR, F_VIS|F_CHG),
    rcfpack (R_SUNR, C_SUNRAZ, F_VIS|F_PLT),
    rcfpack (R_SUNR, C_SUNRT, F_VIS|F_PLT),
    rcfpack (R_SUNS, C_SUNS, F_VIS|F_CHG),
    rcfpack (R_SUNS, C_SUNSAZ, F_VIS|F_PLT),
    rcfpack (R_SUNS, C_SUNST, F_VIS|F_PLT),
    rcfpack (R_TEMP, C_TEMPV, F_VIS|F_CHG|F_PLT),
    rcfpack (R_TZN, C_TZN, F_VIS|F_CHG),
    rcfpack (R_TZONE, C_TZONEV, F_VIS|F_CHG),
    rcfpack (R_UD, C_UD, F_VIS|F_PLT|F_CHG),
    rcfpack (R_URANUS, C_ALT, F_VIS|F_PLT),
    rcfpack (R_URANUS, C_AZ, F_VIS|F_PLT),
    rcfpack (R_URANUS, C_DEC, F_VIS|F_PLT),
    rcfpack (R_URANUS, C_EDIST, F_VIS|F_PLT),
    rcfpack (R_URANUS, C_ELONG, F_VIS|F_PLT),
    rcfpack (R_URANUS, C_HLAT, F_VIS|F_PLT),
    rcfpack (R_URANUS, C_HLONG, F_VIS|F_PLT),
    rcfpack (R_URANUS, C_MAG, F_VIS|F_PLT),
    rcfpack (R_URANUS, C_OBJ, F_VIS|F_CHG),
    rcfpack (R_URANUS, C_PHASE, F_VIS|F_PLT),
    rcfpack (R_URANUS, C_RA, F_VIS|F_PLT),
    rcfpack (R_URANUS, C_SDIST, F_VIS|F_PLT),
    rcfpack (R_URANUS, C_SIZE, F_VIS|F_PLT),
    rcfpack (R_UT, C_UTV, F_VIS|F_PLT|F_CHG),
    rcfpack (R_VENUS, C_ALT, F_VIS|F_PLT),
    rcfpack (R_VENUS, C_AZ, F_VIS|F_PLT),
    rcfpack (R_VENUS, C_DEC, F_VIS|F_PLT),
    rcfpack (R_VENUS, C_EDIST, F_VIS|F_PLT),
    rcfpack (R_VENUS, C_ELONG, F_VIS|F_PLT),
    rcfpack (R_VENUS, C_HLAT, F_VIS|F_PLT),
    rcfpack (R_VENUS, C_HLONG, F_VIS|F_PLT),
    rcfpack (R_VENUS, C_MAG, F_VIS|F_PLT),
    rcfpack (R_VENUS, C_OBJ, F_VIS|F_CHG),
    rcfpack (R_VENUS, C_PHASE, F_VIS|F_PLT),
    rcfpack (R_VENUS, C_RA, F_VIS|F_PLT),
    rcfpack (R_VENUS, C_SDIST, F_VIS|F_PLT),
    rcfpack (R_VENUS, C_SIZE, F_VIS|F_PLT),
};
#define	NFIELDS (sizeof(fields)/sizeof(fields[0]))

/* let op select a field by moving around and hitting RETURN, or until see ESC.
 * only allow fields with the given flag mask.
 * return the rcfpack()'d field, or 0 if typed ESC.
 * N.B. we might also exit() entirely by calling bye() of op types QUIT.
 */
sel_fld (r, c, flag, prmpt, help)
int r, c;	/* inial row, col */
int flag;
char *prmpt, *help;
{
	char *lastp;
	int ch;

	lastp = 0;
	while (1) {
	    if (lastp != prmpt) {
		lastp = prmpt;
		pr_prompt (lastp);
	    }
	    c_pos (r, c);
	    switch (ch = read_char()) {
	    case REDRAW:
		pr_redraw();
		lastp = 0;
		break;
	    case VERSION:
		version();
		lastp = 0;
		break;
	    case HELP:
		pr_prompt (help);
		(void) read_char(); /* hit any key to continue */
		lastp = 0;
		break;
	    case QUIT:
		bye();	/* probably never returns */
		break;
	    case ESC:
		return (0);
	    case '\r':
		return (rcfpack (r, c, 0));
	    default:
		move_cur (ch, flag, &r, &c);
		break;
	    }
	}
}

/* move cursor to next field in given direction: hjkl.
 * limit eligible fields to those with given flag mask.
 */
static
move_cur (dirchar, flag, rp, cp)
char dirchar;
int flag;
int *rp, *cp;
{
	int curr = *rp, curc = *cp;
	int f, newf, *fp;
	int d, newd;

	newf = 0;
	newd = 1000;

	switch (dirchar) {
	case 'h': case 'H': /* left */
	    /* go to next field to the left, or wrap.  */
	    for (fp = fields+NFIELDS; --fp >= fields; ) {
		f = *fp;
		if (tstpackf(f,flag) && unpackr(f) == curr) {
		    d = curc - unpackc(f);
		    if (d > 0 && d < newd) {
			newf = f;
			newd = d;
		    }
		}
	    }
	    if (newf)
		curc = unpackc(newf);
	    else {
		curc = NC;
		move_cur (dirchar, flag, &curr, &curc);
	    }
	    break;

	case 'j': case 'J': /* down */
	    /* go to closest field on next row down with anything on it,
	     * or wrap.
	     */
	    for (fp = fields+NFIELDS; --fp >= fields; ) {
		f = *fp;
		if (tstpackf(f,flag)) {
		    d = unpackr(f) - curr;
		    if (d > 0 && d < newd) {
			newf = f;
			newd = d;
		    }
		}
	    }
	    if (newf) {
		newf = nearestfld (unpackr(newf), curc, flag);
		curr = unpackr(newf);
		curc = unpackc(newf);
	    } else {
		curr = 0;
		move_cur (dirchar, flag, &curr, &curc);
	    }
	    break;

	case 'k': case 'K': /* up */
	    /* go to closest field on next row up with anything on it, 
	     * or wrap.
	     */
	    for (fp = fields+NFIELDS; --fp >= fields; ) {
		f = *fp;
		if (tstpackf(f,flag)) {
		    d = curr - unpackr(f);
		    if (d > 0 && d < newd) {
			newf = f;
			newd = d;
		    }
		}
	    }
	    if (newf) {
		newf = nearestfld (unpackr(newf), curc, flag);
		curr = unpackr(newf);
		curc = unpackc(newf);
	    } else {
		curr = NR+1;
		move_cur (dirchar, flag, &curr, &curc);
	    }
	    break;

	case 'l': case 'L': /* right */
	case ' ': /* space also goes right */
	    /* go to next field to the right, or wrap.  */
	    for (fp = fields+NFIELDS; --fp >= fields; ) {
		f = *fp;
		if (tstpackf(f,flag) && unpackr(f) == curr) {
		    d = unpackc(f) - curc;
		    if (d > 0 && d < newd) {
			newf = f;
			newd = d;
		    }
		}
	    }
	    if (newf)
		curc = unpackc(newf);
	    else {
		curc = 0;
		move_cur (dirchar, flag, &curr, &curc);
	    }
	    break;
	}

	*rp = curr;
	*cp = curc;
}

/* return the nearest field with given flag mask, either way, on this row,
 * else -1 if none.
 */
static
nearestfld (r, c, flag)
int r, c, flag;
{
	int nf, f, *fp;
	int d, d0;

	nf = 0;
	d0 = 1000;

	for (fp = fields+NFIELDS; --fp >= fields; ) {
	    f = *fp;
	    if (tstpackf(f,flag) && unpackr(f) == r) {
		d = abs(c - unpackc(f));
		if (d < d0) {
		    nf = f;
		    d0 = d;
		}
	    }
	}
	return (nf ? nf : -1);
}
xXx
echo extracting time.c
cat > time.c << 'xXx'
#include <stdio.h>
#include <time.h>
#include "astro.h"
#include "circum.h"

/* shorthands into np */
#define mjd	np->n_mjd
#define lat	np->n_lat
#define lng	np->n_lng
#define tz	np->n_tz
#define temp	np->n_temp
#define pressure	np->n_pressure
#define height	np->n_height
#define tznm	np->n_tznm

static long c0;
static double mjd0;

/* save current mjd and corresponding system clock for use by inc_mjd().
 * this establishes the base correspondence between the mjd and system clock.
 */
set_t0 (np)
Now *np;
{
	mjd0 = mjd;
	time (&c0);
}

/* fill in n_mjd/tz/tznm from system clock */
time_fromsys (np)
Now *np;
{
	extern long timezone;
	extern int daylight;
	extern char *tzname[2];
	extern struct tm *gmtime();
	struct tm *tp;
	long c;
	float day, hr;

	tzset();
	tz = timezone/3600;
	strncpy (tznm, tzname[daylight?1:0], sizeof(tznm)-1);
	tznm[sizeof(tznm)-1] = '\0';	/* insure string is terminated */

	time (&c);
	tp = gmtime (&c);
	cal_mjd (tp->tm_mon+1, (float)tp->tm_mday, tp->tm_year+1900, &day);
	sex_dec (tp->tm_hour, tp->tm_min, tp->tm_sec, &hr);
	mjd = (double)day + hr/24.0;
}

inc_mjd (np, inc)
Now *np;
float inc;
{
	if (inc == RTC) {
	    long c;
	    time (&c);
	    mjd = mjd0 + (c - c0)/SPD;
	} else
	    mjd += inc/24.0;

	/* round to nearest whole second.
	 * without this, you can get fractional days so close to .5 but
	 * not quite there that mjd_hr() can return 24.0
	 */
	rnd_second (&mjd);
}
xXx
echo extracting version.c
cat > version.c << 'xXx'
/* N.B. edit this any time something is changed.
 * keep a running history too:
 *  2.0  9/13/1988 add version ^v option
 *  2.1  9/14/1988 moon phase always >= 0 to match planets convention
 *  2.2  9/20/1988 more caution in aaha_aux() guarding acos() arg range
 *  2.3  9/23/1988 exchange Altitude/Elevation titles (no code changes)
 *  2.4 10/31/1988 add credits banner, -s turns it off; savings time fix.
 *  2.5 12/26/1988 remove trace capability; add screen shadowing: ^l.
 *  2.6 12/28/1988 twilight defined as 18 rather than 15 degrees below horizon
 *  2.7 12/30/1988 add version to credits.
 *  3.0 12/31/1988 add graphing; add version to credits.
 *  3.1   1/1/1989 user def. graph labels; nstep/stpsz control; genuine c_eol
 *  3.2   1/3/1989 if set date/time then time does not inc first step
 *  3.3   1/6/1989 add z to plot files (still don't plot it however)
 *  3.4  1/22/1989 calendar and all rise/set times based on local date, not utc
 *  3.5   2/2/1989 sunrise/set times based on actual sun size and pressure/temp
 *  3.6   2/7/1989 try adding .cfg suffix if can't find config file
 *  3.7  2/13/1989 change to ^d to quit program.
 *  3.8   3/2/1989 shorten displayed precision, add heliocentric lat/long
 *  3.9   4/5/1989 discard leading termcap delay digits, for now
 *  3.10 4/27/1989 allow caps for moving cursor around too
 *  3.11 5/16/1989 local time prompt said utc; add NiteLn; check for bad plot
 *                 files; couldn't plot dayln or niteln.
 */

#include "screen.h"

static char vmsg[] = "Version 3.11  May 16, 1989";

version()
{
	pr_prompt (vmsg);
	(void) read_char(); /* hit any key to continue */
}

static char *cre[] = {
"Ephem - computerized ephemeris",
vmsg,
"by Elwood Downey",
"",
"Many formulas and tables are based, with permission, on material found in",
"\"Astronomy with your Personal Computer\"",
"by Dr. Peter Duffett-Smith, Cambridge University Press, 1985",
"",
"type any key to continue..."
};
credits()
{
	int r = 10;	/* first row of credits message */
	int l;

	pr_erase();
	for (l = 0; l < sizeof(cre)/sizeof(cre[0]); l++)
	    pr_string (r++, (NC - strlen(cre[l]))/2, cre[l]);
	(void) read_char();	/* wait for any char to continue */
}
xXx