home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume28 / ephem / part03 < prev    next >
Text File  |  1992-03-15  |  55KB  |  2,034 lines

  1. Newsgroups: comp.sources.misc
  2. From: e_downey@hwking.cca.cr.rockwell.com (Elwood C. Downey)
  3. Subject:  v28i086:  ephem - an interactive astronomical ephemeris, v4.28, Part03/09
  4. Message-ID: <1992Mar10.215726.15960@sparky.imd.sterling.com>
  5. X-Md4-Signature: c3900dac45b48d6d5612e76d0e9fef18
  6. Date: Tue, 10 Mar 1992 21:57:26 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: e_downey@hwking.cca.cr.rockwell.com (Elwood C. Downey)
  10. Posting-number: Volume 28, Issue 86
  11. Archive-name: ephem/part03
  12. Environment: UNIX, VMS, DOS, MAC
  13. Supersedes: ephem-4.21: Volume 14, Issue 76-81
  14.  
  15. #! /bin/sh
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  19. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  20. # Contents:  io.c objx.c
  21. # Wrapped by kent@sparky on Tue Mar 10 14:34:05 1992
  22. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  23. echo If this archive is complete, you will see the following message:
  24. echo '          "shar: End of archive 3 (of 9)."'
  25. if test -f 'io.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'io.c'\"
  27. else
  28.   echo shar: Extracting \"'io.c'\" \(21617 characters\)
  29.   sed "s/^X//" >'io.c' <<'END_OF_FILE'
  30. X/* this file (in principle) contains all the device-dependent code for
  31. X * handling screen movement and reading the keyboard. public routines are:
  32. X *   c_pos(r,c), c_erase(), c_eol();
  33. X *   chk_char(), read_char(), read_line (buf, max); and
  34. X *   byetty().
  35. X * N.B. we assume output may be performed by printf(), putchar() and
  36. X *   fputs(stdout). since these are buffered we flush first in read_char().
  37. X */
  38. X
  39. X/* explanation of various conditional #define options:
  40. X * UNIX: uses termcap for screen management.
  41. X *   USE_TERMIO: use termio.h to control tty modes.
  42. X *   USE_SGTTY: use sgtty.h to control tty modes.
  43. X *   USE_NDELAY: do non-blocking tty reads with fcntl(O_NDELAY).
  44. X *   USE_FIONREAD: do non-blocking tty reads with ioctl(FIONREAD).
  45. X *   USE_ATTSELECT: do non-blocking reads with att's select(2) (4 args).
  46. X *   USE_BSDSELECT: do non-blocking reads with bsd's select(2) (5 args).
  47. X * TURBO_C: compiles for Turbo C 2.0. I'm told it works for Lattice and
  48. X *     Microsoft too.
  49. X *   USE_ANSISYS: default PC cursor control uses direct BIOS calls (thanks to
  50. X *     Mr. Doug McDonald). If your PC does not work with this, however, add
  51. X *     "device ANSI.SYS" to your config.sys file and build ephem with
  52. X *     USE_ANSISYS.
  53. X * VMS: uses QIO for input, TERMTABLE info for output. This code uses only
  54. X *     standard VMS calls, i.e. it does not rely on any third-vendor termcap
  55. X *     package or the like. The code includes recoqnition of arrow keys, it
  56. X *     is easy to extend it to recoqnize other function keys. you don't
  57. X *     need to #define VMS since it is inherent in the compiler.
  58. X */
  59. X
  60. X/* unless you are on VMS define one of these... */
  61. X#define UNIX
  62. X/* #define TURBO_C */
  63. X
  64. X/* then if you defined UNIX you must use one of these ways to do non-blocking
  65. X * tty reads
  66. X */
  67. X#define USE_FIONREAD
  68. X/* #define USE_NDELAY */
  69. X/* #define USE_ATTSELECT */
  70. X/* #define USE_BSDSELECT */
  71. X
  72. X/* and then if you defined UNIX you must also use one of these ways to control
  73. X * the tty modes.
  74. X */
  75. X#define USE_TERMIO
  76. X/* #define USE_SGTTY */
  77. X
  78. X/* if you defined TURBO_C you might want this too if screen io looks garbled */
  79. X/* #define USE_ANSISYS */
  80. X
  81. X#include <stdio.h>
  82. X#include <ctype.h>
  83. X#include "screen.h"
  84. X
  85. X#ifdef UNIX
  86. X#include <signal.h>
  87. X#ifdef USE_TERMIO
  88. X#include <termio.h>
  89. X#endif
  90. X#ifdef USE_SGTTY
  91. X#include <sgtty.h>
  92. X#endif
  93. X#ifdef USE_BSDSELECT
  94. X#include <sys/time.h>
  95. X#endif
  96. X#ifdef USE_NDELAY
  97. X#include <fcntl.h>
  98. X#endif
  99. X
  100. Xextern char *tgoto();
  101. Xstatic char *cm, *ce, *cl, *ks, *ke, *kl, *kr, *ku, *kd; /* termcap sequences */
  102. Xstatic int tloaded;
  103. Xstatic int ttysetup;
  104. X#ifdef USE_TERMIO
  105. Xstatic struct termio orig_tio;
  106. X#endif
  107. X#ifdef USE_SGTTY
  108. Xstatic struct sgttyb orig_sgtty;
  109. X#endif
  110. X
  111. X/* move cursor to row, col, 1-based.
  112. X * we assume this also moves a visible cursor to this location.
  113. X */
  114. Xc_pos (r, c)
  115. Xint r, c;
  116. X{
  117. X    if (!tloaded) tload();
  118. X    fputs (tgoto (cm, c-1, r-1), stdout);
  119. X}
  120. X
  121. X/* erase entire screen. */
  122. Xc_erase()
  123. X{
  124. X    if (!tloaded) tload();
  125. X    fputs (cl, stdout);
  126. X}
  127. X
  128. X/* erase to end of line */
  129. Xc_eol()
  130. X{
  131. X    if (!tloaded) tload();
  132. X    fputs (ce, stdout);
  133. X}
  134. X
  135. X#ifdef USE_NDELAY
  136. Xstatic char sav_char;    /* one character read-ahead for chk_char() */
  137. X#endif
  138. X
  139. X/* return 0 if there is a char that may be read without blocking, else -1 */
  140. Xchk_char()
  141. X{
  142. X#ifdef USE_NDELAY
  143. X    if (!ttysetup) setuptty();
  144. X    fflush (stdout);
  145. X    if (sav_char)
  146. X        return (0);
  147. X    fcntl (0, F_SETFL, O_NDELAY);    /* non-blocking read. FNDELAY on BSD */
  148. X    if (read (0, &sav_char, 1) != 1)
  149. X        sav_char = 0;
  150. X    return (sav_char ? 0 : -1);
  151. X#endif
  152. X#ifdef USE_ATTSELECT
  153. X    int nfds, rfds, wfds, to;
  154. X    if (!ttysetup) setuptty();
  155. X    fflush (stdout);
  156. X    rfds = 1 << 0;    /* reads are on fd 0 */
  157. X    wfds = 0;    /* not interested in any write fds */
  158. X    nfds = 1;    /* check only fd 0 */
  159. X    to = 0;        /* don't delay - return 0 if nothing pending */
  160. X    return (select (nfds, &rfds, &wfds, to) == 0 ? -1 : 0);
  161. X#endif
  162. X#ifdef USE_BSDSELECT
  163. X    int nfds, rfds, wfds, xfds;
  164. X    struct timeval to;
  165. X    if (!ttysetup) setuptty();
  166. X    fflush (stdout);
  167. X    rfds = 1 << 0;    /* reads are on fd 0 */
  168. X    wfds = 0;    /* not interested in any write fds */
  169. X    xfds = 0;    /* not interested in any exception fds */
  170. X    nfds = 1;    /* check only fd 0 */
  171. X    to.tv_sec = 0;    /* don't delay - return 0 if nothing pending */
  172. X    to.tv_usec = 0;    /* don't delay - return 0 if nothing pending */
  173. X    return (select (nfds, &rfds, &wfds, &xfds, &to) == 0 ? -1 : 0);
  174. X#endif
  175. X#ifdef USE_FIONREAD
  176. X    long n;
  177. X    if (!ttysetup) setuptty();
  178. X    fflush (stdout);
  179. X    ioctl (0, FIONREAD, &n);
  180. X    return (n > 0 ? 0 : -1);
  181. X#endif
  182. X}
  183. X
  184. X/* read the next char, blocking if necessary, and return it. don't echo.
  185. X * map the arrow keys if we can too into hjkl
  186. X */
  187. Xread_char()
  188. X{
  189. X    char c;
  190. X    if (!ttysetup) setuptty();
  191. X    fflush (stdout);
  192. X#ifdef USE_NDELAY
  193. X    fcntl (0, F_SETFL, 0);    /* blocking read */
  194. X    if (sav_char) {
  195. X        c = sav_char;
  196. X        sav_char = 0;
  197. X    } else
  198. X#endif
  199. X        read (0, &c, 1);
  200. X    c = chk_arrow (c & 0177); /* just ASCII, please */
  201. X    return (c);
  202. X}
  203. X
  204. X/* used to time out of a read */
  205. Xstatic got_alrm;
  206. Xstatic
  207. Xon_alrm()
  208. X{
  209. X    got_alrm = 1;
  210. X}
  211. X
  212. X/* see if c is the first of any of the termcap arrow key sequences.
  213. X * if it is, read the rest of the sequence, and return the hjkl code
  214. X * that corresponds.
  215. X * if no match, just return c.
  216. X */
  217. Xstatic 
  218. Xchk_arrow (c)
  219. Xregister char c;
  220. X{
  221. X    register char *seq;
  222. X
  223. X    if (kl && kd && ku && kr &&
  224. X        (c == *(seq = kl) || c == *(seq = kd) || c == *(seq = ku)
  225. X                         || c == *(seq = kr))) {
  226. X        char seqa[32]; /* maximum arrow escape sequence ever expected */
  227. X        unsigned l = strlen(seq);
  228. X        seqa[0] = c;
  229. X        if (l > 1) {
  230. X        extern unsigned alarm();
  231. X        /* cautiously read rest of arrow sequence */
  232. X        got_alrm = 0;
  233. X        (void) signal (SIGALRM, on_alrm);
  234. X        alarm(2);
  235. X        read (0, seqa+1, l-1);
  236. X        alarm(0);
  237. X        if (got_alrm)
  238. X            return (c);
  239. X        }
  240. X        seqa[l] = '\0';
  241. X        if (strcmp (seqa, kl) == 0)
  242. X        return ('h');
  243. X        if (strcmp (seqa, kd) == 0)
  244. X        return ('j');
  245. X        if (strcmp (seqa, ku) == 0)
  246. X        return ('k');
  247. X        if (strcmp (seqa, kr) == 0)
  248. X        return ('l');
  249. X    }
  250. X    return (c);
  251. X}
  252. X
  253. X/* do whatever might be necessary to get the screen and/or tty back into shape.
  254. X */
  255. Xbyetty()
  256. X{
  257. X    /* if keypad mode switch is used, turn it off now */
  258. X    if (ke) {
  259. X        fputs (ke, stdout);
  260. X        fflush (stdout);
  261. X    }
  262. X
  263. X#ifdef USE_TERMIO
  264. X    ioctl (0, TCSETA, &orig_tio);
  265. X#endif
  266. X#ifdef USE_SGTTY
  267. X    ioctl (0, TIOCSETP, &orig_sgtty);
  268. X#endif
  269. X#ifdef USE_NDELAY
  270. X    fcntl (0, F_SETFL, 0);    /* be sure to go back to blocking read */
  271. X#endif
  272. X    ttysetup = 0;
  273. X}
  274. X
  275. Xstatic 
  276. Xtload()
  277. X{
  278. X    extern char *getenv(), *tgetstr();
  279. X    extern char *UP, *BC;
  280. X    char *egetstr();
  281. X    static char tbuf[512];
  282. X    char rawtbuf[1024];
  283. X    char *tp;
  284. X    char *ptr;
  285. X
  286. X    if (!(tp = getenv ("TERM"))) {
  287. X        printf ("no TERM\n");
  288. X        exit(1);
  289. X    }
  290. X    if (tgetent (rawtbuf, tp) != 1) {
  291. X        printf ("Can't find termcap for %s\n", tp);
  292. X        exit (1);
  293. X    }
  294. X
  295. X    ptr = tbuf;
  296. X
  297. X    ku = egetstr ("ku", &ptr);
  298. X    kd = egetstr ("kd", &ptr);
  299. X    kl = egetstr ("kl", &ptr);
  300. X    kr = egetstr ("kr", &ptr);
  301. X
  302. X    if (!(cm = egetstr ("cm", &ptr))) {
  303. X        printf ("No termcap cm code\n");
  304. X        exit(1);
  305. X    }
  306. X    if (!(ce = egetstr ("ce", &ptr))) {
  307. X        printf ("No termcap ce code\n");
  308. X        exit(1);
  309. X    }
  310. X    if (!(cl = egetstr ("cl", &ptr))) {
  311. X        printf ("No termcap cl code\n");
  312. X        exit(1);
  313. X    }
  314. X
  315. X    UP = egetstr ("up", &ptr);
  316. X    if (!tgetflag ("bs"))
  317. X        BC = egetstr ("bc", &ptr);
  318. X    
  319. X    if (!ttysetup) setuptty();
  320. X
  321. X    /* if keypad mode switch is used, do it now */
  322. X    if (ks = egetstr ("ks", &ptr)) {
  323. X        ke = egetstr ("ke", &ptr);
  324. X        fputs (ks, stdout);
  325. X        fflush (stdout);
  326. X    }
  327. X
  328. X    tloaded = 1;
  329. X}
  330. X
  331. X/* like tgetstr() but discard termcap delay codes, for now anyways */
  332. Xstatic char *
  333. Xegetstr (name, sptr)
  334. Xchar *name;
  335. Xchar **sptr;
  336. X{
  337. X    extern char *tgetstr();
  338. X    char *s;
  339. X
  340. X    if (s = tgetstr (name, sptr)) {
  341. X        char c;
  342. X        while ((c = *s) == '*' || isdigit(c))
  343. X        s += 1;
  344. X    }
  345. X    return (s);
  346. X}
  347. X
  348. X/* set up tty for char-by-char read, non-blocking  */
  349. Xstatic
  350. Xsetuptty()
  351. X{
  352. X#ifdef USE_TERMIO
  353. X    struct termio tio;
  354. X
  355. X    ioctl (0, TCGETA, &orig_tio);
  356. X    tio = orig_tio;
  357. X    tio.c_iflag &= ~ICRNL;    /* leave CR unchanged */
  358. X    tio.c_oflag &= ~OPOST;    /* no output processing */
  359. X    tio.c_lflag &= ~(ICANON|ECHO); /* no input processing, no echo */
  360. X    tio.c_cc[VMIN] = 1;    /* return after each char */
  361. X    tio.c_cc[VTIME] = 0;    /* no read timeout */
  362. X    ioctl (0, TCSETA, &tio);
  363. X#endif
  364. X#ifdef USE_SGTTY
  365. X    struct sgttyb sg;
  366. X
  367. X    ioctl (0, TIOCGETP, &orig_sgtty);
  368. X    sg = orig_sgtty;
  369. X    sg.sg_flags &= ~ECHO;    /* do our own echoing */
  370. X    sg.sg_flags &= ~CRMOD;    /* leave CR and LF unchanged */
  371. X    sg.sg_flags |= XTABS;    /* no tabs with termcap */
  372. X    sg.sg_flags |= CBREAK;    /* wake up on each char but can still kill */
  373. X    ioctl (0, TIOCSETP, &sg);
  374. X#endif
  375. X    ttysetup = 1;
  376. X}
  377. X/* end of #ifdef UNIX */
  378. X#endif
  379. X
  380. X#ifdef TURBO_C
  381. X#ifdef USE_ANSISYS
  382. X#define    ESC    '\033'
  383. X/* position cursor.
  384. X * (ANSI: ESC [ r ; c f) (r/c are numbers given in ASCII digits)
  385. X */
  386. Xc_pos (r, c)
  387. Xint r, c;
  388. X{
  389. X    printf ("%c[%d;%df", ESC, r, c);
  390. X}
  391. X
  392. X/* erase entire screen. (ANSI: ESC [ 2 J) */
  393. Xc_erase()
  394. X{
  395. X    printf ("%c[2J", ESC);
  396. X}
  397. X
  398. X/* erase to end of line. (ANSI: ESC [ K) */
  399. Xc_eol()
  400. X{
  401. X    printf ("%c[K", ESC);
  402. X}
  403. X#else
  404. X#include <dos.h>   
  405. Xunion REGS rg;
  406. X
  407. X/* position cursor.
  408. X */
  409. Xc_pos (r, c)
  410. Xint r, c;
  411. X{
  412. X        rg.h.ah = 2;
  413. X        rg.h.bh = 0;
  414. X        rg.h.dh = r-1;
  415. X        rg.h.dl = c-1;
  416. X        int86(16,&rg,&rg);
  417. X}
  418. X
  419. X/* erase entire screen.  */
  420. Xc_erase()
  421. X{
  422. X        int cur_cursor, i;
  423. X        rg.h.ah = 3;
  424. X        rg.h.bh = 0;
  425. X        int86(16,&rg,&rg);
  426. X        cur_cursor = rg.x.dx;
  427. X        for(i = 0; i < 25; i++){
  428. X            c_pos(i+1,1);
  429. X            rg.h.ah = 10;
  430. X            rg.h.bh = 0;
  431. X            rg.h.al = 32;
  432. X            rg.x.cx = 80;
  433. X            int86(16,&rg,&rg);
  434. X        }
  435. X        rg.h.ah = 2;
  436. X        rg.h.bh = 0;
  437. X        rg.x.dx = cur_cursor;
  438. X        int86(16,&rg,&rg);
  439. X        
  440. X}
  441. X
  442. X/* erase to end of line.*/
  443. Xc_eol()
  444. X{
  445. X        int cur_cursor, i;
  446. X        rg.h.ah = 3;
  447. X        rg.h.bh = 0;
  448. X        int86(16,&rg,&rg);
  449. X        cur_cursor = rg.x.dx;
  450. X        rg.h.ah = 10;
  451. X        rg.h.bh = 0;
  452. X        rg.h.al = 32;
  453. X        rg.x.cx = 80 - rg.h.dl;
  454. X        int86(16,&rg,&rg);
  455. X        rg.h.ah = 2;
  456. X        rg.h.bh = 0;
  457. X        rg.x.dx = cur_cursor;
  458. X        int86(16,&rg,&rg);
  459. X
  460. X}
  461. X#endif
  462. X
  463. X/* return 0 if there is a char that may be read without blocking, else -1 */
  464. Xchk_char()
  465. X{
  466. X    return (kbhit() == 0 ? -1 : 0);
  467. X}
  468. X
  469. X/* read the next char, blocking if necessary, and return it. don't echo.
  470. X * map the arrow keys if we can too into hjkl
  471. X */
  472. Xread_char()
  473. X{
  474. X    int c;
  475. X    fflush (stdout);
  476. X    c = getch();
  477. X    if (c == 0) {
  478. X        /* get scan code; convert to direction hjkl if possible */
  479. X        c = getch();
  480. X        switch (c) {
  481. X        case 0x4b: c = 'h'; break;
  482. X        case 0x50: c = 'j'; break;
  483. X        case 0x48: c = 'k'; break;
  484. X        case 0x4d: c = 'l'; break;
  485. X        }
  486. X    }
  487. X    return (c);
  488. X}
  489. X
  490. X/* do whatever might be necessary to get the screen and/or tty back into shape.
  491. X */
  492. Xbyetty()
  493. X{
  494. X}
  495. X/* end of #ifdef TURBO_C */
  496. X#endif
  497. X
  498. X#ifdef VMS
  499. X#include <string.h>
  500. X#include <iodef.h>
  501. X#include <descrip.h>
  502. X#include <dvidef.h>
  503. X#include <smgtrmptr.h>
  504. X#include <starlet.h>
  505. X#include <lib$routines.h>
  506. X#include <smg$routines.h>
  507. X/* Structured types for use in system calls */
  508. Xtypedef struct{
  509. X    unsigned short status;
  510. X    unsigned short count;
  511. X    unsigned int info;
  512. X} io_status_block;
  513. Xtypedef struct{
  514. X    unsigned short buffer_length;
  515. X    unsigned short item_code;
  516. X    void *buffer_address;
  517. X    unsigned short *return_length_address;
  518. X    unsigned long terminator;
  519. X} item_list;
  520. Xstatic unsigned short ttchan = 0; /* channel number for terminal    */
  521. Xvolatile static io_status_block iosb; /* I/O status block for operation */
  522. X                                      /* currently in progress          */
  523. Xvolatile static unsigned char input_buf; /* buffer to recieve input charac-*/
  524. X                                         /* ter when operation completes   */
  525. Xstatic void *term_entry;          /* pointer to TERMTABLE entry     */
  526. X#define MAXCAP 10
  527. Xstatic char ce[MAXCAP];           /* ce and cl capability strings for  */
  528. Xstatic char cl[MAXCAP];           /* this terminal type                */
  529. X/* Declaration of special keys to be recoqnized on input */
  530. X/* Number of special keys defined */
  531. X#define MAXKEY 4
  532. X/* TERMTABLE capability codes for the keys */
  533. Xstatic long capcode[MAXKEY] = {SMG$K_KEY_UP_ARROW,SMG$K_KEY_DOWN_ARROW,
  534. X    SMG$K_KEY_RIGHT_ARROW,SMG$K_KEY_LEFT_ARROW};
  535. X/* character codes to be returned by read_char when a special key is presssed */
  536. Xstatic int retcode[MAXKEY] = {'k','j','l','h'};
  537. X/* the actual capability strings from the key */
  538. Xstatic char keycap[MAXKEY][MAXCAP];
  539. Xstatic char special_buffer[MAXCAP];   /* buffer for reading special key */
  540. Xstatic int chars_in_buffer;           /* number of characters in buffer */
  541. X/* set up the structures for this I/O module */
  542. Xinittt()
  543. X{
  544. X    unsigned int status;   /* system routine return status */
  545. X    $DESCRIPTOR(tt,"TT");  /* terminal name */
  546. X    item_list itmlst;      /* item list for $getdvi obtaining term type */
  547. X    unsigned long devtype; /* terminal type returned form $getdvi */
  548. X    unsigned short retlen; /* return length from $getdvi */
  549. X    unsigned long lenret;  /* return length from smg$get_term_data */
  550. X    unsigned long maxlen;  /* maximum return length */
  551. X    unsigned long cap_code;/* capability code */
  552. X#define MAXINIT 20
  553. X    char init_string[MAXINIT];/* string to initialize terminal */
  554. X    int key;
  555. X    /* Assign a channel to the terminal */
  556. X    if (!((status = sys$assign(&tt,&ttchan,0,0))&1)) lib$signal(status);
  557. X    /* Get terminal type. Note that it is possible to use the same
  558. X     * iosb at this stage, because no I/O is initiated yet.
  559. X     */
  560. X    itmlst.buffer_length = 4;
  561. X    itmlst.item_code = DVI$_DEVTYPE;
  562. X    itmlst.buffer_address = &devtype;
  563. X    itmlst.return_length_address = &retlen;
  564. X    itmlst.terminator = 0;
  565. X    if (!((status = sys$getdviw(0,ttchan,0,&itmlst,&iosb,0,0,0))&1))
  566. X        lib$signal(status);
  567. X    if (!(iosb.status&1)) lib$signal(iosb.status);
  568. X    /* Get the TERMTABLE entry corresponding to the terminal type */
  569. X    if (!((status = smg$init_term_table_by_type(&devtype,
  570. X        &term_entry))&1)) lib$signal(status);
  571. X    /* Get the initialisation string and initialize terminal */
  572. X    cap_code = SMG$K_INIT_STRING;
  573. X    maxlen = MAXINIT - 1;
  574. X    if (!((status = smg$get_term_data(&term_entry,&cap_code,&maxlen,
  575. X        &lenret,init_string))&1)) lib$signal(status);
  576. X    init_string[lenret] = '\0';
  577. X    fputs(init_string,stdout);
  578. X    fflush(stdout);
  579. X    /* Get ce and cl capabilities, these are static */
  580. X    cap_code = SMG$K_ERASE_TO_END_LINE;
  581. X    maxlen = MAXCAP-1;
  582. X    if (!((status = smg$get_term_data(&term_entry,&cap_code,&maxlen,
  583. X        &lenret,ce))&1)) lib$signal(status);
  584. X    ce[lenret] = '\0';
  585. X    cap_code = SMG$K_ERASE_WHOLE_DISPLAY;
  586. X    maxlen = MAXCAP-1;
  587. X    if (!((status = smg$get_term_data(&term_entry,&cap_code,&maxlen,
  588. X        &lenret,cl))&1)) lib$signal(status);
  589. X    cl[lenret] = '\0';
  590. X    /* Here one could obtain line drawing sequences, please feel free
  591. X       to implement it ... */
  592. X    /* Get special keys to be recoqnized on input */
  593. X    for (key = 0;key<MAXKEY;key++)
  594. X    {
  595. X        maxlen = MAXCAP-1;
  596. X        if (!((status = smg$get_term_data(&term_entry,&capcode[key],
  597. X            &maxlen,&lenret,keycap[key]))&1)) lib$signal(status);
  598. X        keycap[key][lenret] = '\0';
  599. X    }
  600. X    /* Initiate first input operation, NOECHO.
  601. X     * NOFILTR allows any character to get through, this makes it
  602. X     * possible to implement arrow recoqnition, and also makes
  603. X     * DEL and BS get through.
  604. X     * We don't wait for the operation to complete.
  605. X     * Note that stdout has already been fflush'ed above.
  606. X     */
  607. X    if (!((status = sys$qio(0,ttchan,
  608. X        IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
  609. X        &iosb,0,0,&input_buf,1,0,0,0,0))&1)) lib$signal(status);
  610. X    /* Initialise special key buffer */
  611. X    chars_in_buffer = 0;
  612. X} /* inittt */
  613. X/* return 0 if there is a char that may be read without blocking, else -1 */
  614. Xchk_char()
  615. X{
  616. X    if (!ttchan) inittt();
  617. X        return ( chars_in_buffer != 0 ? 0 :(iosb.status == 0 ? -1 : 0));
  618. X}
  619. X/* read the next char, blocking if necessary, and return it. don't echo.
  620. X * map the arrow keys if we can too into hjkl
  621. X */
  622. Xread_char()
  623. X{
  624. X    unsigned int status;
  625. X    int buf;
  626. X    int i;
  627. X    int found_key;
  628. X    int key;
  629. X    int this_len;
  630. X    int match;
  631. X    if (!ttchan) inittt();
  632. X    /* If we attempted to read an special key previously, there are characters
  633. X     * left in the buffer, return these before doing more I/O
  634. X     */
  635. X    if (chars_in_buffer!=0){
  636. X        buf = special_buffer[0];
  637. X        chars_in_buffer--;
  638. X        for (i = 0;i<chars_in_buffer;i++)
  639. X        {
  640. X            special_buffer[i] = special_buffer[i+1];
  641. X        }
  642. X        special_buffer[chars_in_buffer] = '\0';
  643. X    }
  644. X    else {
  645. X        /* Loop over characters read, the loop is terminated when the
  646. X         * characters read so far do not match any of the special keys
  647. X         * or when the characters read so far is identical to one of
  648. X         * the special keys.
  649. X         */
  650. X        do
  651. X        {
  652. X            /* Wait for I/O to complete */
  653. X            if (!((status = sys$synch(0,&iosb))&1)) lib$signal(status);
  654. X            special_buffer[chars_in_buffer] = input_buf;
  655. X            chars_in_buffer++;
  656. X            special_buffer[chars_in_buffer] = '\0';
  657. X            /* Initiate next input operation */
  658. X            fflush (stdout);
  659. X            if (!((status = sys$qio(0,ttchan,
  660. X                IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
  661. X                &iosb,0,0,&input_buf,1,0,0,0,0))&1)) lib$signal(status);
  662. X            /* Check for match with all special strings */
  663. X            match = 0;
  664. X            found_key = MAXKEY;
  665. X            for (key = 0;key<MAXKEY;key++)
  666. X            {
  667. X                this_len = strlen(keycap[key]);
  668. X                if (this_len<chars_in_buffer) continue;
  669. X                if (!strncmp(keycap[key],special_buffer,chars_in_buffer)){
  670. X                    match = -1;
  671. X                    if (this_len == chars_in_buffer){
  672. X                        found_key = key;
  673. X                        break;
  674. X                    }
  675. X                }
  676. X            }
  677. X        }
  678. X        while (match && (found_key == MAXKEY));
  679. X        /* If one of the keys matches the input string, return the
  680. X         * corresponding  key code
  681. X         */
  682. X        if (found_key != MAXKEY)
  683. X        {
  684. X            buf = retcode[found_key];
  685. X            chars_in_buffer = 0;
  686. X        }
  687. X        else /* return first character and store the rest in the buffer */
  688. X        {
  689. X            buf = special_buffer[0];
  690. X            chars_in_buffer--;
  691. X            for (i = 0;i<chars_in_buffer;i++)
  692. X            {
  693. X                special_buffer[i] = special_buffer[i+1];
  694. X            }
  695. X        }
  696. X        special_buffer[chars_in_buffer] = '\0';
  697. X    }
  698. X    return(buf);
  699. X}
  700. X/* do whatever might be necessary to get the screen and/or tty back into shape.
  701. X */
  702. Xbyetty()
  703. X{
  704. X    unsigned int status;
  705. X    if (ttchan)
  706. X    {
  707. X        /* There is no string in SMG to send to the terminal when
  708. X         * terminating, one could clear the screen, move the cursor to
  709. X         * the last line, or whatever. This program clears the screen
  710. X         * anyway before calling this routine, so we do nothing.
  711. X         */
  712. X        /* The following is not really neccessary, it will be done at program
  713. X         * termination anyway, but if someone tries to use the I/O routines agai
  714. X   n
  715. X         * it might prove useful...
  716. X         */
  717. X        if (!((status = smg$del_term_table())&1)) lib$signal(status);
  718. X        if (!((status = sys$dassgn(ttchan))&1)) lib$signal(status);
  719. X        /* This also cancels any outstanding I/O on the channel */
  720. X        ttchan = 0; /* marks terminal I/O as not initialized */
  721. X    }
  722. X}
  723. X/* position cursor. */
  724. Xc_pos (r, c)
  725. Xint r, c;
  726. X{
  727. X    unsigned long vector[3]; /* argument vector (position)   */
  728. X    unsigned long status;    /* system service return status */
  729. X    long lenret;             /* length of returned string    */
  730. X    long maxlen;             /* maximum return length        */
  731. X    unsigned long capcode;   /* capability code              */
  732. X    char seq[2*MAXCAP];      /* returned string              */
  733. X    if (!ttchan) inittt();
  734. X    /* Set cursor depends on the position, therefore we have to call
  735. X     * get_term_data for each operation
  736. X     */
  737. X    vector[0] = 2;
  738. X    vector[1] = r;
  739. X    vector[2] = c;
  740. X    capcode = SMG$K_SET_CURSOR_ABS;
  741. X    maxlen = 2*MAXCAP-1;
  742. X    if (!((status = smg$get_term_data(&term_entry,&capcode,&maxlen,
  743. X        &lenret,seq,vector))&1)) lib$signal(status);
  744. X    seq[lenret] = '\0';
  745. X    fputs(seq,stdout);
  746. X}
  747. X/* erase entire screen. */
  748. Xc_erase()
  749. X{
  750. X    if (!ttchan) inittt();
  751. X    fputs(cl,stdout);
  752. X}
  753. X/* erase to end of line. */
  754. Xc_eol()
  755. X{
  756. X    if (!ttchan) inittt();
  757. X    fputs(ce,stdout);
  758. X}
  759. X/* end of #ifdef VMS */
  760. X#endif
  761. X
  762. X/* read up to max chars into buf, with cannonization.
  763. X * add trailing '\0' (buf is really max+1 chars long).
  764. X * return count of chars read (not counting '\0').
  765. X * assume cursor is already positioned as desired.
  766. X * if type END when n==0 then return -1.
  767. X */
  768. Xread_line (buf, max)
  769. Xchar buf[];
  770. Xint max;
  771. X{
  772. X    static char erase[] = "\b \b";
  773. X    int n, c;
  774. X    int done;
  775. X
  776. X#ifdef UNIX
  777. X    if (!ttysetup) setuptty();
  778. X#endif
  779. X
  780. X    for (done = 0, n = 0; !done; )
  781. X        switch (c = read_char()) {    /* does not echo */
  782. X        case cntrl('h'):    /* backspace or */
  783. X        case 0177:        /* delete are each char erase */
  784. X        if (n > 0) {
  785. X            fputs (erase, stdout);
  786. X            n -= 1;
  787. X        }
  788. X        break;
  789. X        case cntrl('u'):        /* line erase */
  790. X        while (n > 0) {
  791. X            fputs (erase, stdout);
  792. X            n -= 1;
  793. X        }
  794. X        break;
  795. X        case '\r':    /* EOL */
  796. X        done++;
  797. X        break;
  798. X        default:            /* echo and store, if ok */
  799. X        if (n == 0 && c == END)
  800. X            return (-1);
  801. X        if (n >= max)
  802. X            putchar (cntrl('g'));
  803. X        else if (isprint(c)) {
  804. X            putchar (c);
  805. X            buf[n++] = c;
  806. X        }
  807. X        }
  808. X
  809. X    buf[n] = '\0';
  810. X    return (n);
  811. X}
  812. END_OF_FILE
  813.   if test 21617 -ne `wc -c <'io.c'`; then
  814.     echo shar: \"'io.c'\" unpacked with wrong size!
  815.   fi
  816.   # end of 'io.c'
  817. fi
  818. if test -f 'objx.c' -a "${1}" != "-c" ; then 
  819.   echo shar: Will not clobber existing file \"'objx.c'\"
  820. else
  821.   echo shar: Extracting \"'objx.c'\" \(29454 characters\)
  822.   sed "s/^X//" >'objx.c' <<'END_OF_FILE'
  823. X/* functions to save the user-definable objects, referred to as "x" and "y".
  824. X * this way, once defined, the objects can be quieried for position just like
  825. X * the other bodies, with obj_cir(). 
  826. X */
  827. X
  828. X#include <stdio.h>
  829. X#include <math.h>
  830. X#include <ctype.h>
  831. X#ifdef VMS
  832. X#include <stdlib.h>
  833. X#endif
  834. X#include "astro.h"
  835. X#include "circum.h"
  836. X#include "screen.h"
  837. X
  838. Xextern char *strcat(), *strcpy(), *strncpy(), *getenv();
  839. X
  840. Xstatic char *dbfile;            /* !0 if set by -d option */
  841. Xstatic char dbfdef[] = "ephem.db";     /* default database file name */
  842. X
  843. X/* structures to describe objects of various types.
  844. X */
  845. X#define    MAXNM        16    /* longest allowed object name, inc \0 */
  846. Xtypedef struct {
  847. X    double m_m1, m_m2;    /* either g/k or H/G, depending on... */
  848. X    int m_whichm;    /* one of MAG_gk or MAG_HG */
  849. X} Mag;
  850. Xtypedef struct {
  851. X    double f_ra;    /* ra, rads, at given epoch */
  852. X    double f_dec;    /* dec, rads, at given epoch */
  853. X    double f_mag;    /* visual magnitude */
  854. X    double f_siz;    /* angular size, in arc seconds */
  855. X    double f_epoch;    /* the given epoch, as an mjd */
  856. X    char   f_name[MAXNM]; /* name */
  857. X} ObjF;            /* fixed object */
  858. Xtypedef struct {
  859. X    double e_inc;    /* inclination, degrees */
  860. X    double e_Om;    /* longitude of ascending node, degrees */
  861. X    double e_om;    /* argument of perihelion, degress */
  862. X    double e_a;        /* mean distance, aka, semi-maj axis, in AU */
  863. X    double e_n;        /* daily motion, degrees/day */
  864. X    double e_e;        /* eccentricity */
  865. X    double e_M;        /* mean anomaly, ie, degrees from perihelion at... */
  866. X    double e_cepoch;    /* epoch date (M reference), as an mjd */
  867. X    double e_epoch;    /* equinox year (inc/Om/om reference), as an mjd */
  868. X    Mag    e_mag;    /* magnitude */
  869. X    double e_siz;    /* angular size, in arc seconds at 1 AU */
  870. X    char   e_name[MAXNM]; /* name */
  871. X} ObjE;            /* object in heliocentric elliptical orbit */
  872. Xtypedef struct {
  873. X    double h_ep;    /* epoch of perihelion, as an mjd */
  874. X    double h_inc;    /* inclination, degs */
  875. X    double h_Om;    /* longitude of ascending node, degs */
  876. X    double h_om;    /* argument of perihelion, degs. */
  877. X    double h_e;        /* eccentricity */
  878. X    double h_qp;    /* perihelion distance, AU */
  879. X    double h_epoch;    /* equinox year (inc/Om/om reference), as an mjd */
  880. X    double h_g, h_k;    /* magnitude model coefficients */
  881. X    double h_siz;    /* angular size, in arc seconds at 1 AU */
  882. X    char   h_name[MAXNM]; /* name */
  883. X} ObjH;            /* object in heliocentric parabolic trajectory */
  884. Xtypedef struct {
  885. X    double p_ep;    /* epoch of perihelion, as an mjd */
  886. X    double p_inc;    /* inclination, degs */
  887. X    double p_qp;    /* perihelion distance, AU */
  888. X    double p_om;    /* argument of perihelion, degs. */
  889. X    double p_Om;    /* longitude of ascending node, degs */
  890. X    double p_epoch;    /* reference epoch, as an mjd */
  891. X    double p_g, p_k;    /* magnitude model coefficients */
  892. X    double p_siz;    /* angular size, in arc seconds at 1 AU */
  893. X    char   p_name[MAXNM]; /* name */
  894. X} ObjP;            /* object in heliocentric parabolic trajectory */
  895. X
  896. Xtypedef struct {
  897. X    int  o_type;    /* current object type; see flags, below */
  898. X    int  o_on;        /* !=0 while current object is active */
  899. X    ObjF o_f;        /* the fixed object */
  900. X    ObjE o_e;        /* the elliptical orbit object */
  901. X    ObjH o_h;        /* the hyperbolic orbit object */
  902. X    ObjP o_p;        /* the parabolic orbit object */
  903. X} Obj;
  904. X
  905. X/* o_type */
  906. X#define    FIXED        1
  907. X#define    ELLIPTICAL    2
  908. X#define    HYPERBOLIC    3
  909. X#define    PARABOLIC    4
  910. X
  911. X/* m_whichm */
  912. X#define    MAG_HG        0    /* using 0 makes HG the initial default */
  913. X#define    MAG_gk        1
  914. X
  915. Xstatic Obj objx;
  916. Xstatic Obj objy;
  917. X
  918. X#define    DY    0        /* decimal year flag for set_year() */
  919. X#define    YMD    1        /* year/mon/day flag for set_year() */
  920. X
  921. X/* run when Objx or y is picked from menu.
  922. X * we tell which by the planet code.
  923. X * let op define object and turn it on and off.
  924. X */
  925. Xobj_setup(p)
  926. Xint p;
  927. X{
  928. X    static char *pr[6] = { /* leave a slot for "On"/"Off" */
  929. X        "Fixed", "Elliptical", "Hyperbolic", "Parabolic", "Lookup"
  930. X    };
  931. X    int f;
  932. X    Obj *op;
  933. X
  934. X    op = (p == OBJX) ? &objx : &objy;
  935. X
  936. X    rechk:
  937. X    /* map o_type to popup choice.
  938. X     */
  939. X    switch (op->o_type) {
  940. X    case FIXED: f = 0; break;
  941. X    case ELLIPTICAL: f = 1; break;
  942. X    case HYPERBOLIC: f = 2; break;
  943. X    case PARABOLIC: f = 3; break;
  944. X    default: f = 4; break;
  945. X    }
  946. X
  947. X    ask:
  948. X    pr[5] = op->o_on ? "On" : "Off";
  949. X    switch (f = popup (pr, f, 6)) {
  950. X    case 0: obj_dfixed(op, 0, (char**)0); goto ask;
  951. X    case 1: obj_delliptical(op, 0, (char**)0); goto ask;
  952. X    case 2: obj_dhyperbolic(op, 0, (char**)0); goto ask;
  953. X    case 3: obj_dparabolic(op, 0, (char**)0); goto ask;
  954. X    case 4: if (obj_filelookup(p, (char *)0) == 0) obj_on(p); goto rechk;
  955. X    case 5: op->o_on ^= 1; break;
  956. X    }
  957. X}
  958. X
  959. X/* turn "on" or "off" but don't forget facts about object the object.
  960. X */
  961. Xobj_on (p)
  962. Xint p;
  963. X{
  964. X    if (p == OBJX)
  965. X        objx.o_on = 1;
  966. X    else
  967. X        objy.o_on = 1;
  968. X}
  969. Xobj_off (p)
  970. Xint p;
  971. X{
  972. X    if (p == OBJX)
  973. X        objx.o_on = 0;
  974. X    else
  975. X        objy.o_on = 0;
  976. X}
  977. X
  978. X/* return true if object is now on, else 0.
  979. X */
  980. Xobj_ison(p)
  981. Xint p;
  982. X{
  983. X    return ((p == OBJX) ? objx.o_on : objy.o_on);
  984. X}
  985. X
  986. X/* set an alternate database file name.
  987. X * N.B. we assume the storage pointed to by name is permanent.
  988. X */
  989. Xobj_setdbfilename (name)
  990. Xchar *name;
  991. X{
  992. X    dbfile = name;
  993. X}
  994. X
  995. X/* fill in info about object x or y.
  996. X * most arguments and conditions are the same as for plans().
  997. X * only difference is that mag is already apparent, not absolute magnitude.
  998. X * this is called by body_cir() for object x and y just like plans() is called
  999. X * for the planets.
  1000. X */
  1001. Xobj_cir (jd, p, lpd0, psi0, rp0, rho0, lam, bet, siz, mag)
  1002. Xdouble jd;    /* mjd now */
  1003. Xint p;        /* OBJX or OBJY */
  1004. Xdouble *lpd0;    /* heliocentric longitude, or NOHELIO  */
  1005. Xdouble *psi0;    /* heliocentric latitude, or 0 if *lpd0 set to NOHELIO */
  1006. Xdouble *rp0;    /* distance from the sun, or 0 */
  1007. Xdouble *rho0;    /* true distance from the Earth, or 0 */
  1008. Xdouble *lam;    /* apparent geocentric ecliptic longitude */
  1009. Xdouble *bet;    /* apparent geocentric ecliptic latitude */
  1010. Xdouble *siz;    /* angular size of object, arc seconds */
  1011. Xdouble *mag;    /* APPARENT magnitude */
  1012. X{
  1013. X    Obj *op = (p == OBJX) ? &objx : &objy;
  1014. X
  1015. X    switch (op->o_type) {
  1016. X    case FIXED: {
  1017. X        double xr, xd;
  1018. X        xr = op->o_f.f_ra;
  1019. X        xd = op->o_f.f_dec;
  1020. X        if (op->o_f.f_epoch != jd)
  1021. X        precess (op->o_f.f_epoch, jd, &xr, &xd);
  1022. X        eq_ecl (jd, xr, xd, bet, lam);
  1023. X
  1024. X        *lpd0 = NOHELIO;
  1025. X        *psi0 = *rp0 = *rho0 = 0.0;
  1026. X        *mag = op->o_f.f_mag;
  1027. X        *siz = op->o_f.f_siz;
  1028. X        }
  1029. X        break;
  1030. X
  1031. X    case ELLIPTICAL: {
  1032. X        /* this is basically the same code as pelement() and plans()
  1033. X         * combined and simplified for the special case of osculating
  1034. X         * (unperturbed) elements.
  1035. X         * inputs have been changed to match the Astronomical Almanac.
  1036. X         * we have added reduction of elements using reduce_elements().
  1037. X         */
  1038. X        double dt, lg, lsn, rsn;
  1039. X        double nu, ea;
  1040. X        double ma, rp, lo, slo, clo;
  1041. X        double inc, psi, spsi, cpsi;
  1042. X        double y, lpd, rpd, ll, rho, sll, cll;
  1043. X        double om;        /* arg of perihelion */
  1044. X        double Om;        /* long of ascending node. */
  1045. X        double e;
  1046. X        int pass;
  1047. X
  1048. X        dt = 0;
  1049. X        sunpos (jd, &lsn, &rsn);
  1050. X        lg = lsn + PI;
  1051. X        e = op->o_e.e_e;
  1052. X
  1053. X        for (pass = 0; pass < 2; pass++) {
  1054. X
  1055. X        reduce_elements (op->o_e.e_epoch, jd-dt, degrad(op->o_e.e_inc),
  1056. X                degrad (op->o_e.e_om), degrad (op->o_e.e_Om),
  1057. X                &inc, &om, &Om);
  1058. X
  1059. X        ma = degrad (op->o_e.e_M
  1060. X                + (jd - op->o_e.e_cepoch - dt) * op->o_e.e_n);
  1061. X        anomaly (ma, e, &nu, &ea);
  1062. X        rp = op->o_e.e_a * (1-e*e) / (1+e*cos(nu));
  1063. X        lo = nu + om;
  1064. X        slo = sin(lo);
  1065. X        clo = cos(lo);
  1066. X        spsi = slo*sin(inc);
  1067. X        y = slo*cos(inc);
  1068. X        psi = asin(spsi);
  1069. X        lpd = atan(y/clo)+Om;
  1070. X        if (clo<0) lpd += PI;
  1071. X        range (&lpd, 2*PI);
  1072. X        cpsi = cos(psi);
  1073. X        rpd = rp*cpsi;
  1074. X        ll = lpd-lg;
  1075. X        rho = sqrt(rsn*rsn+rp*rp-2*rsn*rp*cpsi*cos(ll));
  1076. X        dt = rho*5.775518e-3;    /* light travel time, in days */
  1077. X        if (pass == 0) {
  1078. X            *lpd0 = lpd;
  1079. X            *psi0 = psi;
  1080. X            *rp0 = rp;
  1081. X            *rho0 = rho;
  1082. X        }
  1083. X        }
  1084. X
  1085. X        sll = sin(ll);
  1086. X        cll = cos(ll);
  1087. X        if (rpd < rsn)
  1088. X        *lam = atan(-1*rpd*sll/(rsn-rpd*cll))+lg+PI;
  1089. X        else
  1090. X        *lam = atan(rsn*sll/(rpd-rsn*cll))+lpd;
  1091. X        range (lam, 2*PI);
  1092. X        *bet = atan(rpd*spsi*sin(*lam-lpd)/(cpsi*rsn*sll));
  1093. X
  1094. X        if (op->o_e.e_mag.m_whichm == MAG_HG) {
  1095. X        /* the H and G parameters from the Astro. Almanac.
  1096. X         */
  1097. X        double psi_t, Psi_1, Psi_2, beta;
  1098. X        beta = acos((rp*rp + rho*rho - rsn*rsn)/ (2*rp*rho));
  1099. X        psi_t = exp(log(tan(beta/2.0))*0.63);
  1100. X        Psi_1 = exp(-3.33*psi_t);
  1101. X        psi_t = exp(log(tan(beta/2.0))*1.22);
  1102. X        Psi_2 = exp(-1.87*psi_t);
  1103. X        *mag = op->o_e.e_mag.m_m1 + 5.0*log10(rp*rho)
  1104. X            - 2.5*log10((1-op->o_e.e_mag.m_m2)*Psi_1
  1105. X            + op->o_e.e_mag.m_m2*Psi_2);
  1106. X        } else {
  1107. X        /* the g/k model of comets */
  1108. X        *mag = op->o_e.e_mag.m_m1 + 5*log10(rho)
  1109. X                    + 2.5*op->o_e.e_mag.m_m2*log10(rp);
  1110. X        }
  1111. X        *siz = op->o_e.e_siz / rho;
  1112. X        }
  1113. X        break;
  1114. X
  1115. X    case HYPERBOLIC: {
  1116. X        double dt, lg, lsn, rsn;
  1117. X        double nu, ea;
  1118. X        double ma, rp, lo, slo, clo;
  1119. X        double inc, psi, spsi, cpsi;
  1120. X        double y, lpd, rpd, ll, rho, sll, cll;
  1121. X        double om;        /* arg of perihelion */
  1122. X        double Om;        /* long of ascending node. */
  1123. X        double e;
  1124. X        double a, n;    /* semi-major axis, mean daily motion */
  1125. X        int pass;
  1126. X
  1127. X        dt = 0;
  1128. X        sunpos (jd, &lsn, &rsn);
  1129. X        lg = lsn + PI;
  1130. X        e = op->o_h.h_e;
  1131. X        a = op->o_h.h_qp/(e - 1.0);
  1132. X        n = .98563/sqrt(a*a*a);
  1133. X
  1134. X        for (pass = 0; pass < 2; pass++) {
  1135. X
  1136. X        reduce_elements (op->o_h.h_epoch, jd-dt, degrad(op->o_h.h_inc),
  1137. X                degrad (op->o_h.h_om), degrad (op->o_h.h_Om),
  1138. X                &inc, &om, &Om);
  1139. X
  1140. X        ma = degrad ((jd - op->o_h.h_ep - dt) * n);
  1141. X        anomaly (ma, e, &nu, &ea);
  1142. X        rp = a * (e*e-1.0) / (1.0+e*cos(nu));
  1143. X        lo = nu + om;
  1144. X        slo = sin(lo);
  1145. X        clo = cos(lo);
  1146. X        spsi = slo*sin(inc);
  1147. X        y = slo*cos(inc);
  1148. X        psi = asin(spsi);
  1149. X        lpd = atan(y/clo)+Om;
  1150. X        if (clo<0) lpd += PI;
  1151. X        range (&lpd, 2*PI);
  1152. X        cpsi = cos(psi);
  1153. X        rpd = rp*cpsi;
  1154. X        ll = lpd-lg;
  1155. X        rho = sqrt(rsn*rsn+rp*rp-2*rsn*rp*cpsi*cos(ll));
  1156. X        dt = rho*5.775518e-3;    /* light travel time, in days */
  1157. X        if (pass == 0) {
  1158. X            *lpd0 = lpd;
  1159. X            *psi0 = psi;
  1160. X            *rp0 = rp;
  1161. X            *rho0 = rho;
  1162. X        }
  1163. X        }
  1164. X
  1165. X        sll = sin(ll);
  1166. X        cll = cos(ll);
  1167. X        if (rpd < rsn)
  1168. X        *lam = atan(-1*rpd*sll/(rsn-rpd*cll))+lg+PI;
  1169. X        else
  1170. X        *lam = atan(rsn*sll/(rpd-rsn*cll))+lpd;
  1171. X        range (lam, 2*PI);
  1172. X        *bet = atan(rpd*spsi*sin(*lam-lpd)/(cpsi*rsn*sll));
  1173. X
  1174. X        *mag = op->o_h.h_g + 5*log10(rho) + 2.5*op->o_h.h_k*log10(rp);
  1175. X        *siz = op->o_h.h_siz / rho;
  1176. X        }
  1177. X        break;
  1178. X
  1179. X    case PARABOLIC: {
  1180. X        double inc, om, Om;
  1181. X        double lpd, psi, rp, rho;
  1182. X        double dt;
  1183. X        int pass;
  1184. X
  1185. X        /* two passes to correct lam and bet for light travel time. */
  1186. X        dt = 0.0;
  1187. X        for (pass = 0; pass < 2; pass++) {
  1188. X        reduce_elements (op->o_p.p_epoch, jd-dt, degrad(op->o_p.p_inc),
  1189. X            degrad(op->o_p.p_om), degrad(op->o_p.p_Om), &inc, &om, &Om);
  1190. X        comet (jd-dt, op->o_p.p_ep, inc, om, op->o_p.p_qp, Om,
  1191. X                    &lpd, &psi, &rp, &rho, lam, bet);
  1192. X        if (pass == 0) {
  1193. X            *lpd0 = lpd;
  1194. X            *psi0 = psi;
  1195. X            *rp0 = rp;
  1196. X            *rho0 = rho;
  1197. X        }
  1198. X        dt = rho*5.775518e-3;    /* au to light-days */
  1199. X        }
  1200. X        *mag = op->o_p.p_g + 5*log10(rho) + 2.5*op->o_p.p_k*log10(rp);
  1201. X        *siz = op->o_p.p_siz / rho;
  1202. X        }
  1203. X        break;
  1204. X
  1205. X    default:
  1206. X        f_msg ((p == OBJX) ? "Obj X is not defined"
  1207. X                   : "Obj Y is not defined");
  1208. X        break;
  1209. X    }
  1210. X}
  1211. X
  1212. X/* define obj based on the ephem.db line, s.
  1213. X * p is one of OBJX or OBJY.
  1214. X * format: name,type,[other fields, as per corresponding ObjX typedef]
  1215. X * N.B. we replace all ',' within s with '\0' IN PLACE.
  1216. X * return 0 if ok, else print reason why not with f_msg() and return -1.
  1217. X */
  1218. Xobj_define (p, s)
  1219. Xint p;    /* OBJX or OBJY */
  1220. Xchar *s;
  1221. X{
  1222. X#define    MAXARGS    20
  1223. X    char *av[MAXARGS];    /* point to each field for easy reference */
  1224. X    char c;
  1225. X    int ac;
  1226. X    Obj *op = (p == OBJX) ? &objx : &objy;
  1227. X
  1228. X    /* parse into comma separated fields */
  1229. X    ac = 0;
  1230. X    av[0] = s;
  1231. X    do {
  1232. X        c = *s++;
  1233. X        if (c == ',' || c == '\0') {
  1234. X        s[-1] = '\0';
  1235. X        av[++ac] = s;
  1236. X        }
  1237. X    } while (c);
  1238. X
  1239. X    if (ac < 2) {
  1240. X        char buf[NC];
  1241. X        if (ac > 0)
  1242. X        (void) sprintf (buf, "No type for Object %s", av[0]);
  1243. X        else
  1244. X        (void) sprintf (buf, "No fields in %s", s);
  1245. X        f_msg (buf);
  1246. X        return (-1);
  1247. X    }
  1248. X
  1249. X    /* switch out on type of object - the second field */
  1250. X    switch (av[1][0]) {
  1251. X    case 'f':
  1252. X        if (ac != 6 && ac != 7) {
  1253. X        char buf[NC];
  1254. X        (void) sprintf(buf,
  1255. X            "Need ra,dec,mag,D[,siz] for fixed object %s", av[0]);
  1256. X        f_msg (buf);
  1257. X        return (-1);
  1258. X        }
  1259. X        obj_dfixed (op, ac, av);
  1260. X        break;
  1261. X
  1262. X    case 'e':
  1263. X        if (ac != 13 && ac != 14) {
  1264. X        char buf[NC];
  1265. X        (void) sprintf (buf,
  1266. X            "Need i,O,o,a,n,e,M,E,D,H/g,G/k[,siz] for elliptical object %s",
  1267. X                                    av[0]);
  1268. X        f_msg (buf);
  1269. X        return (-1);
  1270. X        }
  1271. X        obj_delliptical (op, ac, av);
  1272. X        break;
  1273. X
  1274. X    case 'h':
  1275. X        if (ac != 11 && ac != 12) {
  1276. X        char buf[NC];
  1277. X        (void) sprintf (buf,
  1278. X            "Need T,i,O,o,e,q,D,g,k[,siz] for hyperbolic object %s", av[0]);
  1279. X        f_msg (buf);
  1280. X        return (-1);
  1281. X        }
  1282. X        obj_dhyperbolic (op, ac, av);
  1283. X        break;
  1284. X
  1285. X    case 'p':
  1286. X        if (ac != 10 && ac != 11) {
  1287. X        char buf[NC];
  1288. X        (void) sprintf (buf,
  1289. X            "Need T,i,o,q,O,D,g,k[,siz] for parabolic object %s", av[0]);
  1290. X        f_msg (buf);
  1291. X        return (-1);
  1292. X        }
  1293. X        obj_dparabolic (op, ac, av);
  1294. X        break;
  1295. X
  1296. X    default: {
  1297. X        char buf[NC];
  1298. X        (void) sprintf (buf, "Unknown type for Object %s: %s",
  1299. X                                av[0], av[1]);
  1300. X        f_msg (buf);
  1301. X        return (-1);
  1302. X        }
  1303. X    }
  1304. X
  1305. X    return (0);
  1306. X}
  1307. X
  1308. X/* if name, then look it up in the ephem database file and set p.
  1309. X * else display a table of all objects and let op pick one.
  1310. X * p is either OBJX or OBJY.
  1311. X * if -d was used use it; else if EPHEMDB env set use it, else use default.
  1312. X * return 0 if successfully set object p, else -1.
  1313. X */
  1314. Xobj_filelookup (p, name)
  1315. Xint p;            /* OBJX or OBJY */
  1316. Xchar *name;
  1317. X{
  1318. X/* redefine RCTN,NTR,NTC for column-major order if you prefer */
  1319. X#define    NLR        (NR-1)        /* number of rows of names.
  1320. X                     * leave 1 for prompt
  1321. X                     */
  1322. X#define    LCW        9        /* screen columns per name */
  1323. X#define    NLC        9        /* total number of name columns */
  1324. X#define    NL        (NLR*NLC)    /* total number of names per screen */
  1325. X#define    RCTN(r,c)    ((r)*NLC+(c))    /* row/col to index */
  1326. X#define    NTR(n)        ((n)/NLC)    /* index to row */
  1327. X#define    NTC(n)        ((n)%NLC)    /* index to col (0 based) */
  1328. X                    /* N.B. all these are 0-based */
  1329. X    static char prompt[] =
  1330. X            "RETURN to select, p/n for previous/next page, q to quit";
  1331. X    FILE *fp;
  1332. X    char *fn;
  1333. X    int i, pgn;    /* index on current screen, current page number */
  1334. X    int r, c;
  1335. X    char buf[160];    /* longer than any one database line */
  1336. X    char pb[NC];    /* prompt buffer */
  1337. X    int readahd;    /* 1 if buffer set from previous loop */
  1338. X    int choice;    /* index to selection; -1 until set */
  1339. X    int roaming;    /* 1 while just roaming around screen */
  1340. X    int abandon;    /* 1 if decide to not pick afterall */
  1341. X
  1342. X    /* open the database file */
  1343. X    if (dbfile)
  1344. X        fn = dbfile;
  1345. X    else {
  1346. X        fn = getenv ("EPHEMDB");
  1347. X        if (!fn)
  1348. X        fn = dbfdef;
  1349. X    }
  1350. X    fp = fopen (fn, "r");
  1351. X    if (!fp) {
  1352. X        (void) sprintf (buf, "Can not open database file %s", fn);
  1353. X        f_msg(buf);
  1354. X        return(-1);
  1355. X    }
  1356. X
  1357. X    /* name is specified so just search for it without any op interaction */
  1358. X    if (name) {
  1359. X        int nl = strlen (name);
  1360. X        int ret = 0;
  1361. X        while (nxt_db(buf, sizeof(buf), fp) == 0 && strncmp(buf, name, nl))
  1362. X        continue;
  1363. X        if (feof(fp)) {
  1364. X        (void) sprintf (buf, "Object %s not found", name);
  1365. X        f_msg (buf);
  1366. X        ret = -1;
  1367. X        } else
  1368. X        (void) obj_define (p, buf);
  1369. X        (void) fclose (fp);
  1370. X        return (ret);
  1371. X    }
  1372. X        
  1373. X    pgn = 0;
  1374. X    readahd = 0;
  1375. X    choice = -1;
  1376. X    abandon = 0;
  1377. X
  1378. X    /* continue until a choice is made or op abandons the attempt */
  1379. X    do {
  1380. X        /* put up next screen full of names.
  1381. X         * leave top row open for messages.
  1382. X         */
  1383. X        c_erase();
  1384. X        for (i = 0; i < NL; )
  1385. X        if (readahd || nxt_db (buf, sizeof(buf), fp) == 0) {
  1386. X            char objname[LCW];
  1387. X            int ii;
  1388. X            for (ii = 0; ii < sizeof(objname)-1; ii++)
  1389. X            if ((objname[ii] = buf[ii]) == ',')
  1390. X                break;
  1391. X            objname[ii] = '\0';
  1392. X            if (i == NL-1)
  1393. X            objname[LCW-2] = '\0'; /* avoid scroll in low-r corner*/
  1394. X            f_string (NTR(i)+2, NTC(i)*LCW+1, objname);
  1395. X            i++;
  1396. X            readahd = 0;
  1397. X        } else
  1398. X            break;
  1399. X
  1400. X        /* read another to check for eof. if valid, set readahd for next
  1401. X         * time.
  1402. X         */
  1403. X        if (nxt_db (buf, sizeof(buf), fp) == 0)
  1404. X        readahd = 1;
  1405. X
  1406. X        /* let op pick one. set cursor on first one.
  1407. X         * remember these r/c are 0-based, but c_pos() is 1-based 
  1408. X         */
  1409. X        (void) sprintf (pb, "Page %d%s. %s", pgn+1,
  1410. X                        feof(fp) ? " (last)" : "", prompt);
  1411. X        f_prompt(pb);
  1412. X        r = c = 0;
  1413. X        roaming = 1;
  1414. X        do {
  1415. X        c_pos (r+2, c*LCW+1);
  1416. X        switch (read_char()) {
  1417. X        case 'h': /* left */
  1418. X            if (c == 0) c = NLC;
  1419. X            c -= 1;
  1420. X            if (RCTN(r,c) >= i)
  1421. X            c = NTC(i-1);
  1422. X            break;
  1423. X        case 'j': /* down */
  1424. X            if (++r == NLR) r = 0;
  1425. X            if (RCTN(r,c) >= i)
  1426. X            r = 0;
  1427. X            break;
  1428. X        case 'k': /* up */
  1429. X            if (r == 0) r = NLR;
  1430. X            r -= 1;
  1431. X            while (RCTN(r,c) >= i)
  1432. X            r -= 1;
  1433. X            break;
  1434. X        case 'l': /* right */
  1435. X            if (++c == NLC) c = 0;
  1436. X            if (RCTN(r,c) >= i)
  1437. X            c = 0;
  1438. X            break;
  1439. X        case REDRAW:
  1440. X            /* start over and skip over prior pages' entries */
  1441. X            rewind(fp);
  1442. X            for (i = 0; i < NL*pgn; i++)
  1443. X            (void) nxt_db (buf, sizeof(buf), fp);
  1444. X            readahd = 0;
  1445. X            roaming = 0;
  1446. X            break;
  1447. X        case 'p':
  1448. X            /* if not at first page, start over and skip back one
  1449. X             * pages' entries
  1450. X             */
  1451. X            if (pgn > 0) {
  1452. X            rewind(fp);
  1453. X            pgn--;
  1454. X            for (i = 0; i < NL*pgn; i++)
  1455. X                (void) nxt_db (buf, sizeof(buf), fp);
  1456. X            readahd = 0;
  1457. X            roaming = 0;
  1458. X            }
  1459. X            break;
  1460. X        case 'n':
  1461. X            /* if not already at eof, we can go ahead another page */
  1462. X            if (!feof (fp)) {
  1463. X            pgn++;
  1464. X            roaming = 0;
  1465. X            }
  1466. X            break;
  1467. X        case END:
  1468. X            abandon = 1;
  1469. X            roaming = 0;
  1470. X            break;
  1471. X        case ' ': case '\r':
  1472. X            choice = NL*pgn + RCTN(r,c);
  1473. X            roaming = 0;
  1474. X            break;
  1475. X        }
  1476. X        } while (roaming);
  1477. X    } while (choice < 0 && !abandon);
  1478. X
  1479. X    if (choice >= 0) {
  1480. X        /* skip first choice entries; selection is the next one */
  1481. X        (void) rewind (fp);
  1482. X        for (i = 0; i < choice; i++)
  1483. X        (void) nxt_db (buf, sizeof(buf), fp);
  1484. X        (void) nxt_db (buf, sizeof(buf), fp);
  1485. X        (void) obj_define (p, buf);
  1486. X    }
  1487. X    (void) fclose (fp);
  1488. X    redraw_screen (2);
  1489. X    return (choice >= 0 ? 0 : -1);
  1490. X}
  1491. X
  1492. X/* read database file fp and put next valid entry into buf.
  1493. X * return 0 if ok, else -1
  1494. X */
  1495. Xstatic
  1496. Xnxt_db (buf, blen, fp)
  1497. Xchar buf[];
  1498. Xint blen;
  1499. XFILE *fp;
  1500. X{
  1501. X    char s;
  1502. X    while (1) {
  1503. X        if (fgets (buf, blen, fp) == 0)
  1504. X        return (-1);
  1505. X        s = buf[0];
  1506. X        if (isalpha(s))
  1507. X        return (0);
  1508. X    }
  1509. X}
  1510. X
  1511. X/* define a fixed object.
  1512. X * args in av, in order, are name, type, ra, dec, magnitude, reference epoch
  1513. X *   and optional angular size.
  1514. X * if av then it is a list of strings to use for each parameter, else must
  1515. X * ask for each (but type). the av option is for cracking the ephem.db line.
  1516. X * if asking show current settings and leave unchanged if hit RETURN.
  1517. X * END aborts without making any more changes.
  1518. X * o_type is set to FIXED.
  1519. X * N.B. we don't error check av in any way, not even for length.
  1520. X */
  1521. Xstatic
  1522. Xobj_dfixed (op, ac, av)
  1523. XObj *op;
  1524. Xint ac;
  1525. Xchar *av[];
  1526. X{
  1527. X    char buf[NC];
  1528. X    char *bp;
  1529. X    int sts;
  1530. X
  1531. X    op->o_type = FIXED;
  1532. X
  1533. X    if (set_name (av, op->o_f.f_name) < 0)
  1534. X        return;
  1535. X
  1536. X    if (av) {
  1537. X        bp = av[2];
  1538. X        sts = 1;
  1539. X    } else {
  1540. X        static char p[] = "RA (h:m:s): (";
  1541. X        f_prompt (p);
  1542. X        f_ra (R_PROMPT, C_PROMPT+sizeof(p)-1, op->o_f.f_ra);
  1543. X        (void) printf (") ");
  1544. X        sts = read_line (buf, 8+1);
  1545. X        if (sts < 0)
  1546. X        return;
  1547. X        bp = buf;
  1548. X    }
  1549. X    if (sts > 0) {
  1550. X        int h, m, s;
  1551. X        f_dec_sexsign (radhr(op->o_f.f_ra), &h, &m, &s);
  1552. X        f_sscansex (bp, &h, &m, &s);
  1553. X        sex_dec (h, m, s, &op->o_f.f_ra);
  1554. X        op->o_f.f_ra = hrrad(op->o_f.f_ra);
  1555. X    }
  1556. X
  1557. X    if (av) {
  1558. X        bp = av[3];
  1559. X        sts = 1;
  1560. X    } else {
  1561. X        static char p[] = "Dec (d:m:s): (";
  1562. X        f_prompt (p);
  1563. X        f_gangle (R_PROMPT, C_PROMPT+sizeof(p)-1, op->o_f.f_dec);
  1564. X        (void) printf (") ");
  1565. X        sts = read_line (buf, 9+1);
  1566. X        if (sts < 0)
  1567. X        return;
  1568. X        bp = buf;
  1569. X    }
  1570. X    if (sts > 0) {
  1571. X        int dg, m, s;
  1572. X        f_dec_sexsign (raddeg(op->o_f.f_dec), &dg, &m, &s);
  1573. X        f_sscansex (bp, &dg, &m, &s);
  1574. X        sex_dec (dg, m, s, &op->o_f.f_dec);
  1575. X        op->o_f.f_dec = degrad(op->o_f.f_dec);
  1576. X    }
  1577. X
  1578. X    if (set_double (av, 4, "Magnitude: ", &op->o_f.f_mag) < 0)
  1579. X        return;
  1580. X
  1581. X    if (set_year (av, 5,"Reference epoch (UT Date, m/d.d/y or year.d): ",
  1582. X                            DY, &op->o_f.f_epoch) < 0)
  1583. X        return;
  1584. X
  1585. X    if (ac == 7 || !av)
  1586. X        (void) set_double (av, 6, "Angular Size: ", &op->o_f.f_siz);
  1587. X    else
  1588. X        op->o_f.f_siz = 0.0;
  1589. X
  1590. X}
  1591. X
  1592. X/* define an object in an elliptical heliocentric orbit.
  1593. X * 13 or 14 args in av, in order, are name, type, inclination, longitude of
  1594. X *   ascending node, argument of perihelion, mean distance (aka semi-major
  1595. X *   axis), daily motion, eccentricity, mean anomaly (ie, degrees from
  1596. X *   perihelion), epoch date (ie, time of the mean anomaly value), equinox year
  1597. X *   (ie, time of inc/lon/aop), two magnitude coefficients and optional size.
  1598. X * the mag may be H/G or g/k model, set by leading g or H (use H/G if none).
  1599. X * if av then it is a list of strings to use for each parameter, else must
  1600. X * ask for each. the av option is for cracking the ephem.db line.
  1601. X * if asking show current settings and leave unchanged if hit RETURN.
  1602. X * END aborts without making any more changes.
  1603. X * o_type is set to ELLIPTICAL.
  1604. X * N.B. we don't error check av in any way, not even for length.
  1605. X */
  1606. Xstatic
  1607. Xobj_delliptical(op, ac, av)
  1608. XObj *op;
  1609. Xint ac;
  1610. Xchar *av[];
  1611. X{
  1612. X    op->o_type = ELLIPTICAL;
  1613. X
  1614. X    if (set_name (av, op->o_e.e_name) < 0)
  1615. X        return;
  1616. X
  1617. X    if (set_double (av, 2, "Inclination (degs):", &op->o_e.e_inc) < 0)
  1618. X        return;
  1619. X
  1620. X    if (set_double (av, 3, "Longitude of ascending node (degs):",
  1621. X                &op->o_e.e_Om) < 0)
  1622. X        return;
  1623. X
  1624. X    if (set_double (av, 4, "Argument of Perihelion (degs):",
  1625. X                &op->o_e.e_om) < 0)
  1626. X        return;
  1627. X
  1628. X    if (set_double (av, 5, "Mean distance (AU):", &op->o_e.e_a) < 0)
  1629. X        return;
  1630. X
  1631. X    if (set_double (av, 6, "Daily motion (degs/day):", &op->o_e.e_n) < 0)
  1632. X        return;
  1633. X
  1634. X    if (set_double (av, 7, "Eccentricity:", &op->o_e.e_e) < 0)
  1635. X        return;
  1636. X
  1637. X    if (set_double (av, 8, "Mean anomaly (degs):", &op->o_e.e_M) < 0)
  1638. X        return;
  1639. X
  1640. X    if (set_year (av, 9, "Epoch date (UT Date, m/d.d/y or year.d): ",
  1641. X                            YMD, &op->o_e.e_cepoch) < 0)
  1642. X        return;
  1643. X
  1644. X    if (set_year (av, 10, "Equinox year (UT Date, m/d.d/y or year.d): ",
  1645. X                            DY, &op->o_e.e_epoch) < 0)
  1646. X        return;
  1647. X
  1648. X    if (set_mag (av, 11, &op->o_e.e_mag) < 0)
  1649. X        return;
  1650. X
  1651. X    if (ac == 14 || !av)
  1652. X        (void) set_double (av, 13, "Angular Size @ 1 AU: ", &op->o_e.e_siz);
  1653. X    else
  1654. X        op->o_e.e_siz = 0.0;
  1655. X
  1656. X}
  1657. X
  1658. X/* define an object in heliocentric hyperbolic orbit.
  1659. X * 11 or 12 args in av, in order, are name, type, epoch of perihelion,
  1660. X *   inclination, longitude of ascending node, argument of perihelion,
  1661. X *    eccentricity, perihelion distance, reference epoch, absolute magnitude
  1662. X *    and luminosity index, and optional size.
  1663. X * if av then it is a list of strings to use for each parameter, else must
  1664. X * ask for each. the av option is for cracking the ephem.db line.
  1665. X * if asking show current settings and leave unchanged if hit RETURN.
  1666. X * END aborts without making any more changes.
  1667. X * o_type is set to HYPERBOLIC.
  1668. X * N.B. we don't error check av in any way, not even for length.
  1669. X */
  1670. Xstatic
  1671. Xobj_dhyperbolic (op, ac, av)
  1672. XObj *op;
  1673. Xint ac;
  1674. Xchar *av[];
  1675. X{
  1676. X    op->o_type = HYPERBOLIC;
  1677. X
  1678. X    if (set_name (av, op->o_h.h_name) < 0)
  1679. X        return;
  1680. X
  1681. X    if (set_year(av,2,"Epoch of perihelion (UT Date, m/d.d/y or year.d): ",
  1682. X                            YMD, &op->o_h.h_ep) < 0)
  1683. X        return;
  1684. X
  1685. X    if (set_double (av, 3, "Inclination (degs):", &op->o_h.h_inc) < 0)
  1686. X        return;
  1687. X
  1688. X    if (set_double (av, 4,
  1689. X        "Longitude of ascending node (degs):", &op->o_h.h_Om) < 0)
  1690. X        return;
  1691. X
  1692. X    if (set_double(av,5,"Argument of perihelion (degs):", &op->o_h.h_om) <0)
  1693. X        return;
  1694. X
  1695. X    if (set_double (av, 6, "Eccentricity:", &op->o_h.h_e) < 0)
  1696. X        return;
  1697. X
  1698. X    if (set_double (av, 7, "Perihelion distance (AU):", &op->o_h.h_qp) < 0)
  1699. X        return;
  1700. X
  1701. X    if (set_year (av, 8, "Reference epoch (UT Date, m/d.d/y or year.d): ",
  1702. X                            DY, &op->o_h.h_epoch) < 0)
  1703. X        return;
  1704. X
  1705. X    if (set_double (av, 9, "g:", &op->o_h.h_g) < 0)
  1706. X        return;
  1707. X
  1708. X    if (set_double (av, 10, "k:", &op->o_h.h_k) < 0)
  1709. X        return;
  1710. X
  1711. X    if (ac == 12 || !av)
  1712. X        (void) set_double (av, 11, "Angular Size @ 1 AU: ", &op->o_h.h_siz);
  1713. X    else
  1714. X        op->o_h.h_siz = 0.0;
  1715. X}
  1716. X
  1717. X/* define an object in heliocentric parabolic orbit.
  1718. X * 10 or 11 args in av, in order, are name, type, epoch of perihelion,
  1719. X *   inclination, argument of perihelion, perihelion distance, longitude of
  1720. X *   ascending node, reference epoch, absolute magnitude and luminosity index,
  1721. X *   and optional size.
  1722. X * if av then it is a list of strings to use for each parameter, else must
  1723. X * ask for each. the av option is for cracking the ephem.db line.
  1724. X * if asking show current settings and leave unchanged if hit RETURN.
  1725. X * END aborts without making any more changes.
  1726. X * o_type is set to PARABOLIC.
  1727. X * N.B. we don't error check av in any way, not even for length.
  1728. X */
  1729. Xstatic
  1730. Xobj_dparabolic(op, ac, av)
  1731. XObj *op;
  1732. Xint ac;
  1733. Xchar *av[];
  1734. X{
  1735. X    op->o_type = PARABOLIC;
  1736. X
  1737. X    if (set_name (av, op->o_p.p_name) < 0)
  1738. X        return;
  1739. X
  1740. X    if (set_year(av,2,"Epoch of perihelion (UT Date, m/d.d/y or year.d): ",
  1741. X                            YMD, &op->o_p.p_ep) < 0)
  1742. X        return;
  1743. X
  1744. X    if (set_double (av, 3, "Inclination (degs):", &op->o_p.p_inc) < 0)
  1745. X        return;
  1746. X
  1747. X    if (set_double(av,4,"Argument of perihelion (degs):", &op->o_p.p_om) <0)
  1748. X        return;
  1749. X
  1750. X    if (set_double (av, 5, "Perihelion distance (AU):", &op->o_p.p_qp) < 0)
  1751. X        return;
  1752. X
  1753. X    if (set_double (av, 6,
  1754. X        "Longitude of ascending node (degs):", &op->o_p.p_Om) < 0)
  1755. X        return;
  1756. X
  1757. X    if (set_year (av, 7, "Reference epoch (UT Date, m/d.d/y or year.d): ",
  1758. X                            DY, &op->o_p.p_epoch) < 0)
  1759. X        return;
  1760. X
  1761. X    if (set_double (av, 8, "g:", &op->o_p.p_g) < 0)
  1762. X        return;
  1763. X
  1764. X    if (set_double (av, 9, "k:", &op->o_p.p_k) < 0)
  1765. X        return;
  1766. X
  1767. X    if (ac == 11 || !av)
  1768. X        (void) set_double (av, 10, "Angular Size @ 1 AU: ", &op->o_p.p_siz);
  1769. X    else
  1770. X        op->o_p.p_siz = 0.0;
  1771. X}
  1772. X
  1773. Xstatic
  1774. Xset_double (av, vn, pr, fp)
  1775. Xchar *av[];    /* arg list */
  1776. Xint vn;        /* which arg */
  1777. Xchar *pr;    /* prompt */
  1778. Xdouble *fp;    /* ptr to double to be set */
  1779. X{
  1780. X    int sts;
  1781. X    char buf[NC];
  1782. X    char *bp;
  1783. X
  1784. X    if (av) {
  1785. X        bp = av[vn];
  1786. X        sts = 1;
  1787. X    } else {
  1788. X        f_prompt (pr);
  1789. X        f_double (R_PROMPT, C_PROMPT+1+strlen(pr), "(%g) ", *fp);
  1790. X        sts = read_line (buf, 20);
  1791. X        if (sts < 0)
  1792. X        return (-1);
  1793. X        bp = buf;
  1794. X    }
  1795. X    if (sts > 0)
  1796. X        *fp = atof (bp);
  1797. X    return (0);
  1798. X}
  1799. X
  1800. Xstatic
  1801. Xset_name (av, np)
  1802. Xchar *av[];    /* arg list */
  1803. Xchar *np;    /* name to be set */
  1804. X{
  1805. X    int sts;
  1806. X    char buf[NC];
  1807. X    char *bp;
  1808. X
  1809. X    if (av) {
  1810. X        bp = av[0];
  1811. X        sts = 1;
  1812. X    } else {
  1813. X        (void) sprintf (buf, "Name: (%s) ", np);
  1814. X        f_prompt (buf);
  1815. X        sts = read_line (buf, MAXNM-1);
  1816. X        if (sts < 0)
  1817. X        return (-1);
  1818. X        bp = buf;
  1819. X    }
  1820. X    if (sts > 0)
  1821. X        (void) strcpy (np, bp);
  1822. X    return (0);
  1823. X}
  1824. X
  1825. Xstatic
  1826. Xset_year (av, vn, pr, type, yp)
  1827. Xchar *av[];    /* arg list */
  1828. Xint vn;        /* which arg */
  1829. Xchar *pr;    /* prompt */
  1830. Xint type;    /* display type: YMD or DY */
  1831. Xdouble *yp;    /* ptr to year to be set */
  1832. X{
  1833. X    int sts;
  1834. X    char buf[NC];
  1835. X    char *bp;
  1836. X
  1837. X    if (av) {
  1838. X        bp = av[vn];
  1839. X        sts = 1;
  1840. X    } else {
  1841. X        f_prompt (pr);
  1842. X        if (type == DY) {
  1843. X        double y;
  1844. X        mjd_year (*yp, &y);
  1845. X        (void) printf ("(%g) ", y);
  1846. X        } else {
  1847. X        int m, y;
  1848. X        double d;
  1849. X        mjd_cal (*yp, &m, &d, &y);
  1850. X        (void) printf ("(%d/%g/%d) ", m, d, y);
  1851. X        }
  1852. X        sts = read_line (buf, 20);
  1853. X        if (sts < 0)
  1854. X        return (-1);
  1855. X        bp = buf;
  1856. X    }
  1857. X    if (sts > 0)
  1858. X        crack_year (bp, yp);
  1859. X    return (0);
  1860. X}
  1861. X
  1862. X/* given either a decimal year (xxxx. something) or a calendar (x/x/x)
  1863. X * convert it to an mjd and store it at *p;
  1864. X */
  1865. Xstatic
  1866. Xcrack_year (bp, p)
  1867. Xchar *bp;
  1868. Xdouble *p;
  1869. X{
  1870. X    if (decimal_year(bp)) {
  1871. X        double y = atof (bp);
  1872. X        year_mjd (y, p);
  1873. X    } else {
  1874. X        int m, y;
  1875. X        double d;
  1876. X        mjd_cal (*p, &m, &d, &y);    /* init with current */
  1877. X        f_sscandate (bp, &m, &d, &y);
  1878. X        cal_mjd (m, d, y, p);
  1879. X    }
  1880. X}
  1881. X
  1882. X/* read next two args from av and load the magnitude members m_m1 and m_m2.
  1883. X * also set m_whichm to default if this is from the .db file, ie, if av!=0.
  1884. X * #,#     -> model is unchanged
  1885. X * g#,[k]# -> g/k
  1886. X * H#,[G]# -> H/G
  1887. X */
  1888. Xstatic
  1889. Xset_mag (av, vn, mp)
  1890. Xchar *av[];    /* arg list */
  1891. Xint vn;        /* which arg. we use av[vn] and av[vn+1] */
  1892. XMag *mp;
  1893. X{
  1894. X    int sts;
  1895. X    char buf[NC];
  1896. X    char *bp;
  1897. X
  1898. X    if (av) {
  1899. X        mp->m_whichm = MAG_HG;    /* always the default for the db file */
  1900. X        bp = av[vn];
  1901. X        sts = 1;
  1902. X    } else {
  1903. X        /* show both the value and the type of the first mag param,
  1904. X         * as well as a hint as to how to set the type if desired.
  1905. X         */
  1906. X        (void) sprintf (buf, "%c: (%g) (g# H# or #) ",
  1907. X                mp->m_whichm == MAG_HG ? 'H' : 'g', mp->m_m1);
  1908. X        f_prompt (buf);
  1909. X        sts = read_line (buf, 9);
  1910. X        if (sts < 0)
  1911. X        return (-1);
  1912. X        bp = buf;
  1913. X    }
  1914. X    if (sts > 0) {
  1915. X        switch (bp[0]) {
  1916. X        case 'g':
  1917. X        mp->m_whichm = MAG_gk;
  1918. X        bp++;
  1919. X        break;
  1920. X        case 'H':
  1921. X        mp->m_whichm = MAG_HG;
  1922. X        bp++;
  1923. X        default:
  1924. X        /* leave type unchanged if no prefix */
  1925. X        break;
  1926. X        }
  1927. X        mp->m_m1 = atof (bp);
  1928. X    }
  1929. X
  1930. X    if (av) {
  1931. X        bp = av[vn+1];
  1932. X        sts = 1;
  1933. X    } else {
  1934. X        /* can't change the type in the second param */
  1935. X        (void) sprintf (buf, "%c: (%g) ",
  1936. X                mp->m_whichm == MAG_HG ? 'G' : 'k', mp->m_m2);
  1937. X        f_prompt (buf);
  1938. X        sts = read_line (buf, 9);
  1939. X        if (sts < 0)
  1940. X        return (-1);
  1941. X        bp = buf;
  1942. X    }
  1943. X    if (sts > 0) {
  1944. X        int ok = 0;
  1945. X        switch (bp[0]) {
  1946. X        case 'k':
  1947. X        if (mp->m_whichm == MAG_gk) {
  1948. X            bp++;
  1949. X            ok = 1;
  1950. X        }
  1951. X        break;
  1952. X        case 'G':
  1953. X        if (mp->m_whichm == MAG_HG) {
  1954. X            bp++;
  1955. X            ok = 1;
  1956. X        }
  1957. X        break;
  1958. X        default:
  1959. X        ok = 1;
  1960. X        break;
  1961. X        }
  1962. X        if (ok)
  1963. X        mp->m_m2 = atof (bp);
  1964. X        else {
  1965. X        f_msg ("Can't switch magnitude models at second parameter.");
  1966. X        return (-1);
  1967. X        }
  1968. X    }
  1969. X    return (0);
  1970. X}
  1971. END_OF_FILE
  1972.   if test 29454 -ne `wc -c <'objx.c'`; then
  1973.     echo shar: \"'objx.c'\" unpacked with wrong size!
  1974.   fi
  1975.   # end of 'objx.c'
  1976. fi
  1977. echo shar: End of archive 3 \(of 9\).
  1978. cp /dev/null ark3isdone
  1979. MISSING=""
  1980. for I in 1 2 3 4 5 6 7 8 9 ; do
  1981.     if test ! -f ark${I}isdone ; then
  1982.     MISSING="${MISSING} ${I}"
  1983.     fi
  1984. done
  1985. if test "${MISSING}" = "" ; then
  1986.     echo You have unpacked all 9 archives.
  1987.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1988. else
  1989.     echo You still must unpack the following archives:
  1990.     echo "        " ${MISSING}
  1991. fi
  1992. exit 0
  1993. exit 0 # Just in case...
  1994.