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