home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / astrnomy / ephem421.zip / MAIN.C < prev    next >
C/C++ Source or Header  |  1990-09-13  |  26KB  |  965 lines

  1. /* main "ephem" program. 
  2.  * -------------------------------------------------------------------
  3.  * Copyright (c) 1990 by Elwood Charles Downey
  4.  * 
  5.  * Permission is granted to make and distribute copies of this program
  6.  * free of charge, provided the copyright notice and this permission
  7.  * notice are preserved on all copies.  All other rights reserved.
  8.  * -------------------------------------------------------------------
  9.  * set options.
  10.  * init screen and circumstances.
  11.  * enter infinite loop updating screen and allowing operator input.
  12.  */
  13.  
  14. #include <stdio.h>
  15. #include <signal.h>
  16. #include <setjmp.h>
  17. #include <math.h>
  18. #ifdef VMS
  19. #include <stdlib.h>
  20. #endif
  21. #include "astro.h"
  22. #include "circum.h"
  23. #include "screen.h"
  24.  
  25. extern char *strncpy();
  26. extern char *getenv();
  27.  
  28. /* shorthands for fields of a Now structure, now.
  29.  * first undo the ones for a Now pointer from circum.h.
  30.  */
  31. #undef mjd
  32. #undef lat
  33. #undef lng
  34. #undef tz
  35. #undef temp
  36. #undef pressure
  37. #undef height
  38. #undef epoch
  39. #undef tznm
  40.  
  41. #define mjd    now.n_mjd
  42. #define lat    now.n_lat
  43. #define lng    now.n_lng
  44. #define tz    now.n_tz
  45. #define temp    now.n_temp
  46. #define pressure now.n_pressure
  47. #define height    now.n_height
  48. #define epoch    now.n_epoch
  49. #define tznm    now.n_tznm
  50.  
  51. static jmp_buf fpe_err_jmp;    /* used to recover from SIGFPE */
  52. static char *cfgfile;        /* !0 if -c used */
  53. static char cfgdef[] = "ephem.cfg"; /* default configuration file name */
  54. static Now now;        /* where when and how, right now */
  55. static double tminc;    /* hrs to inc time by each loop; RTC means use clock */
  56. static int nstep;    /* steps to go before stopping */
  57. static int spause;    /* secs to pause between steps */
  58. static int optwi;    /* set when want to display dawn/dusk/len-of-night */
  59. static int oppl;    /* mask of (1<<planet) bits; set when want to show it */
  60.  
  61. main (ac, av)
  62. int ac;
  63. char *av[];
  64. {
  65.     void bye();
  66.     void on_fpe();
  67.     static char freerun[] =
  68.         "Running... press any key to stop to make changes.";
  69.     static char prmpt[] =
  70. "Move to another field, RETURN to change this field, ? for help, or q to run";
  71.     static char hlp[] =
  72.     "arrow keys move to field; any key stops running; ^d exits; ^l redraws";
  73.     int curr = R_NSTEP, curc = C_NSTEPV;    /* must start somewhere */
  74.     int sflag = 0;    /* not silent, by default */
  75.     int one = 1;    /* use a variable so optimizer doesn't get disabled */
  76.     int srchdone = 0; /* true when search funcs say so */
  77.     int newcir = 2;    /* set when circumstances change - means don't tminc */
  78.  
  79.     while ((--ac > 0) && (**++av == '-')) {
  80.         char *s;
  81.         for (s = *av+1; *s != '\0'; s++)
  82.         switch (*s) {
  83.         case 's': /* no credits "silent" (don't publish this) */
  84.             sflag++;
  85.             break;
  86.         case 'c': /* set name of config file to use */
  87.             if (--ac <= 0) usage("-c but no config file");
  88.             cfgfile = *++av;
  89.             break;
  90.         case 'd': /* set alternate database file name */
  91.             if (--ac <= 0) usage("-d but no database file");
  92.             obj_setdbfilename (*++av);
  93.             break;
  94.         default:
  95.             usage("Bad - option");
  96.         }
  97.     }
  98.  
  99.     if (!sflag)
  100.         credits();
  101.  
  102.     /* fresh screen.
  103.      * crack config file, THEN args so args may override.
  104.      */
  105.     c_erase();
  106.     read_cfgfile ();
  107.     read_fieldargs (ac, av);
  108.  
  109.     /* set up to clean up screen and tty if interrupted.
  110.      * also set up to stop if get floating error.
  111.      */
  112.     (void) signal (SIGINT, bye);
  113.     (void) signal (SIGFPE, on_fpe);
  114.  
  115.     /* update screen forever (until QUIT) */
  116.     while (one) {
  117.  
  118.         /* if get a floating error, longjmp() here and stop looping */
  119.         if (setjmp (fpe_err_jmp))
  120.         nstep = 0;
  121.         else {
  122.         nstep -= 1;
  123.  
  124.         /* recalculate everything and update all the fields */
  125.         redraw_screen (newcir);
  126.         mm_newcir (0);
  127.  
  128.         /* let searching functions change tminc and check for done */
  129.         srchdone = srch_eval (mjd, &tminc) < 0;
  130.         print_tminc(0);    /* to show possibly new search increment */
  131.  
  132.         /* update plot and listing files, now that all fields are up
  133.          * to date and search function has been evaluated.
  134.          */
  135.         plot();
  136.         listing();
  137.  
  138.         /* handle spause if we are really looping */
  139.         if (nstep > 0)
  140.             slp_sync();
  141.         }
  142.  
  143.         /* stop loop to allow op to change parameters:
  144.          * if a search evaluation converges (or errors out),
  145.          * or if steps are done,
  146.          * or if op hits any key.
  147.          */
  148.         newcir = 0;
  149.         if (srchdone || nstep <= 0 || (chk_char()==0 && read_char()!=0)) {
  150.         int fld;
  151.  
  152.         /* update screen with the current stuff if stopped during
  153.          * unattended plotting or listing since last redraw_screen()
  154.          * didn't.
  155.          */
  156.         if ((plot_ison() || listing_ison()) && nstep > 0)
  157.             redraw_screen (1);
  158.  
  159.         /* return nstep to default of 1 */
  160.         if (nstep <= 0) {
  161.             nstep = 1;
  162.             print_nstep (0);
  163.         }
  164.  
  165.         /* change fields until END.
  166.          * update all time fields if any are changed
  167.          * and print NEW CIRCUMSTANCES if any have changed.
  168.          * QUIT causes bye() to be called and we never return.
  169.          */
  170.         while(fld = sel_fld(curr,curc,alt_menumask()|F_CHG,prmpt,hlp)) {
  171.             if (chg_fld ((char *)0, fld)) {
  172.             mm_now (&now, 1);
  173.             mm_newcir(1);
  174.             newcir = 1;
  175.             }
  176.             curr = unpackr (fld);
  177.             curc = unpackc (fld);
  178.         }
  179.         if (nstep > 1)
  180.             f_prompt (freerun);
  181.         }
  182.  
  183.         /* increment time only if op didn't change cirumstances */
  184.         if (!newcir)
  185.         inc_mjd (&now, tminc);
  186.     }
  187.  
  188.     return (0);
  189. }
  190.  
  191. /* read in ephem's configuration file, if any.
  192.  * if errors in file, call usage() (which exits).
  193.  * if use -d, require it; else try $EPHEMCFG and ephem.cfg but don't
  194.  *   complain if can't find these since, after all, one is not required.
  195.  * skip blank lines and lines that begin with '#', '*', ' ' or '\t'.
  196.  */
  197. static
  198. read_cfgfile()
  199. {
  200.     char buf[128];
  201.     FILE *fp;
  202.     char *fn;
  203.  
  204.     /* open the config file. 
  205.      * only REQUIRED if used -d option.
  206.      * if succcessful, fn points to file name.
  207.      */
  208.     if (cfgfile) {
  209.         fn = cfgfile;
  210.         fp = fopen (fn, "r");
  211.         if (!fp) {
  212.         (void) sprintf (buf, "Can not open %s", fn);
  213.         usage (buf);    /* does not return */
  214.         }
  215.     } else {
  216.         fn = getenv ("EPHEMCFG");
  217.         if (!fn)
  218.         fn = cfgdef;
  219.     }
  220.     fp = fopen (fn, "r");
  221.     if (!fp)
  222.         return;    /* oh well; after all, it's not required */
  223.  
  224.     while (fgets (buf, sizeof(buf), fp)) {
  225.         switch (buf[0]) {
  226.         case '#': case '*': case ' ': case '\t': case '\n':
  227.         continue;
  228.         }
  229.         buf[strlen(buf)-1] = '\0';        /* discard trailing \n */
  230.         if (crack_fieldset (buf) < 0) {
  231.         char why[NC];
  232.         (void) sprintf (why, "Bad field spec in %s: %s\n", fn, buf);
  233.         usage (why);
  234.         }
  235.     }
  236.     (void) fclose (fp);
  237. }
  238.  
  239.  
  240. /* draw all the stuff on the screen, using the current menu.
  241.  * if how_much == 0 then just update fields that need it;
  242.  * if how_much == 1 then redraw all fields;
  243.  * if how_much == 2 then erase the screen and redraw EVERYTHING.
  244.  */
  245. redraw_screen (how_much)
  246. int how_much;
  247. {
  248.     if (how_much == 2)
  249.         c_erase();
  250.  
  251.     /* print the single-step message if this is the last loop */
  252.     if (nstep < 1)
  253.         print_updating();
  254.  
  255.     if (how_much == 2) {
  256.         mm_borders();
  257.         mm_labels();
  258.         srch_prstate(1);
  259.         plot_prstate(1);
  260.         listing_prstate(1);
  261.         alt_labels();
  262.     }
  263.  
  264.     /* if just updating changed fields while plotting or listing
  265.      * unattended then suppress most screen updates except
  266.      * always show nstep to show plot loops to go and
  267.      * always show tminc to show search convergence progress.
  268.      */
  269.     print_nstep(how_much);
  270.     print_tminc(how_much);
  271.     print_spause(how_much);
  272.     if (how_much == 0 && (plot_ison() || listing_ison()) && nstep > 0)
  273.         f_off();
  274.  
  275.     /* print all the time-related fields */
  276.     mm_now (&now, how_much);
  277.  
  278.     if (optwi)
  279.         mm_twilight (&now, how_much);
  280.  
  281.     /* print solar system body info */
  282.     print_bodies (how_much);
  283.  
  284.     f_on();
  285. }
  286.  
  287. /* clean up and exit.
  288.  */
  289. void
  290. bye()
  291. {
  292.     c_erase();
  293.     byetty();
  294.     exit (0);
  295. }
  296.  
  297. /* this gets called when a floating point error occurs.
  298.  * we force a jump back into main() with looping terminated.
  299.  */
  300. static
  301. void
  302. on_fpe()
  303. {
  304.     (void) signal (SIGFPE, on_fpe);
  305.     f_msg ("Floating point error has occurred - computations aborted.");
  306.     longjmp (fpe_err_jmp, 1);
  307. }
  308.  
  309. usage(why)
  310. char *why;
  311. {
  312.     /* don't advertise -s (silent) option */
  313.     c_erase();
  314.     f_string (1, 1, why);
  315.     f_string (2, 1,
  316.         "usage: [-c <configfile>] [-d <database>] [field=value ...]\r\n");
  317.     byetty();
  318.     exit (1);
  319. }
  320.  
  321. /* process the field specs from the command line.
  322.  * if trouble call usage() (which exits).
  323.  */
  324. static
  325. read_fieldargs (ac, av)
  326. int ac;        /* number of such specs */
  327. char *av[];    /* array of strings in form <field_name value> */
  328. {
  329.     while (--ac >= 0) {
  330.         char *fs = *av++;
  331.         if (crack_fieldset (fs) < 0) {
  332.         char why[NC];
  333.         (void) sprintf (why, "Bad command line spec: %.*s",
  334.                             sizeof(why)-26, fs);
  335.         usage (why);
  336.         }
  337.     }
  338. }
  339.  
  340. /* process a field spec in buf, either from config file or argv.
  341.  * return 0 if recognized ok, else -1.
  342.  */
  343. static
  344. crack_fieldset (buf)
  345. char *buf;
  346. {
  347.     if (strncmp ("LAT", buf, 3) == 0)
  348.         (void) chg_fld (buf+4, rcfpack (R_LAT,C_LATV,0));
  349.     else if (strncmp ("LONG", buf, 4) == 0)
  350.         (void) chg_fld (buf+5, rcfpack (R_LONG,C_LONGV,0));
  351.     else if (strncmp ("UT", buf, 2) == 0)
  352.         (void) chg_fld (buf+3, rcfpack (R_UT,C_UTV,0));
  353.     else if (strncmp ("UD", buf, 2) == 0)
  354.         (void) chg_fld (buf+3, rcfpack (R_UD,C_UD,0));
  355.     else if (strncmp ("TZONE", buf, 5) == 0)
  356.         (void) chg_fld (buf+6, rcfpack (R_TZONE,C_TZONEV,0));
  357.     else if (strncmp ("TZNAME", buf, 6) == 0)
  358.         (void) chg_fld (buf+7, rcfpack (R_TZN,C_TZN,0));
  359.     else if (strncmp ("HEIGHT", buf, 6) == 0)
  360.         (void) chg_fld (buf+7, rcfpack (R_HEIGHT,C_HEIGHTV,0));
  361.     else if (strncmp ("NSTEP", buf, 5) == 0)
  362.         (void) chg_fld (buf+6, rcfpack (R_NSTEP,C_NSTEPV,0));
  363.     else if (strncmp ("PAUSE", buf, 5) == 0)
  364.         (void) chg_fld (buf+6, rcfpack (R_PAUSE,C_PAUSEV,0));
  365.     else if (strncmp ("STPSZ", buf, 5) == 0)
  366.         (void) chg_fld (buf+6, rcfpack (R_STPSZ,C_STPSZV,0));
  367.     else if (strncmp ("TEMP", buf, 4) == 0)
  368.         (void) chg_fld (buf+5, rcfpack (R_TEMP,C_TEMPV,0));
  369.     else if (strncmp ("PRES", buf, 4) == 0)
  370.         (void) chg_fld (buf+5, rcfpack (R_PRES,C_PRESV,0));
  371.     else if (strncmp ("EPOCH", buf, 5) == 0)
  372.         (void) chg_fld (buf+6, rcfpack (R_EPOCH,C_EPOCHV,0));
  373.     else if (strncmp ("JD", buf, 2) == 0)
  374.         (void) chg_fld (buf+3, rcfpack (R_JD,C_JDV,0));
  375.     else if (strncmp ("OBJX", buf, 4) == 0)
  376.         obj_filelookup (OBJX, buf+5);
  377.     else if (strncmp ("OBJY", buf, 4) == 0)
  378.         obj_filelookup (OBJY, buf+5);
  379.     else if (strncmp ("PROPTS", buf, 6) == 0) {
  380.         char *bp = buf+7;
  381.         if (buf[6] != '+')
  382.         optwi = oppl = 0;
  383.         while (*bp)
  384.         switch (*bp++) {
  385.         case 'T': optwi = 1; break;
  386.         case 'S': oppl |= (1<<SUN); break;
  387.         case 'M': oppl |= (1<<MOON); break;
  388.         case 'e': oppl |= (1<<MERCURY); break;
  389.         case 'v': oppl |= (1<<VENUS); break;
  390.         case 'm': oppl |= (1<<MARS); break;
  391.         case 'j': oppl |= (1<<JUPITER); break;
  392.         case 's': oppl |= (1<<SATURN); break;
  393.         case 'u': oppl |= (1<<URANUS); break;
  394.         case 'n': oppl |= (1<<NEPTUNE); break;
  395.         case 'p': oppl |= (1<<PLUTO); break;
  396.         case 'x': oppl |= (1<<OBJX); obj_on(OBJX); break;
  397.         case 'y': oppl |= (1<<OBJY); obj_on(OBJY); break;
  398.         }
  399.     } else if (strncmp ("MENU", buf, 4) == 0) {
  400.         if (strncmp (buf+5, "DATA", 4) == 0)
  401.         altmenu_init (F_MNU1);
  402.         else if (strncmp (buf+5, "RISET", 5) == 0)
  403.         altmenu_init (F_MNU2);
  404.         else if (strncmp (buf+5, "SEP", 3) == 0)
  405.         altmenu_init (F_MNU3);
  406.     } else
  407.         return (-1);
  408.     return (0);
  409. }
  410.  
  411. /* change the field at rcpk according to the optional string input at bp.
  412.  * if bp is != 0 use it, else issue read_line() and use buffer.
  413.  * then sscanf the buffer and update the corresponding (global) variable(s)
  414.  * or do whatever a pick at that field should do.
  415.  * return 1 if we change a field that invalidates any of the times or
  416.  * to update all related fields.
  417.  */
  418. static
  419. chg_fld (bp, rcpk)
  420. char *bp;
  421. int rcpk;
  422. {
  423.     char buf[NC];
  424.     int deghrs = 0, mins = 0, secs = 0;
  425.     int new = 0;
  426.  
  427.     /* switch on just the row/col portion */
  428.     switch (unpackrc(rcpk)) {
  429.     case rcfpack (R_ALTM, C_ALTM, 0):
  430.         if (altmenu_setup() == 0) {
  431.         print_updating();
  432.         alt_nolabels();
  433.         clrall_bodies();
  434.         alt_labels();
  435.         print_bodies(1);
  436.         }
  437.         break;
  438.     case rcfpack (R_JD, C_JDV, 0):
  439.         if (!bp) {
  440.         static char p[] = "Julian Date (or n for Now): ";
  441.         f_prompt (p);
  442.         if (read_line (buf, PW-sizeof(p)) <= 0)
  443.             break;
  444.         bp = buf;
  445.         }
  446.         if (bp[0] == 'n' || bp[0] == 'N')
  447.         time_fromsys (&now);
  448.         else
  449.         mjd = atof(bp) - 2415020L;
  450.         set_t0 (&now);
  451.         new = 1;
  452.         break;
  453.     case rcfpack (R_UD, C_UD, 0):
  454.         if (!bp) {
  455.         static char p[] = "utc date (m/d/y, or year.d, or n for Now): ";
  456.         f_prompt (p);
  457.         if (read_line (buf, PW-sizeof(p)) <= 0)
  458.             break;
  459.         bp = buf;
  460.         }
  461.         if (bp[0] == 'n' || bp[0] == 'N')
  462.         time_fromsys (&now);
  463.         else {
  464.         if (decimal_year(bp)) {
  465.             double y = atof (bp);
  466.             year_mjd (y, &mjd);
  467.         } else {
  468.             double day, newmjd0;
  469.             int month, year;
  470.             mjd_cal (mjd, &month, &day, &year); /* init with now */
  471.             f_sscandate (bp, &month, &day, &year);
  472.             cal_mjd (month, day, year, &newmjd0);
  473.             /* if don't give a fractional part to days
  474.              * then retain current hours.
  475.              */
  476.             if ((long)day == day)
  477.             mjd = newmjd0 + mjd_hr(mjd)/24.0;
  478.             else
  479.             mjd = newmjd0;
  480.         }
  481.         }
  482.         set_t0 (&now);
  483.         new = 1;
  484.         break;
  485.     case rcfpack (R_UT, C_UTV, 0):
  486.         if (!bp) {
  487.         static char p[] = "utc time (h:m:s, or n for Now): ";
  488.         f_prompt (p);
  489.         if (read_line (buf, PW-sizeof(p)) <= 0)
  490.             break;
  491.         bp = buf;
  492.         }
  493.         if (bp[0] == 'n' || bp[0] == 'N')
  494.         time_fromsys (&now);
  495.         else {
  496.         double newutc = (mjd-mjd_day(mjd)) * 24.0;
  497.         f_dec_sexsign (newutc, °hrs, &mins, &secs);
  498.         f_sscansex (bp, °hrs, &mins, &secs);
  499.         sex_dec (deghrs, mins, secs, &newutc);
  500.         mjd = mjd_day(mjd) + newutc/24.0;
  501.         }
  502.         set_t0 (&now);
  503.         new = 1;
  504.         break;
  505.     case rcfpack (R_LD, C_LD, 0):
  506.         if (!bp) {
  507.         static char p[] = "local date (m/d/y, or year.d, n for Now): ";
  508.         f_prompt (p);
  509.         if (read_line (buf, PW-sizeof(p)) <= 0)
  510.             break;
  511.         bp = buf;
  512.         }
  513.         if (bp[0] == 'n' || bp[0] == 'N')
  514.         time_fromsys (&now);
  515.         else {
  516.         if (decimal_year(bp)) {
  517.             double y = atof (bp);
  518.             year_mjd (y, &mjd);
  519.             mjd += tz/24.0;
  520.         } else {
  521.             double day, newlmjd0;
  522.             int month, year;
  523.             mjd_cal (mjd-tz/24.0, &month, &day, &year); /* now */
  524.             f_sscandate (bp, &month, &day, &year);
  525.             cal_mjd (month, day, year, &newlmjd0);
  526.             /* if don't give a fractional part to days
  527.              * then retain current hours.
  528.              */
  529.             if ((long)day == day)
  530.             mjd = newlmjd0 + mjd_hr(mjd-tz/24.0)/24.0;
  531.             else
  532.             mjd = newlmjd0;
  533.             mjd += tz/24.0;
  534.         }
  535.         }
  536.         set_t0 (&now);
  537.         new = 1;
  538.         break;
  539.     case rcfpack (R_LT, C_LT, 0):
  540.         if (!bp) {
  541.         static char p[] = "local time (h:m:s, or n for Now): ";
  542.         f_prompt (p);
  543.         if (read_line (buf, PW-sizeof(p)) <= 0)
  544.             break;
  545.         bp = buf;
  546.         }
  547.         if (bp[0] == 'n' || bp[0] == 'N')
  548.         time_fromsys (&now);
  549.         else {
  550.         double newlt = (mjd-mjd_day(mjd)) * 24.0 - tz;
  551.         range (&newlt, 24.0);
  552.         f_dec_sexsign (newlt, °hrs, &mins, &secs);
  553.         f_sscansex (bp, °hrs, &mins, &secs);
  554.         sex_dec (deghrs, mins, secs, &newlt);
  555.         mjd = mjd_day(mjd-tz/24.0) + (newlt + tz)/24.0;
  556.         }
  557.         set_t0 (&now);
  558.         new = 1;
  559.         break;
  560.     case rcfpack (R_LST, C_LSTV, 0):
  561.         if (!bp) {
  562.         static char p[] = "local sidereal time (h:m:s, or n for Now): ";
  563.         f_prompt (p);
  564.         if (read_line (buf, PW-sizeof(p)) <= 0)
  565.             break;
  566.         bp = buf;
  567.         }
  568.         if (bp[0] == 'n' || bp[0] == 'N')
  569.         time_fromsys (&now);
  570.         else {
  571.         double lst, utc;
  572.         now_lst (&now, &lst);
  573.         f_dec_sexsign (lst, °hrs, &mins, &secs);
  574.         f_sscansex (bp, °hrs, &mins, &secs);
  575.         sex_dec (deghrs, mins, secs, &lst);
  576.         lst -= radhr(lng); /* convert to gst */
  577.         range (&lst, 24.0);
  578.         gst_utc (mjd_day(mjd), lst, &utc);
  579.         mjd = mjd_day(mjd) + utc/24.0;
  580.         }
  581.         set_t0 (&now);
  582.         new = 1;
  583.         break;
  584.     case rcfpack (R_TZN, C_TZN, 0):
  585.         if (!bp) {
  586.         static char p[] = "timezone abbreviation (3 char max): ";
  587.         f_prompt (p);
  588.         if (read_line (buf, 3) <= 0)
  589.             break;
  590.         bp = buf;
  591.         }
  592.         (void) strncpy (tznm, bp, sizeof(tznm)-1);
  593.         new = 1;
  594.         break;
  595.     case rcfpack (R_TZONE, C_TZONEV, 0):
  596.         if (!bp) {
  597.         static char p[] = "hours behind utc: ";
  598.         f_prompt (p);
  599.         if (read_line (buf, PW-sizeof(p)) <= 0)
  600.             break;
  601.         bp = buf;
  602.         }
  603.         f_dec_sexsign (tz, °hrs, &mins, &secs);
  604.         f_sscansex (bp, °hrs, &mins, &secs);
  605.         sex_dec (deghrs, mins, secs, &tz);
  606.         new = 1;
  607.         break;
  608.     case rcfpack (R_LONG, C_LONGV, 0):
  609.         if (!bp) {
  610.         static char p[] = "longitude (+ west) (d:m:s): ";
  611.         f_prompt (p);
  612.         if (read_line (buf, PW-sizeof(p)) <= 0)
  613.             break;
  614.         bp = buf;
  615.         }
  616.         f_dec_sexsign (-raddeg(lng), °hrs, &mins, &secs);
  617.         f_sscansex (bp, °hrs, &mins, &secs);
  618.         sex_dec (deghrs, mins, secs, &lng);
  619.         lng = degrad (-lng);         /* want - radians west */
  620.         new = 1;
  621.         break;
  622.     case rcfpack (R_LAT, C_LATV, 0):
  623.         if (!bp) {
  624.         static char p[] = "latitude (+ north) (d:m:s): ";
  625.         f_prompt (p);
  626.         if (read_line (buf, PW-sizeof(p)) <= 0)
  627.             break;
  628.         bp = buf;
  629.         }
  630.         f_dec_sexsign (raddeg(lat), °hrs, &mins, &secs);
  631.         f_sscansex (bp, °hrs, &mins, &secs);
  632.         sex_dec (deghrs, mins, secs, &lat);
  633.         lat = degrad (lat);
  634.         new = 1;
  635.         break;
  636.     case rcfpack (R_HEIGHT, C_HEIGHTV, 0):
  637.         if (!bp) {
  638.         static char p[] = "height above sea level (ft): ";
  639.         f_prompt (p);
  640.         if (read_line (buf, PW-sizeof(p)) <= 0)
  641.             break;
  642.         bp = buf;
  643.         }
  644.         (void) sscanf (bp, "%lf", &height);
  645.         height /= 2.093e7; /* convert ft to earth radii above sea level */
  646.         new = 1;
  647.         break;
  648.     case rcfpack (R_NSTEP, C_NSTEPV, 0):
  649.         if (!bp) {
  650.         static char p[] = "number of steps to run: ";
  651.         f_prompt (p);
  652.         if (read_line (buf, 8) <= 0)
  653.             break;
  654.         bp = buf;
  655.         }
  656.         (void) sscanf (bp, "%d", &nstep);
  657.         print_nstep (0);
  658.         break;
  659.     case rcfpack (R_PAUSE, C_PAUSEV, 0):
  660.         if (!bp) {
  661.         static char p[] = "seconds to pause between steps: ";
  662.         f_prompt (p);
  663.         if (read_line (buf, 8) <= 0)
  664.             break;
  665.         bp = buf;
  666.         }
  667.         (void) sscanf (bp, "%d", &spause);
  668.         print_spause (0);
  669.         break;
  670.     case rcfpack (R_TEMP, C_TEMPV, 0):
  671.         if (!bp) {
  672.         static char p[] = "temperature (deg.F): ";
  673.         f_prompt (p);
  674.         if (read_line (buf, PW-sizeof(p)) <= 0)
  675.             break;
  676.         bp = buf;
  677.         }
  678.         (void) sscanf (bp, "%lf", &temp);
  679.         temp = 5./9.*(temp - 32.0);    /* want degs C */
  680.         new = 1;
  681.         break;
  682.     case rcfpack (R_PRES, C_PRESV, 0):
  683.         if (!bp) {
  684.         static char p[] =
  685.             "atmos pressure (in. Hg; 0 for no refraction correction): ";
  686.         f_prompt (p);
  687.         if (read_line (buf, PW-sizeof(p)) <= 0)
  688.             break;
  689.         bp = buf;
  690.         }
  691.         (void) sscanf (bp, "%lf", &pressure);
  692.         pressure *= 33.86;        /* want mBar */
  693.         new = 1;
  694.         break;
  695.     case rcfpack (R_EPOCH, C_EPOCHV, 0):
  696.         if (!bp) {
  697.         static char p[] = "epoch (year, or e for Equinox of Date): ";
  698.         f_prompt (p);
  699.         if (read_line (buf, PW-strlen(p)) <= 0)
  700.             break;
  701.         bp = buf;
  702.         }
  703.         if (bp[0] == 'e' || bp[0] == 'E')
  704.         epoch = EOD;
  705.         else {
  706.         double e;
  707.         e = atof(bp);
  708.         year_mjd (e, &epoch);
  709.         }
  710.         new = 1;
  711.         break;
  712.     case rcfpack (R_STPSZ, C_STPSZV, 0):
  713.         if (!bp) {
  714.         static char p[] =
  715.             "step size increment (h:m:s, or <x>d for x days, or r for RTC): ";
  716.         f_prompt (p);
  717.         if (read_line (buf, PW-sizeof(p)) <= 0)
  718.             break;
  719.         bp = buf;
  720.         }
  721.         if (bp[0] == 'r' || bp[0] == 'R')
  722.         tminc = RTC;
  723.         else {
  724.         int last = strlen (bp) - 1;
  725.         if (bp[last] == 'd') {
  726.             /* ends in d so treat as a number of days */
  727.             double x;
  728.             (void) sscanf (bp, "%lf", &x);
  729.             tminc = x * 24.0;
  730.         } else {
  731.             if (tminc == RTC)
  732.             deghrs = mins = secs = 0;
  733.             else
  734.             f_dec_sexsign (tminc, °hrs, &mins, &secs);
  735.             f_sscansex (bp, °hrs, &mins, &secs);
  736.             sex_dec (deghrs, mins, secs, &tminc);
  737.         }
  738.         }
  739.         print_tminc(0);
  740.         set_t0 (&now);
  741.         break;
  742.     case rcfpack (R_PLOT, C_PLOT, 0):
  743.         plot_setup();
  744.         if (plot_ison())
  745.         new = 1;
  746.         break;
  747.     case rcfpack (R_LISTING, C_LISTING, 0):
  748.         listing_setup();
  749.         if (listing_ison())
  750.         new = 1;
  751.         break;
  752.     case rcfpack (R_WATCH, C_WATCH, 0):
  753.         watch (&now, tminc, oppl);
  754.         /* set new reference time to what watch left it.
  755.          * no need to set new since watch just did a redraw.
  756.          */
  757.         set_t0 (&now);
  758.         break;
  759.     case rcfpack (R_DAWN, C_DAWN, 0):
  760.     case rcfpack (R_DUSK, C_DUSK, 0):
  761.     case rcfpack (R_LON, C_LON, 0):
  762.         if (optwi ^= 1) {
  763.         print_updating();
  764.         mm_twilight (&now, 1);
  765.         } else {
  766.         f_blanks (R_DAWN, C_DAWNV, 5);
  767.         f_blanks (R_DUSK, C_DUSKV, 5);
  768.         f_blanks (R_LON, C_LONV, 5);
  769.         }
  770.         break;
  771.     case rcfpack (R_SRCH, C_SRCH, 0):
  772.         srch_setup();
  773.         if (srch_ison())
  774.         new = 1;
  775.         break;
  776.     case rcfpack (R_SUN, C_OBJ, 0):
  777.         if ((oppl ^= (1<<SUN)) & (1<<SUN)) {
  778.         print_updating();
  779.         alt_body (SUN, 1, &now);
  780.         } else
  781.         alt_nobody (SUN);
  782.         break;
  783.     case rcfpack (R_MOON, C_OBJ, 0):
  784.         if ((oppl ^= (1<<MOON)) & (1<<MOON)) {
  785.         print_updating();
  786.         alt_body (MOON, 1, &now);
  787.         } else
  788.         alt_nobody (MOON);
  789.         break;
  790.     case rcfpack (R_MERCURY, C_OBJ, 0):
  791.         if ((oppl ^= (1<<MERCURY)) & (1<<MERCURY)) {
  792.         print_updating();
  793.         alt_body (MERCURY, 1, &now);
  794.         } else
  795.         alt_nobody (MERCURY);
  796.         break;
  797.     case rcfpack (R_VENUS, C_OBJ, 0):
  798.         if ((oppl ^= (1<<VENUS)) & (1<<VENUS)) {
  799.         print_updating();
  800.         alt_body (VENUS, 1, &now);
  801.         } else
  802.         alt_nobody (VENUS);
  803.         break;
  804.     case rcfpack (R_MARS, C_OBJ, 0):
  805.         if ((oppl ^= (1<<MARS)) & (1<<MARS)) {
  806.         print_updating();
  807.         alt_body (MARS, 1, &now);
  808.         } else
  809.         alt_nobody (MARS);
  810.         break;
  811.     case rcfpack (R_JUPITER, C_OBJ, 0):
  812.         if ((oppl ^= (1<<JUPITER)) & (1<<JUPITER)) {
  813.         print_updating();
  814.         alt_body (JUPITER, 1, &now);
  815.         } else
  816.         alt_nobody (JUPITER);
  817.         break;
  818.     case rcfpack (R_SATURN, C_OBJ, 0):
  819.         if ((oppl ^= (1<<SATURN)) & (1<<SATURN)) {
  820.         print_updating();
  821.         alt_body (SATURN, 1, &now);
  822.         } else
  823.         alt_nobody (SATURN);
  824.         break;
  825.     case rcfpack (R_URANUS, C_OBJ, 0):
  826.         if ((oppl ^= (1<<URANUS)) & (1<<URANUS)) {
  827.         print_updating();
  828.         alt_body (URANUS, 1, &now);
  829.         } else
  830.         alt_nobody (URANUS);
  831.         break;
  832.     case rcfpack (R_NEPTUNE, C_OBJ, 0):
  833.         if ((oppl ^= (1<<NEPTUNE)) & (1<<NEPTUNE)) {
  834.         print_updating();
  835.         alt_body (NEPTUNE, 1, &now);
  836.         } else
  837.         alt_nobody (NEPTUNE);
  838.         break;
  839.     case rcfpack (R_PLUTO, C_OBJ, 0):
  840.         if ((oppl ^= (1<<PLUTO)) & (1<<PLUTO)) {
  841.         print_updating();
  842.         alt_body (PLUTO, 1, &now);
  843.         } else
  844.         alt_nobody (PLUTO);
  845.         break;
  846.     case rcfpack (R_OBJX, C_OBJ, 0):
  847.         /* this might change which columns are used so erase all when
  848.          * returns and redraw if still on.
  849.          */
  850.         obj_setup (OBJX);
  851.         alt_nobody (OBJX);
  852.         if (obj_ison (OBJX)) {
  853.         oppl |= 1 << OBJX;
  854.         print_updating();
  855.         alt_body (OBJX, 1, &now);
  856.         } else
  857.         oppl &= ~(1 << OBJX);    /* already erased; just clear flag */
  858.         break;
  859.     case rcfpack (R_OBJY, C_OBJ, 0):
  860.         /* this might change which columns are used so erase all when
  861.          * returns and redraw if still on.
  862.          */
  863.         obj_setup (OBJY);
  864.         alt_nobody (OBJY);
  865.         if (obj_ison (OBJY)) {
  866.         oppl |= 1 << OBJY;
  867.         print_updating();
  868.         alt_body (OBJY, 1, &now);
  869.         } else
  870.         oppl &= ~(1 << OBJY);    /* already erased; just clear flag */
  871.         break;
  872.     }
  873.  
  874.     return (new);
  875. }
  876.  
  877. static
  878. print_tminc(force)
  879. int force;
  880. {
  881.     static double last = -123.456;    /* anything unlikely */
  882.  
  883.     if (force || tminc != last) {
  884.         if (tminc == RTC)
  885.         f_string (R_STPSZ, C_STPSZV, " RT CLOCK");
  886.         else if (fabs(tminc) >= 24.0)
  887.         f_double (R_STPSZ, C_STPSZV, "%6.4g dy", tminc/24.0);
  888.         else
  889.         f_signtime (R_STPSZ, C_STPSZV, tminc);
  890.         last = tminc;
  891.     }
  892. }
  893.  
  894. static
  895. print_bodies (force)
  896. int force;
  897. {
  898.     int p;
  899.  
  900.     for (p = nxtbody(-1); p != -1; p = nxtbody(p))
  901.         if (oppl & (1<<p))
  902.         alt_body (p, force, &now);
  903. }
  904.  
  905. static
  906. clrall_bodies ()
  907. {
  908.     int p;
  909.  
  910.     for (p = nxtbody(-1); p != -1; p = nxtbody(p))
  911.         if (oppl & (1<<p))
  912.         alt_nobody (p);
  913. }
  914.  
  915. print_updating()
  916. {
  917.     f_prompt ("Updating...");
  918. }
  919.  
  920. static
  921. print_nstep(force)
  922. int force;
  923. {
  924.     static int last;
  925.  
  926.     if (force || nstep != last) {
  927.         char buf[16];
  928.         (void) sprintf (buf, "%8d", nstep);
  929.         f_string (R_NSTEP, C_NSTEPV, buf);
  930.         last = nstep;
  931.     }
  932. }
  933.  
  934. static
  935. print_spause(force)
  936. int force;
  937. {
  938.     static int last;
  939.  
  940.     if (force || spause != last) {
  941.         char buf[16];
  942.         (void) sprintf (buf, "%8d", spause);
  943.         f_string (R_PAUSE, C_PAUSEV, buf);
  944.         last = spause;
  945.     }
  946. }
  947.  
  948. /* if not plotting or searching then sleep spause seconds.
  949.  * if time is being based on the real-time clock, sync on the next
  950.  *   integral multiple of spause seconds after the minute.
  951.  * check for keyboard action once each second to let it break out early.
  952.  */
  953. slp_sync()
  954. {
  955.     if (spause > 0 && !plot_ison() && !srch_ison()) {
  956.         extern long time();
  957.         int n= (tminc == RTC) ? spause - (time((long *)0)%spause) : spause;
  958.         while (--n >= 0)
  959.         if (chk_char() == 0)
  960.             break;
  961.         else
  962.             (void) sleep (1);
  963.     }
  964. }
  965.