home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume9 / ephem2 / part03 < prev    next >
Text File  |  1989-11-27  |  53KB  |  2,087 lines

  1. Newsgroups: comp.sources.misc
  2. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  3. Subject: v09i040: ephem, v4.8, 3 of 5
  4. Reply-To: ecd@umn-cs.cs.umn.edu@ncs-med.UUCP (Elwood C. Downey)
  5.  
  6. Posting-number: Volume 9, Issue 40
  7. Submitted-by: ecd@umn-cs.cs.umn.edu@ncs-med.UUCP (Elwood C. Downey)
  8. Archive-name: ephem2/part03
  9.  
  10. # This is a "shell archive" file; run it with sh.
  11. # This is file 3.
  12. echo x io.c
  13. cat > io.c << 'xXx'
  14. /* this file (in principle) contains all the device-dependent code for
  15.  * handling screen movement and reading the keyboard. public routines are:
  16.  *   c_pos(r,c), c_erase(), c_eol();
  17.  *   chk_char(), read_char(), read_line (buf, max); and
  18.  *   byetty().
  19.  * N.B. we assume output may be performed by printf(), putchar() and
  20.  *   fputs(stdout). since these are buffered we flush first in read_char().
  21.  * #define UNIX or TURBO_C to give two popular versions.
  22.  * UNIX uses termcap; TURBO_C uses ANSI and the IBM-PC keyboard codes.
  23.  * TURBO_C should work for Lattice too.
  24.  */
  25.  
  26. #define    UNIX
  27. /* #define TURBO_C */
  28.  
  29. #include <stdio.h>
  30. #include "screen.h"
  31.  
  32. #ifdef UNIX
  33. #include <sgtty.h>
  34. #include <signal.h>
  35.  
  36. extern char *tgoto();
  37. static char *cm, *ce, *cl, *kl, *kr, *ku, *kd; /* curses sequences */
  38. static int tloaded;
  39. static int ttysetup;
  40. static struct sgttyb orig_sgtty;
  41.  
  42. /* move cursor to row, col, 1-based.
  43.  * we assume this also moves a visible cursor to this location.
  44.  */
  45. c_pos (r, c)
  46. int r, c;
  47. {
  48.     if (!tloaded) tload();
  49.     fputs (tgoto (cm, c-1, r-1), stdout);
  50. }
  51.  
  52. /* erase entire screen. */
  53. c_erase()
  54. {
  55.     if (!tloaded) tload();
  56.     fputs (cl, stdout);
  57. }
  58.  
  59. /* erase to end of line */
  60. c_eol()
  61. {
  62.     if (!tloaded) tload();
  63.     fputs (ce, stdout);
  64. }
  65.  
  66. /* return 0 if there is a char that may be read without blocking, else -1 */
  67. chk_char()
  68. {
  69.     long n = 0;
  70.     if (!ttysetup) setuptty();
  71.     ioctl (0, FIONREAD, &n);
  72.     return (n > 0 ? 0 : -1);
  73. }
  74.  
  75. /* read the next char, blocking if necessary, and return it. don't echo.
  76.  * map the arrow keys if we can too into hjkl
  77.  */
  78. read_char()
  79. {
  80.     char c;
  81.     if (!ttysetup) setuptty();
  82.     fflush (stdout);
  83.     read (0, &c, 1);
  84.     return (chk_arrow (c & 0177)); /* just ASCII, please */
  85. }
  86.  
  87. /* used to time out of a read */
  88. static got_alrm;
  89. static
  90. on_alrm()
  91. {
  92.     got_alrm = 1;
  93. }
  94.  
  95. /* see if c is the first of any of the curses arrow key sequences.
  96.  * if it is, read the rest of the sequence, and return the hjkl code
  97.  * that corresponds.
  98.  * if no match, just return c.
  99.  */
  100. static 
  101. chk_arrow (c)
  102. register char c;
  103. {
  104.     register char *seq;
  105.  
  106.     if (c == *(seq = kl) || c == *(seq = kd) || c == *(seq = ku)
  107.                          || c == *(seq = kr)) {
  108.         char seqa[10]; /* maximum arrow escape sequence ever expected */
  109.         int l = strlen(seq);
  110.         seqa[0] = c;
  111.         /* most arrow keys generate sequences starting with ESC. if so
  112.          * c might just be a lone ESC; time out if so.
  113.          */
  114.         got_alrm=0;
  115.         if (c == '') {
  116.         signal (SIGALRM, on_alrm);
  117.         alarm(1);
  118.         }
  119.         read (0, seqa+1, l-1);
  120.         if (got_alrm == 0) {
  121.         if (c == '')
  122.             alarm(0);
  123.         seqa[l] = '\0';
  124.         if (strcmp (seqa, kl) == 0)
  125.             return ('h');
  126.         if (strcmp (seqa, kd) == 0)
  127.             return ('j');
  128.         if (strcmp (seqa, ku) == 0)
  129.             return ('k');
  130.         if (strcmp (seqa, kr) == 0)
  131.             return ('l');
  132.         }
  133.     }
  134.     return (c);
  135. }
  136.  
  137. /* do whatever might be necessary to get the screen and/or tty back into shape.
  138.  */
  139. byetty()
  140. {
  141.     ioctl (0, TIOCSETP, &orig_sgtty);
  142. }
  143.  
  144. static 
  145. tload()
  146. {
  147.     extern char *getenv(), *tgetstr();
  148.     extern char *UP, *BC;
  149.     char *egetstr();
  150.     static char tbuf[512];
  151.     char rawtbuf[1024];
  152.     char *tp;
  153.     char *ptr;
  154.  
  155.     if (!(tp = getenv ("TERM"))) {
  156.         printf ("Must have addressable cursor\n");
  157.         exit(1);
  158.     }
  159.  
  160.     if (!ttysetup) setuptty();
  161.     if (tgetent (rawtbuf, tp) != 1) {
  162.         printf ("can't find termcap for %s\n", tp);
  163.         exit (1);
  164.     }
  165.     ptr = tbuf;
  166.     ku = egetstr ("ku", &ptr);
  167.     kd = egetstr ("kd", &ptr);
  168.     kl = egetstr ("kl", &ptr);
  169.     kr = egetstr ("kr", &ptr);
  170.     cm = egetstr ("cm", &ptr);
  171.     ce = egetstr ("ce", &ptr);
  172.     cl = egetstr ("cl", &ptr);
  173.     UP = egetstr ("up", &ptr);
  174.     if (!tgetflag ("bs"))
  175.         BC = egetstr ("bc", &ptr);
  176.     tloaded = 1;
  177. }
  178.  
  179. /* like tgetstr() but discard curses delay codes, for now anyways */
  180. static char *
  181. egetstr (name, sptr)
  182. char *name;
  183. char **sptr;
  184. {
  185.     extern char *tgetstr();
  186.     register char c, *s;
  187.  
  188.     s = tgetstr (name, sptr);
  189.     while ((c = *s) >= '0' && c <= '9')
  190.         s += 1;
  191.     return (s);
  192. }
  193.  
  194. static
  195. setuptty()
  196. {
  197.     extern ospeed;
  198.     struct sgttyb sg;
  199.  
  200.     ioctl (0, TIOCGETP, &orig_sgtty);
  201.     sg = orig_sgtty;
  202.     ospeed = sg.sg_ospeed;
  203.     sg.sg_flags &= ~ECHO;    /* do our own echoing */
  204.     sg.sg_flags &= ~CRMOD;    /* leave CR and LF unchanged */
  205.     sg.sg_flags |= XTABS;    /* no tabs with termcap */
  206.     sg.sg_flags |= CBREAK;    /* wake up on each char but can still kill */
  207.     ioctl (0, TIOCSETP, &sg);
  208.     ttysetup = 1;
  209. }
  210. #endif
  211.  
  212. #ifdef TURBO_C
  213.  
  214.  
  215. /* position cursor.
  216.  * (ANSI: ESC [ r ; c f) (r/c are numbers given in ASCII digits)
  217.  */
  218. c_pos (r, c)
  219. int r, c;
  220. {
  221.     printf ("%d;%df", r, c);
  222. }
  223.  
  224. /* erase entire screen. (ANSI: ESC [ 2 J) */
  225. c_erase()
  226. {
  227.     printf ("");
  228. }
  229.  
  230. /* erase to end of line. (ANSI: ESC [ K) */
  231. c_eol()
  232. {
  233.     printf ("");
  234. }
  235.  
  236. /* return 0 if there is a char that may be read without blocking, else -1 */
  237. chk_char()
  238. {
  239.     return (kbhit() == 0 ? -1 : 0);
  240. }
  241.  
  242. /* read the next char, blocking if necessary, and return it. don't echo.
  243.  * map the arrow keys if we can too into hjkl
  244.  */
  245. read_char()
  246. {
  247.     int c;
  248.     fflush (stdout);
  249.     c = getch();
  250.     if (c == 0) {
  251.         /* get scan code; convert to direction hjkl if possible */
  252.         c = getch();
  253.         switch (c) {
  254.         case 0x4b: c = 'h'; break;
  255.         case 0x50: c = 'j'; break;
  256.         case 0x48: c = 'k'; break;
  257.         case 0x4d: c = 'l'; break;
  258.         }
  259.     }
  260.     return (c);
  261. }
  262.  
  263. /* do whatever might be necessary to get the screen and/or tty back into shape.
  264.  */
  265. byetty()
  266. {
  267. }
  268. #endif
  269.  
  270. /* read up to max chars into buf, with cannonization.
  271.  * add trailing '\0' (buf is really max+1 chars long).
  272.  * return count of chars read (not counting '\0').
  273.  * assume cursor is already positioned as desired.
  274.  * if type END when n==0 then return -1.
  275.  */
  276. read_line (buf, max)
  277. char buf[];
  278. int max;
  279. {
  280.     static char erase[] = "\b \b";
  281.     int n, c;
  282.     int done;
  283.  
  284. #ifdef UNIX
  285.     if (!ttysetup) setuptty();
  286. #endif
  287.  
  288.     for (done = 0, n = 0; !done; )
  289.         switch (c = read_char()) {    /* does not echo */
  290.         case cntrl('h'):    /* backspace or */
  291.         case 0177:        /* delete are each char erase */
  292.         if (n > 0) {
  293.             fputs (erase, stdout);
  294.             n -= 1;
  295.         }
  296.         break;
  297.         case cntrl('u'):        /* line erase */
  298.         while (n > 0) {
  299.             fputs (erase, stdout);
  300.             n -= 1;
  301.         }
  302.         break;
  303.         case '\r':    /* EOL */
  304.         done++;
  305.         break;
  306.         default:            /* echo and store, if ok */
  307.         if (n == 0 && c == END)
  308.             return (-1);
  309.         if (n >= max)
  310.             putchar (cntrl('g'));
  311.         else if (c >= ' ') {
  312.             putchar (c);
  313.             buf[n++] = c;
  314.         }
  315.         }
  316.  
  317.     buf[n] = '\0';
  318.     return (n);
  319. }
  320. xXx
  321. echo x main.c
  322. cat > main.c << 'xXx'
  323. /* main program. 
  324.  * set options.
  325.  * init screen and circumstances.
  326.  * enter infinite loop updating screen and allowing operator input.
  327.  */
  328.  
  329. #include <stdio.h>
  330. #include <signal.h>
  331. #include <math.h>
  332. #include "astro.h"
  333. #include "circum.h"
  334. #include "screen.h"
  335.  
  336. extern char *getenv();
  337.  
  338. /* shorthands for fields of a Now structure, now.
  339.  * first undo the ones for a Now pointer from circum.h.
  340.  */
  341. #undef mjd
  342. #undef lat
  343. #undef lng
  344. #undef tz
  345. #undef temp
  346. #undef pressure
  347. #undef height
  348. #undef epoch
  349. #undef tznm
  350.  
  351. #define mjd    now.n_mjd
  352. #define lat    now.n_lat
  353. #define lng    now.n_lng
  354. #define tz    now.n_tz
  355. #define temp    now.n_temp
  356. #define pressure now.n_pressure
  357. #define height    now.n_height
  358. #define epoch    now.n_epoch
  359. #define tznm    now.n_tznm
  360.  
  361. static char *cfgfile = "ephem.cfg";    /* default config filename */
  362.  
  363. static Now now;        /* where when and how, right now */
  364. static double tminc;    /* hrs to inc time by each loop; RTC means use clock */
  365. static int nstep;    /* steps to go before stopping */
  366. static int optwi;    /* set when want to display dawn/dusk/len-of-night */
  367. static int oppl;    /* mask of (1<<planet) bits; set when want to show it */
  368.  
  369. main (ac, av)
  370. int ac;
  371. char *av[];
  372. {
  373.     void bye();
  374.     static char freerun[] =
  375.         "Running... press any key to stop to make changes.";
  376.     static char prmpt[] =
  377. "Move to another field, RETURN to change this field, ? for help, or q to run";
  378.     static char hlp[] =
  379.     "arrow keys move to field; any key stops running; ^d exits; ^l redraws";
  380.     int curr = R_NSTEP, curc = C_NSTEPV;    /* must start somewhere */
  381.     int sflag = 0;    /* not silent, by default */
  382.     int one = 1;    /* use a variable so optimizer doesn't get disabled */
  383.     int srchdone = 0; /* true when search funcs say so */
  384.     int newcir = 2;    /* set when circumstances change - means don't tminc */
  385.  
  386.     while ((--ac > 0) && (**++av == '-')) {
  387.         char *s;
  388.         for (s = *av+1; *s != '\0'; s++)
  389.         switch (*s) {
  390.         case 's': /* no credits "silent" (don't publish this) */
  391.             sflag++;
  392.             break;
  393.         case 'c': /* set name of config file to use */
  394.             if (--ac <= 0) usage("-c but no config file");
  395.             cfgfile = *++av;
  396.             break;
  397.         default:
  398.             usage("Bad - option");
  399.         }
  400.     }
  401.  
  402.     if (!sflag)
  403.         credits();
  404.  
  405.     /* fresh screen.
  406.      * crack config file, THEN args so args may override.
  407.      */
  408.     c_erase();
  409.     read_cfgfile (cfgfile);
  410.     read_fieldargs (ac, av);
  411.  
  412.     /* set up to clean up screen and tty if interrupted */
  413.     signal (SIGINT, bye);
  414.  
  415.     /* update screen forever (until QUIT) */
  416.     while (one) {
  417.  
  418.         nstep -= 1;
  419.  
  420.         /* recalculate everything and update all the fields */
  421.         redraw_screen (newcir);
  422.         mm_newcir (0);
  423.  
  424.         /* let searching functions change tminc and check for done */
  425.         srchdone = srch_eval (mjd, &tminc) < 0;
  426.         print_tminc(0);    /* to show possibly new search increment */
  427.  
  428.         /* update plot file, now that all fields are up to date and
  429.          * search function has been evaluated.
  430.          */
  431.         plot();
  432.  
  433.         /* stop loop to allow op to change parameters:
  434.          * if a search evaluation converges (or errors out),
  435.          * or if steps are done,
  436.          * or if op hits any key.
  437.          */
  438.         newcir = 0;
  439.         if (srchdone || nstep <= 0 || (chk_char()==0 && read_char()!=0)) {
  440.         int fld;
  441.  
  442.         /* update screen with the current stuff if stopped during
  443.          * unattended plotting since last redraw_screen() didn't.
  444.          */
  445.         if (plot_ison() && nstep > 0)
  446.             redraw_screen (1);
  447.  
  448.         /* return nstep to default of 1 */
  449.         if (nstep <= 0) {
  450.             nstep = 1;
  451.             print_nstep (0);
  452.         }
  453.  
  454.         /* change fields until END.
  455.          * update all time fields if any are changed
  456.          * and print NEW CIRCUMSTANCES if any have changed.
  457.          * QUIT causes bye() to be called and we never return.
  458.          */
  459.         while(fld = sel_fld(curr,curc,alt_menumask()|F_CHG,prmpt,hlp)) {
  460.             if (chg_fld ((char *)0, fld)) {
  461.             mm_now (&now, 1);
  462.             mm_newcir(1);
  463.             newcir = 1;
  464.             }
  465.             curr = unpackr (fld);
  466.             curc = unpackc (fld);
  467.         }
  468.         if (nstep > 1)
  469.             f_prompt (freerun);
  470.         }
  471.  
  472.         /* increment time only if op didn't change cirumstances */
  473.         if (!newcir)
  474.         inc_mjd (&now, tminc);
  475.     }
  476.  
  477.     return (0);
  478. }
  479.  
  480. /* draw all the stuff on the screen, using the current menu.
  481.  * if how_much == 0 then just update fields that need it;
  482.  * if how_much == 1 then redraw all fields;
  483.  * if how_much == 2 then erase the screen and redraw EVERYTHING.
  484.  */
  485. redraw_screen (how_much)
  486. int how_much;
  487. {
  488.     if (how_much == 2)
  489.         c_erase();
  490.  
  491.     /* print the single-step message if this is the last loop */
  492.     if (nstep < 1)
  493.         print_updating();
  494.  
  495.     if (how_much == 2) {
  496.         mm_borders();
  497.         mm_labels();
  498.         srch_prstate(1);
  499.         plot_prstate(1);
  500.         alt_labels();
  501.     }
  502.  
  503.     /* if just updating changed fields while plotting unattended then
  504.      * suppress most screen updates except
  505.      * always show nstep to show plot loops to go and
  506.      * always show tminc to show search convergence progress.
  507.      */
  508.     print_nstep(how_much);
  509.     print_tminc(how_much);
  510.     if (how_much == 0 && plot_ison() && nstep > 0)
  511.         f_off();
  512.  
  513.     /* print all the time-related fields */
  514.     mm_now (&now, how_much);
  515.  
  516.     if (optwi)
  517.         mm_twilight (&now, how_much);
  518.  
  519.     /* print solar system body info */
  520.     print_bodies (how_much);
  521.  
  522.     f_on();
  523. }
  524.  
  525. /* clean up and exit
  526.  * TODO: want to ask "are you sure?" ?
  527.  */
  528. void
  529. bye()
  530. {
  531.     c_erase();
  532.     byetty();
  533.     exit (0);
  534. }
  535.  
  536. static
  537. usage(why)
  538. char *why;
  539. {
  540.     /* don't advertise -s (silent) option */
  541.     c_erase();
  542.     f_string (1, 1, why);
  543.     f_string (2, 1, "usage: [-c <configfile>] [field=value] ...\r\n");
  544.     byetty();
  545.     exit (1);
  546. }
  547.  
  548. /* read cfg file, fn, if present.
  549.  * if errors in file, call usage() (which exits).
  550.  * try $HOME/.ephemrc as last resort.
  551.  */
  552. static
  553. read_cfgfile(fn)
  554. char *fn;
  555. {
  556.     char buf[128];
  557.     FILE *fp;
  558.  
  559.     fp = fopen (fn, "r");
  560.     if (!fp) {
  561.         char *home = getenv ("HOME");
  562.         if (home) {
  563.         sprintf (buf, "%s/.ephemrc", home);
  564.         fp = fopen (buf, "r");
  565.         if (!fp)
  566.             return;    /* oh well */
  567.         fn = buf;    /* save fn for error report */
  568.         }
  569.     }
  570.  
  571.     while (fgets (buf, sizeof(buf), fp)) {
  572.         buf[strlen(buf)-1] = '\0';        /* discard trailing \n */
  573.         if (crack_fieldset (buf) < 0) {
  574.         char why[128];
  575.         sprintf (why, "Unknown field spec in %s: %s\n", fn, buf);
  576.         usage (why);
  577.         }
  578.     }
  579.     fclose (fp);
  580. }
  581.  
  582. /* process the field specs from the command line.
  583.  * if trouble call usage() (which exits).
  584.  */
  585. static
  586. read_fieldargs (ac, av)
  587. int ac;        /* number of such specs */
  588. char *av[];    /* array of strings in form <field_name value> */
  589. {
  590.     while (--ac >= 0) {
  591.         char *fs = *av++;
  592.         if (crack_fieldset (fs) < 0) {
  593.         char why[128];
  594.         sprintf (why, "Unknown command line field spec: %s", fs);
  595.         usage (why);
  596.         }
  597.     }
  598. }
  599.  
  600. /* process a field spec in buf, either from config file or argv.
  601.  * return 0 if recognized ok, else -1.
  602.  */
  603. static
  604. crack_fieldset (buf)
  605. char *buf;
  606. {
  607.     if (strncmp ("LAT", buf, 3) == 0)
  608.         (void) chg_fld (buf+4, rcfpack (R_LAT,C_LATV,0));
  609.     else if (strncmp ("LONG", buf, 4) == 0)
  610.         (void) chg_fld (buf+5, rcfpack (R_LONG,C_LONGV,0));
  611.     else if (strncmp ("UT", buf, 2) == 0)
  612.         (void) chg_fld (buf+3, rcfpack (R_UT,C_UTV,0));
  613.     else if (strncmp ("UD", buf, 2) == 0)
  614.         (void) chg_fld (buf+3, rcfpack (R_UD,C_UD,0));
  615.     else if (strncmp ("TZONE", buf, 5) == 0)
  616.         (void) chg_fld (buf+6, rcfpack (R_TZONE,C_TZONEV,0));
  617.     else if (strncmp ("TZNAME", buf, 6) == 0)
  618.         (void) chg_fld (buf+7, rcfpack (R_TZN,C_TZN,0));
  619.     else if (strncmp ("HEIGHT", buf, 6) == 0)
  620.         (void) chg_fld (buf+7, rcfpack (R_HEIGHT,C_HEIGHTV,0));
  621.     else if (strncmp ("NSTEP", buf, 5) == 0)
  622.         (void) chg_fld (buf+6, rcfpack (R_NSTEP,C_NSTEPV,0));
  623.     else if (strncmp ("STPSZ", buf, 5) == 0)
  624.         (void) chg_fld (buf+6, rcfpack (R_STPSZ,C_STPSZV,0));
  625.     else if (strncmp ("TEMP", buf, 4) == 0)
  626.         (void) chg_fld (buf+5, rcfpack (R_TEMP,C_TEMPV,0));
  627.     else if (strncmp ("PRES", buf, 4) == 0)
  628.         (void) chg_fld (buf+5, rcfpack (R_PRES,C_PRESV,0));
  629.     else if (strncmp ("EPOCH", buf, 5) == 0)
  630.         (void) chg_fld (buf+6, rcfpack (R_EPOCH,C_EPOCHV,0));
  631.     else if (strncmp ("JD", buf, 2) == 0)
  632.         (void) chg_fld (buf+3, rcfpack (R_JD,C_JDV,0));
  633.     else if (strncmp ("OBJN", buf, 4) == 0)
  634.         (void) chg_fld (buf+5, rcfpack (R_OBJX,C_OBJ,0));
  635.     else if (strncmp ("OBJRA", buf, 5) == 0)
  636.         (void) chg_fld (buf+6, rcfpack (R_OBJX,C_RA,0));
  637.     else if (strncmp ("OBJDEC", buf, 6) == 0)
  638.         (void) chg_fld (buf+7, rcfpack (R_OBJX,C_DEC,0));
  639.     else if (strncmp ("PROPTS", buf, 6) == 0) {
  640.         char *bp = buf+7;
  641.         while (*bp)
  642.         switch (*bp++) {
  643.         case 'T': optwi = 1; break;
  644.         case 'S': oppl |= (1<<SUN); break;
  645.         case 'M': oppl |= (1<<MOON); break;
  646.         case 'e': oppl |= (1<<MERCURY); break;
  647.         case 'v': oppl |= (1<<VENUS); break;
  648.         case 'm': oppl |= (1<<MARS); break;
  649.         case 'j': oppl |= (1<<JUPITER); break;
  650.         case 's': oppl |= (1<<SATURN); break;
  651.         case 'u': oppl |= (1<<URANUS); break;
  652.         case 'n': oppl |= (1<<NEPTUNE); break;
  653.         case 'p': oppl |= (1<<PLUTO); break;
  654.         }
  655.     } else
  656.         return (-1);
  657.     return (0);
  658. }
  659.  
  660. /* change the field at rcpk according to the optional string input at bp.
  661.  * if bp is != 0 use it, else issue read_line() and use buffer.
  662.  * then sscanf the buffer and update the corresponding (global) variable(s)
  663.  * or do whatever a pick at that field should do.
  664.  * return 1 if we change a field that invalidates any of the times or
  665.  * to update all related fields.
  666.  */
  667. static
  668. chg_fld (bp, rcpk)
  669. char *bp;
  670. int rcpk;
  671. {
  672.     char buf[NC];
  673.     int deghrs = 0, mins = 0, secs = 0;
  674.     int new = 0;
  675.  
  676.     /* switch on just the row/col portion */
  677.     switch (unpackrc(rcpk)) {
  678.     case rcfpack (R_ALTM, C_ALTM, 0):
  679.         if (altmenu_setup() == 0) {
  680.         print_updating();
  681.         alt_nolabels();
  682.         clrall_bodies();
  683.         alt_labels();
  684.         print_bodies(1);
  685.         }
  686.         break;
  687.     case rcfpack (R_JD, C_JDV, 0):
  688.         if (!bp) {
  689.         static char p[] = "Julian Date (or N for Now): ";
  690.         f_prompt (p);
  691.         if (read_line (buf, PW-sizeof(p)) <= 0)
  692.             break;
  693.         bp = buf;
  694.         }
  695.         if (bp[0] == 'n' || bp[0] == 'N')
  696.         time_fromsys (&now);
  697.         else
  698.         mjd = atof(bp) - 2415020L;
  699.         set_t0 (&now);
  700.         new = 1;
  701.         break;
  702.     case rcfpack (R_UD, C_UD, 0):
  703.         if (!bp) {
  704.         static char p[] = "utc date (m/d/y, or N for Now): ";
  705.         f_prompt (p);
  706.         if (read_line (buf, PW-sizeof(p)) <= 0)
  707.             break;
  708.         bp = buf;
  709.         }
  710.         if (bp[0] == 'n' || bp[0] == 'N')
  711.         time_fromsys (&now);
  712.         else {
  713.         double fday, newmjd0;
  714.         int month, day, year;
  715.         mjd_cal (mjd, &month, &fday, &year); /* init with now */
  716.         day = (int)fday;    /* ignore partial days */
  717.         f_sscansex (bp, &month, &day, &year);
  718.         cal_mjd (month, (double)day, year, &newmjd0);
  719.         mjd = newmjd0 + mjd_hr(mjd)/24.0;
  720.         }
  721.         set_t0 (&now);
  722.         new = 1;
  723.         break;
  724.     case rcfpack (R_UT, C_UTV, 0):
  725.         if (!bp) {
  726.         static char p[] = "utc time (h:m:s, or N for Now): ";
  727.         f_prompt (p);
  728.         if (read_line (buf, PW-sizeof(p)) <= 0)
  729.             break;
  730.         bp = buf;
  731.         }
  732.         if (bp[0] == 'n' || bp[0] == 'N')
  733.         time_fromsys (&now);
  734.         else {
  735.         double newutc = (mjd-mjd_day(mjd)) * 24.0;
  736.         f_dec_sexsign (newutc, °hrs, &mins, &secs);
  737.         f_sscansex (bp, °hrs, &mins, &secs);
  738.         sex_dec (deghrs, mins, secs, &newutc);
  739.         mjd = mjd_day(mjd) + newutc/24.0;
  740.         }
  741.         set_t0 (&now);
  742.         new = 1;
  743.         break;
  744.     case rcfpack (R_LD, C_LD, 0):
  745.         if (!bp) {
  746.         static char p[] = "local date (m/d/y, or N for Now): ";
  747.         f_prompt (p);
  748.         if (read_line (buf, PW-sizeof(p)) <= 0)
  749.             break;
  750.         bp = buf;
  751.         }
  752.         if (bp[0] == 'n' || bp[0] == 'N')
  753.         time_fromsys (&now);
  754.         else {
  755.         double fday, newlmjd0;
  756.         int month, day, year;
  757.         mjd_cal (mjd-tz/24.0, &month, &fday, &year); /* now */
  758.         day = (int)fday;    /* ignore partial days */
  759.         f_sscansex (bp, &month, &day, &year);
  760.         cal_mjd (month, (double)day, year, &newlmjd0);
  761.         mjd = newlmjd0 + mjd_hr(mjd)/24.0;
  762.         mjd += newlmjd0 - mjd_day(mjd-tz/24.0);
  763.         }
  764.         set_t0 (&now);
  765.         new = 1;
  766.         break;
  767.     case rcfpack (R_LT, C_LT, 0):
  768.         if (!bp) {
  769.         static char p[] = "local time (h:m:s, or N for Now): ";
  770.         f_prompt (p);
  771.         if (read_line (buf, PW-sizeof(p)) <= 0)
  772.             break;
  773.         bp = buf;
  774.         }
  775.         if (bp[0] == 'n' || bp[0] == 'N')
  776.         time_fromsys (&now);
  777.         else {
  778.         double newlt = (mjd-mjd_day(mjd)) * 24.0 - tz;
  779.         range (&newlt, 24.0);
  780.         f_dec_sexsign (newlt, °hrs, &mins, &secs);
  781.         f_sscansex (bp, °hrs, &mins, &secs);
  782.         sex_dec (deghrs, mins, secs, &newlt);
  783.         mjd = mjd_day(mjd-tz/24.0) + (newlt + tz)/24.0;
  784.         }
  785.         set_t0 (&now);
  786.         new = 1;
  787.         break;
  788.     case rcfpack (R_LST, C_LSTV, 0):
  789.         if (!bp) {
  790.         static char p[] = "local sidereal time (h:m:s, or N for Now): ";
  791.         f_prompt (p);
  792.         if (read_line (buf, PW-sizeof(p)) <= 0)
  793.             break;
  794.         bp = buf;
  795.         }
  796.         if (bp[0] == 'n' || bp[0] == 'N')
  797.         time_fromsys (&now);
  798.         else {
  799.         double lst, utc;
  800.         now_lst (&now, &lst);
  801.         f_dec_sexsign (lst, °hrs, &mins, &secs);
  802.         f_sscansex (bp, °hrs, &mins, &secs);
  803.         sex_dec (deghrs, mins, secs, &lst);
  804.         lst -= radhr(lng); /* convert to gst */
  805.         range (&lst, 24.0);
  806.         gst_utc (mjd_day(mjd), lst, &utc);
  807.         mjd = mjd_day(mjd) + utc/24.0;
  808.         }
  809.         set_t0 (&now);
  810.         new = 1;
  811.         break;
  812.     case rcfpack (R_TZN, C_TZN, 0):
  813.         if (!bp) {
  814.         static char p[] = "timezone abbreviation (3 char max): ";
  815.         f_prompt (p);
  816.         if (read_line (buf, 3) <= 0)
  817.             break;
  818.         bp = buf;
  819.         }
  820.         strcpy (tznm, bp);
  821.         new = 1;
  822.         break;
  823.     case rcfpack (R_TZONE, C_TZONEV, 0):
  824.         if (!bp) {
  825.         static char p[] = "hours behind utc: ";
  826.         f_prompt (p);
  827.         if (read_line (buf, PW-sizeof(p)) <= 0)
  828.             break;
  829.         bp = buf;
  830.         }
  831.         f_dec_sexsign (tz, °hrs, &mins, &secs);
  832.         f_sscansex (bp, °hrs, &mins, &secs);
  833.         sex_dec (deghrs, mins, secs, &tz);
  834.         new = 1;
  835.         break;
  836.     case rcfpack (R_LONG, C_LONGV, 0):
  837.         if (!bp) {
  838.         static char p[] = "longitude (+ west) (d:m:s): ";
  839.         f_prompt (p);
  840.         if (read_line (buf, PW-sizeof(p)) <= 0)
  841.             break;
  842.         bp = buf;
  843.         }
  844.         f_dec_sexsign (-raddeg(lng), °hrs, &mins, &secs);
  845.         f_sscansex (bp, °hrs, &mins, &secs);
  846.         sex_dec (deghrs, mins, secs, &lng);
  847.         lng = degrad (-lng);         /* want - radians west */
  848.         new = 1;
  849.         break;
  850.     case rcfpack (R_LAT, C_LATV, 0):
  851.         if (!bp) {
  852.         static char p[] = "latitude (+ north) (d:m:s): ";
  853.         f_prompt (p);
  854.         if (read_line (buf, PW-sizeof(p)) <= 0)
  855.             break;
  856.         bp = buf;
  857.         }
  858.         f_dec_sexsign (raddeg(lat), °hrs, &mins, &secs);
  859.         f_sscansex (bp, °hrs, &mins, &secs);
  860.         sex_dec (deghrs, mins, secs, &lat);
  861.         lat = degrad (lat);
  862.         new = 1;
  863.         break;
  864.     case rcfpack (R_HEIGHT, C_HEIGHTV, 0):
  865.         if (!bp) {
  866.         static char p[] = "height above sea level (ft): ";
  867.         f_prompt (p);
  868.         if (read_line (buf, PW-sizeof(p)) <= 0)
  869.             break;
  870.         bp = buf;
  871.         }
  872.         sscanf (bp, "%F", &height);
  873.         height /= 2.093e7; /* convert ft to earth radii above sea level */
  874.         new = 1;
  875.         break;
  876.     case rcfpack (R_NSTEP, C_NSTEPV, 0):
  877.         if (!bp) {
  878.         static char p[] = "number of steps to run: ";
  879.         f_prompt (p);
  880.         if (read_line (buf, 8) <= 0)
  881.             break;
  882.         bp = buf;
  883.         }
  884.         sscanf (bp, "%d", &nstep);
  885.         print_nstep (0);
  886.         break;
  887.     case rcfpack (R_TEMP, C_TEMPV, 0):
  888.         if (!bp) {
  889.         static char p[] = "temperature (deg.F): ";
  890.         f_prompt (p);
  891.         if (read_line (buf, PW-sizeof(p)) <= 0)
  892.             break;
  893.         bp = buf;
  894.         }
  895.         sscanf (bp, "%F", &temp);
  896.         temp = 5./9.*(temp - 32.0);    /* want degs C */
  897.         new = 1;
  898.         break;
  899.     case rcfpack (R_PRES, C_PRESV, 0):
  900.         if (!bp) {
  901.         static char p[] =
  902.             "atmos pressure (in. Hg; 0 for no refraction correction): ";
  903.         f_prompt (p);
  904.         if (read_line (buf, PW-sizeof(p)) <= 0)
  905.             break;
  906.         bp = buf;
  907.         }
  908.         sscanf (bp, "%F", &pressure);
  909.         pressure *= 33.86;        /* want mBar */
  910.         new = 1;
  911.         break;
  912.     case rcfpack (R_EPOCH, C_EPOCHV, 0):
  913.         if (!bp) {
  914.         static char p[] = "epoch (year, or E for Equinox of Date): ";
  915.         f_prompt (p);
  916.         if (read_line (buf, PW-strlen(p)) <= 0)
  917.             break;
  918.         bp = buf;
  919.         }
  920.         if (bp[0] == 'e' || bp[0] == 'E')
  921.         epoch = EOD;
  922.         else {
  923.         double e;
  924.         sscanf (bp, "%F", &e);
  925.         cal_mjd (1, 1.0, (int)e, &epoch);    /* convert to mjd */
  926.         epoch += (e - (int)e)*365.24;
  927.         }
  928.         new = 1;
  929.         break;
  930.     case rcfpack (R_STPSZ, C_STPSZV, 0):
  931.         if (!bp) {
  932.         static char p[] =
  933.             "step size increment (h:m:s, or <x>D, or RTC): ";
  934.         f_prompt (p);
  935.         if (read_line (buf, PW-sizeof(p)) <= 0)
  936.             break;
  937.         bp = buf;
  938.         }
  939.         if (bp[0] == 'r' || bp[0] == 'R')
  940.         tminc = RTC;
  941.         else {
  942.         int last = strlen (bp) - 1;
  943.         if (bp[last] == 'd' || bp[last] == 'D') {
  944.             /* ends in d so treat as a number of days */
  945.             double x;
  946.             sscanf (bp, "%G", &x);
  947.             tminc = x * 24.0;
  948.         } else {
  949.             if (tminc == RTC)
  950.             deghrs = mins = secs = 0;
  951.             else
  952.             f_dec_sexsign (tminc, °hrs, &mins, &secs);
  953.             f_sscansex (bp, °hrs, &mins, &secs);
  954.             sex_dec (deghrs, mins, secs, &tminc);
  955.         }
  956.         }
  957.         print_tminc(0);
  958.         set_t0 (&now);
  959.         break;
  960.     case rcfpack (R_PLOT, C_PLOT, 0):
  961.         plot_setup();
  962.         if (plot_ison())
  963.         new = 1;
  964.         break;
  965.     case rcfpack (R_WATCH, C_WATCH, 0):
  966.         watch (&now, tminc, oppl);
  967.         break;
  968.     case rcfpack (R_DAWN, C_DAWN, 0):
  969.     case rcfpack (R_DUSK, C_DUSK, 0):
  970.     case rcfpack (R_LON, C_LON, 0):
  971.         if (optwi ^= 1) {
  972.         print_updating();
  973.         mm_twilight (&now, 1);
  974.         } else {
  975.         f_blanks (R_DAWN, C_DAWNV, 5);
  976.         f_blanks (R_DUSK, C_DUSKV, 5);
  977.         f_blanks (R_LON, C_LONV, 5);
  978.         }
  979.         break;
  980.     case rcfpack (R_SRCH, C_SRCH, 0):
  981.         srch_setup();
  982.         if (srch_ison())
  983.         new = 1;
  984.         break;
  985.     case rcfpack (R_SUN, C_OBJ, 0):
  986.         if ((oppl ^= (1<<SUN)) & (1<<SUN)) {
  987.         print_updating();
  988.         alt_body (SUN, 1, &now);
  989.         } else
  990.         alt_nobody (SUN);
  991.         break;
  992.     case rcfpack (R_MOON, C_OBJ, 0):
  993.         if ((oppl ^= (1<<MOON)) & (1<<MOON)) {
  994.         print_updating();
  995.         alt_body (MOON, 1, &now);
  996.         } else
  997.         alt_nobody (MOON);
  998.         break;
  999.     case rcfpack (R_MERCURY, C_OBJ, 0):
  1000.         if ((oppl ^= (1<<MERCURY)) & (1<<MERCURY)) {
  1001.         print_updating();
  1002.         alt_body (MERCURY, 1, &now);
  1003.         } else
  1004.         alt_nobody (MERCURY);
  1005.         break;
  1006.     case rcfpack (R_VENUS, C_OBJ, 0):
  1007.         if ((oppl ^= (1<<VENUS)) & (1<<VENUS)) {
  1008.         print_updating();
  1009.         alt_body (VENUS, 1, &now);
  1010.         } else
  1011.         alt_nobody (VENUS);
  1012.         break;
  1013.     case rcfpack (R_MARS, C_OBJ, 0):
  1014.         if ((oppl ^= (1<<MARS)) & (1<<MARS)) {
  1015.         print_updating();
  1016.         alt_body (MARS, 1, &now);
  1017.         } else
  1018.         alt_nobody (MARS);
  1019.         break;
  1020.     case rcfpack (R_JUPITER, C_OBJ, 0):
  1021.         if ((oppl ^= (1<<JUPITER)) & (1<<JUPITER)) {
  1022.         print_updating();
  1023.         alt_body (JUPITER, 1, &now);
  1024.         } else
  1025.         alt_nobody (JUPITER);
  1026.         break;
  1027.     case rcfpack (R_SATURN, C_OBJ, 0):
  1028.         if ((oppl ^= (1<<SATURN)) & (1<<SATURN)) {
  1029.         print_updating();
  1030.         alt_body (SATURN, 1, &now);
  1031.         } else
  1032.         alt_nobody (SATURN);
  1033.         break;
  1034.     case rcfpack (R_URANUS, C_OBJ, 0):
  1035.         if ((oppl ^= (1<<URANUS)) & (1<<URANUS)) {
  1036.         print_updating();
  1037.         alt_body (URANUS, 1, &now);
  1038.         } else
  1039.         alt_nobody (URANUS);
  1040.         break;
  1041.     case rcfpack (R_NEPTUNE, C_OBJ, 0):
  1042.         if ((oppl ^= (1<<NEPTUNE)) & (1<<NEPTUNE)) {
  1043.         print_updating();
  1044.         alt_body (NEPTUNE, 1, &now);
  1045.         } else
  1046.         alt_nobody (NEPTUNE);
  1047.         break;
  1048.     case rcfpack (R_PLUTO, C_OBJ, 0):
  1049.         if ((oppl ^= (1<<PLUTO)) & (1<<PLUTO)) {
  1050.         print_updating();
  1051.         alt_body (PLUTO, 1, &now);
  1052.         } else
  1053.         alt_nobody (PLUTO);
  1054.         break;
  1055.     case rcfpack (R_OBJX, C_OBJ, 0):
  1056.         if ((oppl ^= (1<<OBJX)) & (1<<OBJX)) {
  1057.         if (!bp) {
  1058.             static char p[]= "object name (or RETURN for last again): ";
  1059.             f_prompt (p);
  1060.             if (read_line (buf, MAXOBJXNM) < 0) {
  1061.             oppl ^= (1<<OBJX);    /* turn back off */
  1062.             break;
  1063.             }
  1064.             bp = buf;
  1065.         }
  1066.         if (bp[0] != '\0') {
  1067.             /* initialize epoch to EOD to avoid initial precession. */
  1068.             double e = mjd, tmp = 0.0;
  1069.             objx_set (&tmp, &tmp, &e, bp);
  1070.         }
  1071.         objx_on();
  1072.         alt_body (OBJX, 1, &now);
  1073.         } else {
  1074.         objx_off();
  1075.         alt_nobody (OBJX);
  1076.         }
  1077.         break;
  1078.     case rcfpack (R_OBJX, C_RA, 0):
  1079.         if (oppl & (1<<OBJX)) {
  1080.         double r, e;
  1081.         if (!bp) {
  1082.             static char p[] = "ra (current epoch, h:m:s): ";
  1083.             f_prompt (p);
  1084.             if (read_line (buf, PW-sizeof(p)) <= 0)
  1085.             break;
  1086.             bp = buf;
  1087.         }
  1088.         objx_get (&r, (double *)0, (double *)0, (char *)0);
  1089.         f_dec_sexsign (radhr(r), °hrs, &mins, &secs);
  1090.         f_sscansex (bp, °hrs, &mins, &secs);
  1091.         sex_dec (deghrs, mins, secs, &r);
  1092.         r = hrrad(r);
  1093.         e = (epoch == EOD) ? mjd : epoch;
  1094.         objx_set (&r, (double *)0, &e, (char *)0);
  1095.         alt_body (OBJX, 1, &now);
  1096.         }
  1097.         break;
  1098.     case rcfpack (R_OBJX, C_DEC, 0):
  1099.         if (oppl & (1<<OBJX)) {
  1100.         double d, e;
  1101.         if (!bp) {
  1102.             static char p[] = "dec (current epoch, d:m:s): ";
  1103.             f_prompt (p);
  1104.             if (read_line (buf, PW-sizeof(p)) <= 0)
  1105.             break;
  1106.             bp = buf;
  1107.         }
  1108.         objx_get ((double *)0, &d, (double *)0, (char *)0);
  1109.         f_dec_sexsign (raddeg(d), °hrs, &mins, &secs);
  1110.         f_sscansex (bp, °hrs, &mins, &secs);
  1111.         sex_dec (deghrs, mins, secs, &d);
  1112.         d = degrad(d);
  1113.         e = (epoch == EOD) ? mjd : epoch;
  1114.         objx_set ((double *)0, &d, &e, (char *)0);
  1115.         alt_body (OBJX, 1, &now);
  1116.         }
  1117.         break;
  1118.     }
  1119.  
  1120.     return (new);
  1121. }
  1122.  
  1123. static
  1124. print_tminc(force)
  1125. int force;
  1126. {
  1127.     static double last;
  1128.  
  1129.     if (force || tminc != last) {
  1130.         if (tminc == RTC)
  1131.         f_string (R_STPSZ, C_STPSZV, " RT CLOCK");
  1132.         else if (fabs(tminc) >= 24.0)
  1133.         f_double (R_STPSZ, C_STPSZV, "%6.4g dy", tminc/24.0);
  1134.         else
  1135.         f_signtime (R_STPSZ, C_STPSZV, tminc);
  1136.         last = tminc;
  1137.     }
  1138. }
  1139.  
  1140. static
  1141. print_bodies (force)
  1142. int force;
  1143. {
  1144.     int p;
  1145.  
  1146.     for (p = nxtbody(-1); p != -1; p = nxtbody(p))
  1147.         if (oppl & (1<<p))
  1148.         alt_body (p, force, &now);
  1149. }
  1150.  
  1151. static
  1152. clrall_bodies ()
  1153. {
  1154.     int p;
  1155.  
  1156.     for (p = nxtbody(-1); p != -1; p = nxtbody(p))
  1157.         if (oppl & (1<<p))
  1158.         alt_nobody (p);
  1159. }
  1160.  
  1161. print_updating()
  1162. {
  1163.     f_prompt ("Updating...");
  1164. }
  1165.  
  1166. static
  1167. print_nstep(force)
  1168. int force;
  1169. {
  1170.     static int last;
  1171.  
  1172.     if (force || nstep != last) {
  1173.         char buf[16];
  1174.         sprintf (buf, "%8d", nstep);
  1175.         f_string (R_NSTEP, C_NSTEPV, buf);
  1176.         last = nstep;
  1177.     }
  1178. }
  1179. xXx
  1180. echo x mainmenu.c
  1181. cat > mainmenu.c << 'xXx'
  1182. /* printing routines for the main (upper) screen.
  1183.  */
  1184.  
  1185. #include <stdio.h>
  1186. #include <math.h>
  1187. #include "astro.h"
  1188. #include "circum.h"
  1189. #include "screen.h"
  1190.  
  1191. mm_borders()
  1192. {
  1193.     char line[NC+1], *lp;
  1194.     register i;
  1195.  
  1196.     lp = line;
  1197.     for (i = 0; i < NC; i++)
  1198.         *lp++ = '-';
  1199.     *lp = '\0';
  1200.     f_string (R_PLANTAB-1, 1, line);
  1201.     for (i = R_TOP; i < R_PLANTAB-1; i++)
  1202.         f_char (i, COL2-2, '|');
  1203.     for (i = R_TOP; i < R_PLANTAB-1; i++)
  1204.         f_char (i, COL3-2, '|');
  1205.     for (i = R_LST; i < R_PLANTAB-1; i++)
  1206.         f_char (i, COL4-2, '|');
  1207. }
  1208.  
  1209. mm_labels()
  1210. {
  1211.     f_string (R_TZN,    C_TZN,        "LT");
  1212.     f_string (R_UT,        C_UT,        "UTC");
  1213.     f_string (R_JD,        C_JD,        "JulianDate");
  1214.     f_string (R_WATCH,    C_WATCH,    "Watch");
  1215.     f_string (R_SRCH,    C_SRCH,        "Search");
  1216.     f_string (R_PLOT,    C_PLOT,        "Plot");
  1217.     f_string (R_ALTM,    C_ALTM,        "Menu");
  1218.  
  1219.     f_string (R_LST,    C_LST,        "LST");
  1220.     f_string (R_DAWN,    C_DAWN,        "Dawn");
  1221.     f_string (R_DUSK,    C_DUSK,        "Dusk");
  1222.     f_string (R_LON,    C_LON,        "NiteLn");
  1223.     f_string (R_NSTEP,    C_NSTEP,    "NStep");
  1224.     f_string (R_STPSZ,    C_STPSZ,    "StpSz");
  1225.  
  1226.     f_string (R_LAT,    C_LAT,        "Lat");
  1227.     f_string (R_LONG,    C_LONG,        "Long");
  1228.     f_string (R_HEIGHT,    C_HEIGHT,    "Elev");
  1229.     f_string (R_TEMP,    C_TEMP,        "Temp");
  1230.     f_string (R_PRES,    C_PRES,        "AtmPr");
  1231.     f_string (R_TZONE,    C_TZONE,    "TZ");
  1232.     f_string (R_EPOCH,    C_EPOCH,    "Epoch");
  1233.  
  1234.     f_string (R_PLANTAB,    C_OBJ,    "Ob");
  1235.     f_string (R_SUN,    C_OBJ,    "Su");
  1236.     f_string (R_MOON,    C_OBJ,    "Mo");
  1237.     f_string (R_MERCURY,    C_OBJ,    "Me");
  1238.     f_string (R_VENUS,    C_OBJ,    "Ve");
  1239.     f_string (R_MARS,    C_OBJ,    "Ma");
  1240.     f_string (R_JUPITER,    C_OBJ,    "Ju");
  1241.     f_string (R_SATURN,    C_OBJ,    "Sa");
  1242.     f_string (R_URANUS,    C_OBJ,    "Ur");
  1243.     f_string (R_NEPTUNE,    C_OBJ,    "Ne");
  1244.     f_string (R_PLUTO,    C_OBJ,    "Pl");
  1245. }
  1246.  
  1247. /* print all the time/date/where related stuff: the Now structure.
  1248.  * print in a nice order, based on the field locations, as much as possible.
  1249.  */
  1250. mm_now (np, all)
  1251. Now *np;
  1252. int all;
  1253. {
  1254.     char buf[32];
  1255.     double lmjd = mjd - tz/24.0;
  1256.     double jd = mjd + 2415020L;
  1257.     double tmp;
  1258.  
  1259.     sprintf (buf, "%-3.3s", tznm);
  1260.     f_string (R_TZN, C_TZN, buf);
  1261.     f_time (R_LT, C_LT, mjd_hr(lmjd));
  1262.     f_date (R_LD, C_LD, mjd_day(lmjd));
  1263.  
  1264.     f_time (R_UT, C_UTV, mjd_hr(mjd));
  1265.     f_date (R_UD, C_UD, mjd_day(mjd));
  1266.  
  1267.     sprintf (buf, "%14.5f", jd);
  1268.     (void) flog_log (R_JD, C_JDV, jd);
  1269.     f_string (R_JD, C_JDV, buf);
  1270.  
  1271.     now_lst (np, &tmp);
  1272.     f_time (R_LST, C_LSTV, tmp);
  1273.  
  1274.     if (all) {
  1275.         f_gangle (R_LAT, C_LATV, lat);
  1276.         f_gangle (R_LONG, C_LONGV, -lng);    /* + west */
  1277.  
  1278.         tmp = height * 2.093e7;    /* want to see ft, not earth radii */
  1279.         sprintf (buf, "%5g ft", tmp);
  1280.         (void) flog_log (R_HEIGHT, C_HEIGHTV, tmp);
  1281.         f_string (R_HEIGHT, C_HEIGHTV, buf);
  1282.  
  1283.         tmp = 9./5.*temp + 32.0;     /* want to see degrees F, not C */
  1284.         (void) flog_log (R_TEMP, C_TEMPV, tmp);
  1285.         sprintf (buf, "%6g F", tmp);
  1286.         f_string (R_TEMP, C_TEMPV, buf);
  1287.  
  1288.         tmp = pressure / 33.86;    /* want to see in. Hg, not mBar */
  1289.         (void) flog_log (R_PRES, C_PRESV, tmp);
  1290.         sprintf (buf, "%5.2f in", tmp);
  1291.         f_string (R_PRES, C_PRESV, buf);
  1292.  
  1293.         f_signtime (R_TZONE, C_TZONEV, tz);
  1294.  
  1295.         /* TODO: allow epoch to be plotted (?) */
  1296.         if (epoch == EOD)
  1297.         f_string (R_EPOCH, C_EPOCHV, "(OfDate)");
  1298.         else {
  1299.         mjd_year (epoch, &tmp);
  1300.         f_double (R_EPOCH, C_EPOCHV, "%8.1f", tmp);
  1301.         }
  1302.     }
  1303.  
  1304.     /* print the calendar for local day, if new month/year.  */
  1305.     mm_calendar (np, all > 1);
  1306. }
  1307.  
  1308. /* display dawn/dusk/length-of-night times.
  1309.  */
  1310. mm_twilight (np, force)
  1311. Now *np;
  1312. int force;
  1313. {
  1314.     double dusk, dawn;
  1315.     double tmp;
  1316.     int status;
  1317.  
  1318.     if (!twilight_cir (np, &dawn, &dusk, &status) && !force)
  1319.         return;
  1320.  
  1321.     switch (status) {
  1322.     case -1:    /* sun never sets today */
  1323.     case  1:    /* sun never rises today */
  1324.     case  2:    /* can not find where sun is! */
  1325.         f_blanks (R_DAWN, C_DAWNV, 5);
  1326.         f_blanks (R_DUSK, C_DUSKV, 5);
  1327.         f_blanks (R_LON, C_LONV, 5);
  1328.         return;
  1329.     default:    /* all ok */
  1330.         ;
  1331.     }
  1332.  
  1333.     f_mtime (R_DAWN, C_DAWNV, dawn);
  1334.     f_mtime (R_DUSK, C_DUSKV, dusk);
  1335.     tmp = dawn - dusk; range (&tmp, 24.0);
  1336.     f_mtime (R_LON, C_LONV, tmp);
  1337. }
  1338.  
  1339. mm_newcir (y)
  1340. int y;
  1341. {
  1342.     static char ncmsg[] = "NEW CIRCUMSTANCES";
  1343.     static char nomsg[] = "                 ";
  1344.     static int last_y = -1;
  1345.  
  1346.     if (y != last_y) {
  1347.         f_string (R_NEWCIR, C_NEWCIR, y ? ncmsg : nomsg);
  1348.         last_y = y;
  1349.     }
  1350. }
  1351.  
  1352. static
  1353. mm_calendar (np, force)
  1354. Now *np;
  1355. int force;
  1356. {
  1357.     static char *mnames[] = {
  1358.         "January", "February", "March", "April", "May", "June",
  1359.         "July", "August", "September", "October", "November", "December"
  1360.     };
  1361.     static int last_m, last_y;
  1362.     static double last_tz;
  1363.     char str[64];
  1364.     int m, y;
  1365.     double d;
  1366.     int f, nd;
  1367.     int r;
  1368.     double jd0;
  1369.  
  1370.     /* get local m/d/y. do nothing if still same month and not forced. */
  1371.     mjd_cal (mjd_day(mjd-tz/24.0), &m, &d, &y);
  1372.     if (m == last_m && y == last_y && tz == last_tz && !force)
  1373.         return;
  1374.     last_m = m;
  1375.     last_y = y;
  1376.     last_tz = tz;
  1377.  
  1378.     /* find day of week of first day of month */
  1379.     cal_mjd (m, 1.0, y, &jd0);
  1380.     mjd_dow (jd0, &f);
  1381.     if (f < 0) {
  1382.         /* can't figure it out - too hard before Gregorian */
  1383.         int i;
  1384.         for (i = 8; --i >= 0; )
  1385.         f_string (R_CAL+i, C_CAL, "                    ");
  1386.         return;
  1387.     }
  1388.  
  1389.     /* print header */
  1390.     f_blanks (R_CAL, C_CAL, 20);
  1391.     sprintf (str, "%s %4d", mnames[m-1], y);
  1392.     f_string (R_CAL, C_CAL + (20 - (strlen(mnames[m-1]) + 5))/2, str);
  1393.     f_string (R_CAL+1, C_CAL, "Su Mo Tu We Th Fr Sa");
  1394.  
  1395.     /* find number of days in this month */
  1396.     mjd_dpm (jd0, &nd);
  1397.  
  1398.     /* print the calendar */
  1399.     for (r = 0; r < 6; r++) {
  1400.         char row[7*3+1], *rp = row;
  1401.         int c;
  1402.         for (c = 0; c < 7; c++) {
  1403.         int i = r*7+c;
  1404.         if (i < f || i >= f + nd)
  1405.             sprintf (rp, "   ");
  1406.         else
  1407.             sprintf (rp, "%2d ", i-f+1);
  1408.         rp += 3;
  1409.         }
  1410.         row[sizeof(row)-2] = '\0';    /* don't print last blank; causes wrap*/
  1411.         f_string (R_CAL+2+r, C_CAL, row);
  1412.     }
  1413.  
  1414.     /* over print the new and full moons for this month.
  1415.      * TODO: don't really know which dates to use here (see moonnf())
  1416.      *   so try several to be fairly safe. have to go back to 4/29/1988
  1417.      *   to find the full moon on 5/1 for example.
  1418.      */
  1419.     mm_nfmoon (jd0-3, tz, m, f);
  1420.     mm_nfmoon (jd0+15, tz, m, f);
  1421. }
  1422.  
  1423. static
  1424. mm_nfmoon (jd, tzone, m, f)
  1425. double jd, tzone;
  1426. int m, f;
  1427. {
  1428.     static char nm[] = "NM", fm[] = "FM";
  1429.     double dm;
  1430.     int mm, ym;
  1431.     double jdn, jdf;
  1432.     int di;
  1433.  
  1434.     moonnf (jd, &jdn, &jdf);
  1435.     mjd_cal (jdn-tzone/24.0, &mm, &dm, &ym);
  1436.     if (m == mm) {
  1437.         di = dm + f - 1;
  1438.         f_string (R_CAL+2+di/7, C_CAL+3*(di%7), nm);
  1439.     }
  1440.     mjd_cal (jdf-tzone/24.0, &mm, &dm, &ym);
  1441.     if (m == mm) {
  1442.         di = dm + f - 1;
  1443.         f_string (R_CAL+2+di/7, C_CAL+3*(di%7), fm);
  1444.     }
  1445. }
  1446. xXx
  1447. echo x moon.c
  1448. cat > moon.c << 'xXx'
  1449. #include <stdio.h>
  1450. #include <math.h>
  1451. #include "astro.h"
  1452.  
  1453. /* given the mjd, find the geocentric ecliptic longitude, lam, and latitude,
  1454.  * bet, and horizontal parallax, hp for the moon.
  1455.  * N.B. series for long and lat are good to about 10 and 3 arcseconds. however,
  1456.  *   math errors cause up to 100 and 30 arcseconds error, even if use double.
  1457.  *   why?? suspect highly sensitive nature of difference used to get m1..6.
  1458.  * N.B. still need to correct for nutation. then for topocentric location
  1459.  *   further correct for parallax and refraction.
  1460.  */
  1461. moon (mjd, lam, bet, hp)
  1462. double mjd;
  1463. double *lam, *bet, *hp;
  1464. {
  1465.     double t, t2;
  1466.     double ld;
  1467.     double ms;
  1468.     double md;
  1469.     double de;
  1470.     double f;
  1471.     double n;
  1472.     double a, sa, sn, b, sb, c, sc, e, e2, l, g, w1, w2;
  1473.     double m1, m2, m3, m4, m5, m6;
  1474.  
  1475.     t = mjd/36525.;
  1476.     t2 = t*t;
  1477.  
  1478.     m1 = mjd/27.32158213;
  1479.     m1 = 360.0*(m1-(int)m1);
  1480.     m2 = mjd/365.2596407;
  1481.     m2 = 360.0*(m2-(int)m2);
  1482.     m3 = mjd/27.55455094;
  1483.     m3 = 360.0*(m3-(int)m3);
  1484.     m4 = mjd/29.53058868;
  1485.     m4 = 360.0*(m4-(int)m4);
  1486.     m5 = mjd/27.21222039;
  1487.     m5 = 360.0*(m5-(int)m5);
  1488.     m6 = mjd/6798.363307;
  1489.     m6 = 360.0*(m6-(int)m6);
  1490.  
  1491.     ld = 270.434164+m1-(.001133-.0000019*t)*t2;
  1492.     ms = 358.475833+m2-(.00015+.0000033*t)*t2;
  1493.     md = 296.104608+m3+(.009192+.0000144*t)*t2;
  1494.     de = 350.737486+m4-(.001436-.0000019*t)*t2;
  1495.     f = 11.250889+m5-(.003211+.0000003*t)*t2;
  1496.     n = 259.183275-m6+(.002078+.000022*t)*t2;
  1497.  
  1498.     a = degrad(51.2+20.2*t);
  1499.     sa = sin(a);
  1500.     sn = sin(degrad(n));
  1501.     b = 346.56+(132.87-.0091731*t)*t;
  1502.     sb = .003964*sin(degrad(b));
  1503.     c = degrad(n+275.05-2.3*t);
  1504.     sc = sin(c);
  1505.     ld = ld+.000233*sa+sb+.001964*sn;
  1506.     ms = ms-.001778*sa;
  1507.     md = md+.000817*sa+sb+.002541*sn;
  1508.     f = f+sb-.024691*sn-.004328*sc;
  1509.     de = de+.002011*sa+sb+.001964*sn;
  1510.     e = 1-(.002495+7.52e-06*t)*t;
  1511.     e2 = e*e;
  1512.  
  1513.     ld = degrad(ld);
  1514.     ms = degrad(ms);
  1515.     n = degrad(n);
  1516.     de = degrad(de);
  1517.     f = degrad(f);
  1518.     md = degrad(md);
  1519.  
  1520.     l = 6.28875*sin(md)+1.27402*sin(2*de-md)+.658309*sin(2*de)+
  1521.         .213616*sin(2*md)-e*.185596*sin(ms)-.114336*sin(2*f)+
  1522.         .058793*sin(2*(de-md))+.057212*e*sin(2*de-ms-md)+
  1523.         .05332*sin(2*de+md)+.045874*e*sin(2*de-ms)+.041024*e*sin(md-ms);
  1524.     l = l-.034718*sin(de)-e*.030465*sin(ms+md)+.015326*sin(2*(de-f))-
  1525.         .012528*sin(2*f+md)-.01098*sin(2*f-md)+.010674*sin(4*de-md)+
  1526.         .010034*sin(3*md)+.008548*sin(4*de-2*md)-e*.00791*sin(ms-md+2*de)-
  1527.         e*.006783*sin(2*de+ms);
  1528.     l = l+.005162*sin(md-de)+e*.005*sin(ms+de)+.003862*sin(4*de)+
  1529.         e*.004049*sin(md-ms+2*de)+.003996*sin(2*(md+de))+
  1530.         .003665*sin(2*de-3*md)+e*.002695*sin(2*md-ms)+
  1531.         .002602*sin(md-2*(f+de))+e*.002396*sin(2*(de-md)-ms)-
  1532.         .002349*sin(md+de);
  1533.     l = l+e2*.002249*sin(2*(de-ms))-e*.002125*sin(2*md+ms)-
  1534.         e2*.002079*sin(2*ms)+e2*.002059*sin(2*(de-ms)-md)-
  1535.         .001773*sin(md+2*(de-f))-.001595*sin(2*(f+de))+
  1536.         e*.00122*sin(4*de-ms-md)-.00111*sin(2*(md+f))+.000892*sin(md-3*de);
  1537.     l = l-e*.000811*sin(ms+md+2*de)+e*.000761*sin(4*de-ms-2*md)+
  1538.          e2*.000704*sin(md-2*(ms+de))+e*.000693*sin(ms-2*(md-de))+
  1539.          e*.000598*sin(2*(de-f)-ms)+.00055*sin(md+4*de)+.000538*sin(4*md)+
  1540.          e*.000521*sin(4*de-ms)+.000486*sin(2*md-de);
  1541.     l = l+e2*.000717*sin(md-2*ms);
  1542.     *lam = ld+degrad(l);
  1543.     range (lam, 2*PI);
  1544.  
  1545.     g = 5.12819*sin(f)+.280606*sin(md+f)+.277693*sin(md-f)+
  1546.         .173238*sin(2*de-f)+.055413*sin(2*de+f-md)+.046272*sin(2*de-f-md)+
  1547.         .032573*sin(2*de+f)+.017198*sin(2*md+f)+.009267*sin(2*de+md-f)+
  1548.         .008823*sin(2*md-f)+e*.008247*sin(2*de-ms-f);
  1549.     g = g+.004323*sin(2*(de-md)-f)+.0042*sin(2*de+f+md)+
  1550.         e*.003372*sin(f-ms-2*de)+e*.002472*sin(2*de+f-ms-md)+
  1551.         e*.002222*sin(2*de+f-ms)+e*.002072*sin(2*de-f-ms-md)+
  1552.         e*.001877*sin(f-ms+md)+.001828*sin(4*de-f-md)-e*.001803*sin(f+ms)-
  1553.         .00175*sin(3*f);
  1554.     g = g+e*.00157*sin(md-ms-f)-.001487*sin(f+de)-e*.001481*sin(f+ms+md)+
  1555.          e*.001417*sin(f-ms-md)+e*.00135*sin(f-ms)+.00133*sin(f-de)+
  1556.          .001106*sin(f+3*md)+.00102*sin(4*de-f)+.000833*sin(f+4*de-md)+
  1557.          .000781*sin(md-3*f)+.00067*sin(f+4*de-2*md);
  1558.     g = g+.000606*sin(2*de-3*f)+.000597*sin(2*(de+md)-f)+
  1559.         e*.000492*sin(2*de+md-ms-f)+.00045*sin(2*(md-de)-f)+
  1560.         .000439*sin(3*md-f)+.000423*sin(f+2*(de+md))+
  1561.         .000422*sin(2*de-f-3*md)-e*.000367*sin(ms+f+2*de-md)-
  1562.         e*.000353*sin(ms+f+2*de)+.000331*sin(f+4*de);
  1563.     g = g+e*.000317*sin(2*de+f-ms+md)+e2*.000306*sin(2*(de-ms)-f)-
  1564.         .000283*sin(md+3*f);
  1565.     w1 = .0004664*cos(n);
  1566.     w2 = .0000754*cos(c);
  1567.     *bet = degrad(g)*(1-w1-w2);
  1568.  
  1569.     *hp = .950724+.051818*cos(md)+.009531*cos(2*de-md)+.007843*cos(2*de)+
  1570.           .002824*cos(2*md)+.000857*cos(2*de+md)+e*.000533*cos(2*de-ms)+
  1571.           e*.000401*cos(2*de-md-ms)+e*.00032*cos(md-ms)-.000271*cos(de)-
  1572.           e*.000264*cos(ms+md)-.000198*cos(2*f-md);
  1573.     *hp = *hp+.000173*cos(3*md)+.000167*cos(4*de-md)-e*.000111*cos(ms)+
  1574.          .000103*cos(4*de-2*md)-.000084*cos(2*md-2*de)-
  1575.          e*.000083*cos(2*de+ms)+.000079*cos(2*de+2*md)+.000072*cos(4*de)+
  1576.          e*.000064*cos(2*de-ms+md)-e*.000063*cos(2*de+ms-md)+
  1577.          e*.000041*cos(ms+de);
  1578.     *hp = *hp+e*.000035*cos(2*md-ms)-.000033*cos(3*md-2*de)-
  1579.          .00003*cos(md+de)-.000029*cos(2*(f-de))-e*.000029*cos(2*md+ms)+
  1580.          e2*.000026*cos(2*(de-ms))-.000023*cos(2*(f-de)+md)+
  1581.          e*.000019*cos(4*de-ms-md);
  1582.     *hp = degrad(*hp);
  1583. }
  1584. xXx
  1585. echo x moonnf.c
  1586. cat > moonnf.c << 'xXx'
  1587. #include <stdio.h>
  1588. #include <math.h>
  1589. #include "astro.h"
  1590.  
  1591. #define    unw(w,z)    ((w)-floor((w)/(z))*(z))
  1592.  
  1593. /* given a modified Julian date, mjd, return the mjd of the new
  1594.  * and full moons about then, mjdn and mjdf.
  1595.  * TODO: exactly which ones does it find? eg:
  1596.  *   5/28/1988 yields 5/15 and 5/31
  1597.  *   5/29             6/14     6/29
  1598.  */
  1599. moonnf (mjd, mjdn, mjdf)
  1600. double mjd;
  1601. double *mjdn, *mjdf;
  1602. {
  1603.     int mo, yr;
  1604.     double dy;
  1605.     double mjd0;
  1606.     double k, tn, tf, t;
  1607.  
  1608.     mjd_cal (mjd, &mo, &dy, &yr);
  1609.     cal_mjd (1, 0., yr, &mjd0);
  1610.     k = (yr-1900+((mjd-mjd0)/365))*12.3685;
  1611.     k = floor(k+0.5);
  1612.     tn = k/1236.85;
  1613.     tf = (k+0.5)/1236.85;
  1614.     t = tn;
  1615.     m (t, k, mjdn);
  1616.     t = tf;
  1617.     k += 0.5;
  1618.     m (t, k, mjdf);
  1619. }
  1620.  
  1621. static
  1622. m (t, k, mjd)
  1623. double t, k;
  1624. double *mjd;
  1625. {
  1626.     double t2, a, a1, b, b1, c, ms, mm, f, ddjd;
  1627.  
  1628.     t2 = t*t;
  1629.     a = 29.53*k;
  1630.     c = degrad(166.56+(132.87-9.173e-3*t)*t);
  1631.     b = 5.8868e-4*k+(1.178e-4-1.55e-7*t)*t2+3.3e-4*sin(c)+7.5933E-1;
  1632.     ms = 359.2242+360*unw(k/1.236886e1,1)-(3.33e-5+3.47e-6*t)*t2;
  1633.     mm = 306.0253+360*unw(k/9.330851e-1,1)+(1.07306e-2+1.236e-5*t)*t2;
  1634.     f = 21.2964+360*unw(k/9.214926e-1,1)-(1.6528e-3+2.39e-6*t)*t2;
  1635.     ms = unw(ms,360);
  1636.     mm = unw(mm,360);
  1637.     f = unw(f,360);
  1638.     ms = degrad(ms);
  1639.     mm = degrad(mm);
  1640.     f = degrad(f);
  1641.     ddjd = (1.734e-1-3.93e-4*t)*sin(ms)+2.1e-3*sin(2*ms)
  1642.         -4.068e-1*sin(mm)+1.61e-2*sin(2*mm)-4e-4*sin(3*mm)
  1643.         +1.04e-2*sin(2*f)-5.1e-3*sin(ms+mm)-7.4e-3*sin(ms-mm)
  1644.         +4e-4*sin(2*f+ms)-4e-4*sin(2*f-ms)-6e-4*sin(2*f+mm)
  1645.         +1e-3*sin(2*f-mm)+5e-4*sin(ms+2*mm);
  1646.     a1 = (int)a;
  1647.     b = b+ddjd+(a-a1);
  1648.     b1 = (int)b;
  1649.     a = a1+b1;
  1650.     b = b-b1;
  1651.     *mjd = a + b;
  1652. }
  1653. xXx
  1654. echo x nutation.c
  1655. cat > nutation.c << 'xXx'
  1656. #include <stdio.h>
  1657. #include <math.h>
  1658. #include "astro.h"
  1659.  
  1660. /* given the modified JD, mjd, find the nutation in obliquity, *deps, and
  1661.  * the nutation in longitude, *dpsi, each in radians.
  1662.  */
  1663. nutation (mjd, deps, dpsi)
  1664. double mjd;
  1665. double *deps, *dpsi;
  1666. {
  1667.     static double lastmjd, lastdeps, lastdpsi;
  1668.     double ls, ld;    /* sun's mean longitude, moon's mean longitude */
  1669.     double ms, md;    /* sun's mean anomaly, moon's mean anomaly */
  1670.     double nm;    /* longitude of moon's ascending node */
  1671.     double t, t2;    /* number of Julian centuries of 36525 days since
  1672.              * Jan 0.5 1900.
  1673.              */
  1674.     double tls, tnm, tld;    /* twice above */
  1675.     double a, b;    /* temps */
  1676.  
  1677.     if (mjd == lastmjd) {
  1678.         *deps = lastdeps;
  1679.         *dpsi = lastdpsi;
  1680.         return;
  1681.     }
  1682.         
  1683.     t = mjd/36525.;
  1684.     t2 = t*t;
  1685.  
  1686.     a = 100.0021358*t;
  1687.     b = 360.*(a-(int)a);
  1688.     ls = 279.697+.000303*t2+b;
  1689.  
  1690.     a = 1336.855231*t;
  1691.     b = 360.*(a-(int)a);
  1692.     ld = 270.434-.001133*t2+b;
  1693.  
  1694.     a = 99.99736056000026*t;
  1695.     b = 360.*(a-(int)a);
  1696.     ms = 358.476-.00015*t2+b;
  1697.  
  1698.     a = 13255523.59*t;
  1699.     b = 360.*(a-(int)a);
  1700.     md = 296.105+.009192*t2+b;
  1701.  
  1702.     a = 5.372616667*t;
  1703.     b = 360.*(a-(int)a);
  1704.     nm = 259.183+.002078*t2-b;
  1705.  
  1706.     /* convert to radian forms for use with trig functions.
  1707.      */
  1708.     tls = 2*degrad(ls);
  1709.     nm = degrad(nm);
  1710.     tnm = 2*degrad(nm);
  1711.     ms = degrad(ms);
  1712.     tld = 2*degrad(ld);
  1713.     md = degrad(md);
  1714.  
  1715.     /* find delta psi and eps, in arcseconds.
  1716.      */
  1717.     lastdpsi = (-17.2327-.01737*t)*sin(nm)+(-1.2729-.00013*t)*sin(tls)
  1718.            +.2088*sin(tnm)-.2037*sin(tld)+(.1261-.00031*t)*sin(ms)
  1719.            +.0675*sin(md)-(.0497-.00012*t)*sin(tls+ms)
  1720.            -.0342*sin(tld-nm)-.0261*sin(tld+md)+.0214*sin(tls-ms)
  1721.            -.0149*sin(tls-tld+md)+.0124*sin(tls-nm)+.0114*sin(tld-md);
  1722.     lastdeps = (9.21+.00091*t)*cos(nm)+(.5522-.00029*t)*cos(tls)
  1723.            -.0904*cos(tnm)+.0884*cos(tld)+.0216*cos(tls+ms)
  1724.            +.0183*cos(tld-nm)+.0113*cos(tld+md)-.0093*cos(tls-ms)
  1725.            -.0066*cos(tls-nm);
  1726.  
  1727.     /* convert to radians.
  1728.      */
  1729.     lastdpsi = degrad(lastdpsi/3600);
  1730.     lastdeps = degrad(lastdeps/3600);
  1731.  
  1732.     lastmjd = mjd;
  1733.     *deps = lastdeps;
  1734.     *dpsi = lastdpsi;
  1735. }
  1736. xXx
  1737. echo x objx.c
  1738. cat > objx.c << 'xXx'
  1739. /* functions to save the user-definable object.
  1740.  * this way, once set, the object can be quieried for position just like the
  1741.  * other bodies. also, someday we can use oribital elements to let object-x
  1742.  * be any solar system body too.
  1743.  */
  1744.  
  1745. #include <math.h>
  1746. #include "astro.h"
  1747. #include "circum.h"
  1748. #include "screen.h"
  1749.  
  1750. static double objx_ra, objx_dec, objx_epoch;
  1751. static char objx_name[MAXOBJXNM+1] = "";
  1752. static int objx_onflag;        /* !0 while object x is active */
  1753.  
  1754. /* set attributes of object x.
  1755.  * use pointers so we can set just some attributes as desired.
  1756.  */
  1757. objx_set (r, d, e, name)
  1758. double *r, *d, *e;
  1759. char *name;
  1760. {
  1761.     if (r) objx_ra = *r;
  1762.     if (d) objx_dec = *d;
  1763.     if (e) objx_epoch = *e;
  1764.     if (name) strncpy (objx_name, name, MAXOBJXNM);
  1765. }
  1766.  
  1767. /* return those attributes of interest for object x.
  1768.  * always return a 2-char name.
  1769.  */
  1770. objx_get (r, d, e, name)
  1771. double *r, *d, *e;
  1772. char *name;
  1773. {
  1774.     if (r) *r = objx_ra;
  1775.     if (d) *d = objx_dec;
  1776.     if (e) *e = objx_epoch;
  1777.     if (name) {
  1778.         name[0] = name[1] = ' ';
  1779.         strcpy (name, objx_name); /* includes trailing 0 */
  1780.     }
  1781. }
  1782.  
  1783. /* turn "on" or "off" but don't forget facts about object x.
  1784.  */
  1785. objx_on ()
  1786. {
  1787.     objx_onflag = 1;
  1788. }
  1789. objx_off()
  1790. {
  1791.     objx_onflag = 0;
  1792. }
  1793.  
  1794. /* return true if object is now on, else 0.
  1795.  */
  1796. objx_ison()
  1797. {
  1798.     return (objx_onflag);
  1799. }
  1800.  
  1801. /* fill in sp with all we can about object x. */
  1802. /* ARGSUSED */
  1803. objx_cir (as, np, sp)
  1804. double as;    /* desired, accuracy, in arc seconds. ignored for now */
  1805. Now *np;
  1806. Sky *sp;
  1807. {
  1808.     double xr, xd, xe;
  1809.     double lst, alt, az;
  1810.     double lsn, rsn, bet, lam, el;
  1811.  
  1812.     objx_get (&xr, &xd, &xe, (char *)0);
  1813.  
  1814.     precess (xe, epoch==EOD ? mjd : epoch, &xr, &xd);
  1815.     sp->s_ra = xr;
  1816.     sp->s_dec = xd;
  1817.  
  1818.     now_lst (np, &lst);
  1819.     hadec_aa (lat, hrrad(lst) - xr, xd, &alt, &az);
  1820.     refract (pressure, temp, alt, &alt);
  1821.     sp->s_alt = alt;
  1822.     sp->s_az = az;
  1823.  
  1824.     /* elongation */
  1825.     sunpos (mjd, &lsn, &rsn);
  1826.     range (&lsn, 2*PI);
  1827.     eq_ecl (mjd, xr, xd, &bet, &lam);
  1828.     elongation (lam, bet, lsn, &el);
  1829.     sp->s_elong = raddeg (el);
  1830.  
  1831.     /* TODO: not always new really */
  1832.     return (1);
  1833. }
  1834. xXx
  1835. echo x obliq.c
  1836. cat > obliq.c << 'xXx'
  1837. #include <stdio.h>
  1838. #include "astro.h"
  1839.  
  1840. /* given the modified Julian date, mjd, find the obliquity of the
  1841.  * ecliptic, *eps, in radians.
  1842.  */
  1843. obliquity (mjd, eps)
  1844. double mjd;
  1845. double *eps;
  1846. {
  1847.     static double lastmjd, lasteps;
  1848.  
  1849.     if (mjd != lastmjd) {
  1850.         double t;
  1851.         t = mjd/36525.;
  1852.         lasteps = degrad(2.345229444E1 - ((((-1.81E-3*t)+5.9E-3)*t+4.6845E1)*t)/3600.0);
  1853.         lastmjd = mjd;
  1854.     }
  1855.     *eps = lasteps;
  1856. }
  1857. xXx
  1858. echo x parallax.c
  1859. cat > parallax.c << 'xXx'
  1860. #include <stdio.h>
  1861. #include <math.h>
  1862. #include "astro.h"
  1863.  
  1864. /* given true ha and dec, tha and tdec, the geographical latitude, phi, the
  1865.  * height above sea-level (as a fraction of the earths radius, 6378.16km),
  1866.  * ht, and the equatorial horizontal parallax, ehp, find the apparent
  1867.  * ha and dec, aha and adec allowing for parallax.
  1868.  * all angles in radians. ehp is the angle subtended at the body by the
  1869.  * earth's equator.
  1870.  */
  1871. ta_par (tha, tdec, phi, ht, ehp, aha, adec)
  1872. double tha, tdec, phi, ht, ehp;
  1873. double *aha, *adec;
  1874. {
  1875.     static double last_phi, last_ht, rsp, rcp;
  1876.     double rp;    /* distance to object in Earth radii */
  1877.     double ctha;
  1878.     double stdec, ctdec;
  1879.     double tdtha, dtha;
  1880.     double caha;
  1881.  
  1882.     /* avoid calcs involving the same phi and ht */
  1883.     if (phi != last_phi || ht != last_ht) {
  1884.         double cphi, sphi, u;
  1885.         cphi = cos(phi);
  1886.         sphi = sin(phi);
  1887.         u = atan(9.96647e-1*sphi/cphi);
  1888.         rsp = (9.96647e-1*sin(u))+(ht*sphi);
  1889.         rcp = cos(u)+(ht*cphi);
  1890.         last_phi  =  phi;
  1891.         last_ht  =  ht;
  1892.     }
  1893.  
  1894.         rp = 1/sin(ehp);
  1895.  
  1896.         ctha = cos(tha);
  1897.     stdec = sin(tdec);
  1898.     ctdec = cos(tdec);
  1899.         tdtha = (rcp*sin(tha))/((rp*ctdec)-(rcp*ctha));
  1900.         dtha = atan(tdtha);
  1901.     *aha = tha+dtha;
  1902.     caha = cos(*aha);
  1903.     range (aha, 2*PI);
  1904.         *adec = atan(caha*(rp*stdec-rsp)/(rp*ctdec*ctha-rcp));
  1905. }
  1906.  
  1907. /* given the apparent ha and dec, aha and adec, the geographical latitude, phi,
  1908.  * the height above sea-level (as a fraction of the earths radius, 6378.16km),
  1909.  * ht, and the equatorial horizontal parallax, ehp, find the true ha and dec,
  1910.  * tha and tdec allowing for parallax.
  1911.  * all angles in radians. ehp is the angle subtended at the body by the
  1912.  * earth's equator.
  1913.  * uses ta_par() iteratively: find a set of true ha/dec that converts back
  1914.   *  to the given apparent ha/dec.
  1915.  */
  1916. at_par (aha, adec, phi, ht, ehp, tha, tdec)
  1917. double aha, adec, phi, ht, ehp;
  1918. double *tha, *tdec;
  1919. {
  1920.     double nha, ndec;    /* ha/dec corres. to current true guesses */
  1921.     double eha, edec;    /* error in ha/dec */
  1922.  
  1923.     /* first guess for true is just the apparent */
  1924.     *tha = aha;
  1925.     *tdec = adec;
  1926.  
  1927.     while (1) {
  1928.         ta_par (*tha, *tdec, phi, ht, ehp, &nha, &ndec);
  1929.         eha = aha - nha;
  1930.         edec = adec - ndec;
  1931.         if (fabs(eha)<1e-6 && fabs(edec)<1e-6)
  1932.         break;
  1933.         *tha += eha;
  1934.         *tdec += edec;
  1935.     }
  1936. }
  1937. xXx
  1938. echo x pelement.c
  1939. cat > pelement.c << 'xXx'
  1940. #include <stdio.h>
  1941. #include <math.h>
  1942. #include "astro.h"
  1943.  
  1944. /* this array contains polynomial coefficients to find the various orbital
  1945.  *   elements for the mean orbit at any instant in time for each major planet.
  1946.  *   the first five elements are in the form a0 + a1*t + a2*t**2 + a3*t**3,
  1947.  *   where t is the number of Julian centuries of 36525 Julian days since 1900
  1948.  *   Jan 0.5. the last three elements are constants.
  1949.  *
  1950.  * the orbital element (column) indeces are:
  1951.  *   [ 0- 3]: coefficients for mean longitude, in degrees;
  1952.  *   [ 4- 7]: coefficients for longitude of the perihelion, in degrees;
  1953.  *   [ 8-11]: coefficients for eccentricity;
  1954.  *   [12-15]: coefficients for inclination, in degrees;
  1955.  *   [16-19]: coefficients for longitude of the ascending node, in degrees;
  1956.  *      [20]: semi-major axis, in AU;
  1957.  *      [21]: angular diameter at 1 AU, in arcsec;
  1958.  *      [22]: standard visual magnitude, ie, the visual magnitude of the planet
  1959.  *          when at a distance of 1 AU from both the Sun and the Earth and
  1960.  *          with zero phase angle.
  1961.  *
  1962.  * the planent (row) indeces are:
  1963.  *   [0]: Mercury; [1]: Venus;   [2]: Mars;  [3]: Jupiter; [4]: Saturn;
  1964.  *   [5]: Uranus;  [6]: Neptune; [7]: Pluto.
  1965.  */
  1966. #define    NPELE    (5*4 + 3)    /* 4 coeffs for ea of 5 elems, + 3 constants */
  1967. static double elements[8][NPELE] = {
  1968.  
  1969.     {   /*     mercury... */
  1970.  
  1971.         178.179078,    415.2057519,    3.011e-4,    0.0,
  1972.         75.899697,    1.5554889,    2.947e-4,    0.0,
  1973.         .20561421,    2.046e-5,    3e-8,        0.0,
  1974.         7.002881,    1.8608e-3,    -1.83e-5,    0.0,
  1975.         47.145944,    1.1852083,    1.739e-4,    0.0,
  1976.         .3870986,    6.74,         -0.42
  1977.     },
  1978.  
  1979.     {   /*     venus... */
  1980.  
  1981.         342.767053,    162.5533664,    3.097e-4,    0.0,
  1982.         130.163833,    1.4080361,    -9.764e-4,    0.0,
  1983.         6.82069e-3,    -4.774e-5,    9.1e-8,        0.0,
  1984.         3.393631,    1.0058e-3,    -1e-6,        0.0,
  1985.         75.779647,    .89985,        4.1e-4,        0.0,
  1986.         .7233316,    16.92,        -4.4
  1987.     },
  1988.  
  1989.     {   /*     mars... */
  1990.  
  1991.         293.737334,    53.17137642,    3.107e-4,    0.0,
  1992.         3.34218203e2, 1.8407584,    1.299e-4,    -1.19e-6,
  1993.         9.33129e-2,    9.2064e-5,    7.7e-8,        0.0,
  1994.         1.850333,    -6.75e-4,    1.26e-5,    0.0,
  1995.         48.786442,    .7709917,    -1.4e-6,    -5.33e-6,
  1996.         1.5236883,    9.36,        -1.52
  1997.     },
  1998.  
  1999.     {   /*     jupiter... */
  2000.  
  2001.         238.049257,    8.434172183,    3.347e-4,    -1.65e-6,
  2002.         1.2720972e1, 1.6099617,    1.05627e-3,    -3.43e-6,
  2003.         4.833475e-2, 1.6418e-4,    -4.676e-7,    -1.7e-9,
  2004.         1.308736,    -5.6961e-3,    3.9e-6,        0.0,
  2005.         99.443414,    1.01053,    3.5222e-4,    -8.51e-6,
  2006.         5.202561,    196.74,        -9.4
  2007.     },
  2008.  
  2009.     {   /*     saturn... */
  2010.  
  2011.         266.564377,    3.398638567,    3.245e-4,    -5.8e-6,
  2012.         9.1098214e1, 1.9584158,    8.2636e-4,    4.61e-6,
  2013.         5.589232e-2, -3.455e-4,    -7.28e-7,    7.4e-10,
  2014.         2.492519,    -3.9189e-3,    -1.549e-5,    4e-8,
  2015.         112.790414,    .8731951,    -1.5218e-4,    -5.31e-6,
  2016.         9.554747,    165.6,        -8.88
  2017.     },
  2018.  
  2019.     {   /*     uranus... */
  2020.  
  2021.         244.19747,    1.194065406,    3.16e-4,    -6e-7,
  2022.         1.71548692e2, 1.4844328,    2.372e-4,    -6.1e-7,
  2023.         4.63444e-2,    -2.658e-5,    7.7e-8,        0.0,
  2024.         .772464,    6.253e-4,    3.95e-5,    0.0,
  2025.         73.477111,    .4986678,    1.3117e-3,    0.0,
  2026.         19.21814,    65.8,        -7.19
  2027.     },
  2028.  
  2029.     {   /*     neptune... */
  2030.  
  2031.         84.457994,    .6107942056,    3.205e-4,    -6e-7,
  2032.         4.6727364e1, 1.4245744,    3.9082e-4,    -6.05e-7,
  2033.         8.99704e-3,    6.33e-6,    -2e-9,        0.0,
  2034.         1.779242,    -9.5436e-3,    -9.1e-6,    0.0,
  2035.         130.681389,    1.098935,    2.4987e-4,    -4.718e-6,
  2036.         30.10957,    62.2,        -6.87
  2037.     },
  2038.  
  2039.     {   /*     pluto...(osculating 1984 jan 21) */
  2040.  
  2041.         95.3113544,    .3980332167,    0.0,        0.0,
  2042.         224.017,    0.0,        0.0,        0.0,
  2043.         .25515,    0.0,        0.0,        0.0,
  2044.         17.1329,    0.0,        0.0,        0.0,
  2045.         110.191,    0.0,        0.0,        0.0,
  2046.         39.8151,    8.2,        -1.0
  2047.     }
  2048. };
  2049.  
  2050. /* given a modified Julian date, mjd, return the elements for the mean orbit
  2051.  *   at that instant of all the major planets, together with their
  2052.  *   mean daily motions in longitude, angular diameter and standard visual
  2053.  *   magnitude.
  2054.  * plan[i][j] contains all the values for all the planets at mjd, such that
  2055.  *   i = 0..7: mercury, venus, mars, jupiter, saturn, unranus, neptune, pluto;
  2056.  *   j = 0..8: mean longitude, mean daily motion in longitude, longitude of 
  2057.  *     the perihelion, eccentricity, inclination, longitude of the ascending
  2058.  *     node, length of the semi-major axis, angular diameter from 1 AU, and
  2059.  *     the standard visual magnitude (see elements[][] comment, above).
  2060.  */
  2061. pelement (mjd, plan)
  2062. double mjd;
  2063. double plan[8][9];
  2064. {
  2065.     register double *ep, *pp;
  2066.     register double t = mjd/36525.;
  2067.     double aa;
  2068.     int planet, i;
  2069.  
  2070.     for (planet = 0; planet < 8; planet++) {
  2071.         ep = elements[planet];
  2072.         pp = plan[planet];
  2073.         aa = ep[1]*t;
  2074.         pp[0] = ep[0] + 360.*(aa-(int)aa) + (ep[3]*t + ep[2])*t*t;
  2075.         range (pp, 360.);
  2076.         pp[1] = (ep[1]*9.856263e-3) + (ep[2] + ep[3])/36525;
  2077.  
  2078.         for (i = 4; i < 20; i += 4)
  2079.         pp[i/4+1] = ((ep[i+3]*t + ep[i+2])*t + ep[i+1])*t + ep[i+0];
  2080.  
  2081.         pp[6] = ep[20];
  2082.         pp[7] = ep[21];
  2083.         pp[8] = ep[22];
  2084.     }
  2085. }
  2086. xXx
  2087.