home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume28
/
ephem
/
part03
< prev
next >
Wrap
Text File
|
1992-03-15
|
55KB
|
2,034 lines
Newsgroups: comp.sources.misc
From: e_downey@hwking.cca.cr.rockwell.com (Elwood C. Downey)
Subject: v28i086: ephem - an interactive astronomical ephemeris, v4.28, Part03/09
Message-ID: <1992Mar10.215726.15960@sparky.imd.sterling.com>
X-Md4-Signature: c3900dac45b48d6d5612e76d0e9fef18
Date: Tue, 10 Mar 1992 21:57:26 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: e_downey@hwking.cca.cr.rockwell.com (Elwood C. Downey)
Posting-number: Volume 28, Issue 86
Archive-name: ephem/part03
Environment: UNIX, VMS, DOS, MAC
Supersedes: ephem-4.21: Volume 14, Issue 76-81
#! /bin/sh
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# Contents: io.c objx.c
# Wrapped by kent@sparky on Tue Mar 10 14:34:05 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive 3 (of 9)."'
if test -f 'io.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'io.c'\"
else
echo shar: Extracting \"'io.c'\" \(21617 characters\)
sed "s/^X//" >'io.c' <<'END_OF_FILE'
X/* this file (in principle) contains all the device-dependent code for
X * handling screen movement and reading the keyboard. public routines are:
X * c_pos(r,c), c_erase(), c_eol();
X * chk_char(), read_char(), read_line (buf, max); and
X * byetty().
X * N.B. we assume output may be performed by printf(), putchar() and
X * fputs(stdout). since these are buffered we flush first in read_char().
X */
X
X/* explanation of various conditional #define options:
X * UNIX: uses termcap for screen management.
X * USE_TERMIO: use termio.h to control tty modes.
X * USE_SGTTY: use sgtty.h to control tty modes.
X * USE_NDELAY: do non-blocking tty reads with fcntl(O_NDELAY).
X * USE_FIONREAD: do non-blocking tty reads with ioctl(FIONREAD).
X * USE_ATTSELECT: do non-blocking reads with att's select(2) (4 args).
X * USE_BSDSELECT: do non-blocking reads with bsd's select(2) (5 args).
X * TURBO_C: compiles for Turbo C 2.0. I'm told it works for Lattice and
X * Microsoft too.
X * USE_ANSISYS: default PC cursor control uses direct BIOS calls (thanks to
X * Mr. Doug McDonald). If your PC does not work with this, however, add
X * "device ANSI.SYS" to your config.sys file and build ephem with
X * USE_ANSISYS.
X * VMS: uses QIO for input, TERMTABLE info for output. This code uses only
X * standard VMS calls, i.e. it does not rely on any third-vendor termcap
X * package or the like. The code includes recoqnition of arrow keys, it
X * is easy to extend it to recoqnize other function keys. you don't
X * need to #define VMS since it is inherent in the compiler.
X */
X
X/* unless you are on VMS define one of these... */
X#define UNIX
X/* #define TURBO_C */
X
X/* then if you defined UNIX you must use one of these ways to do non-blocking
X * tty reads
X */
X#define USE_FIONREAD
X/* #define USE_NDELAY */
X/* #define USE_ATTSELECT */
X/* #define USE_BSDSELECT */
X
X/* and then if you defined UNIX you must also use one of these ways to control
X * the tty modes.
X */
X#define USE_TERMIO
X/* #define USE_SGTTY */
X
X/* if you defined TURBO_C you might want this too if screen io looks garbled */
X/* #define USE_ANSISYS */
X
X#include <stdio.h>
X#include <ctype.h>
X#include "screen.h"
X
X#ifdef UNIX
X#include <signal.h>
X#ifdef USE_TERMIO
X#include <termio.h>
X#endif
X#ifdef USE_SGTTY
X#include <sgtty.h>
X#endif
X#ifdef USE_BSDSELECT
X#include <sys/time.h>
X#endif
X#ifdef USE_NDELAY
X#include <fcntl.h>
X#endif
X
Xextern char *tgoto();
Xstatic char *cm, *ce, *cl, *ks, *ke, *kl, *kr, *ku, *kd; /* termcap sequences */
Xstatic int tloaded;
Xstatic int ttysetup;
X#ifdef USE_TERMIO
Xstatic struct termio orig_tio;
X#endif
X#ifdef USE_SGTTY
Xstatic struct sgttyb orig_sgtty;
X#endif
X
X/* move cursor to row, col, 1-based.
X * we assume this also moves a visible cursor to this location.
X */
Xc_pos (r, c)
Xint r, c;
X{
X if (!tloaded) tload();
X fputs (tgoto (cm, c-1, r-1), stdout);
X}
X
X/* erase entire screen. */
Xc_erase()
X{
X if (!tloaded) tload();
X fputs (cl, stdout);
X}
X
X/* erase to end of line */
Xc_eol()
X{
X if (!tloaded) tload();
X fputs (ce, stdout);
X}
X
X#ifdef USE_NDELAY
Xstatic char sav_char; /* one character read-ahead for chk_char() */
X#endif
X
X/* return 0 if there is a char that may be read without blocking, else -1 */
Xchk_char()
X{
X#ifdef USE_NDELAY
X if (!ttysetup) setuptty();
X fflush (stdout);
X if (sav_char)
X return (0);
X fcntl (0, F_SETFL, O_NDELAY); /* non-blocking read. FNDELAY on BSD */
X if (read (0, &sav_char, 1) != 1)
X sav_char = 0;
X return (sav_char ? 0 : -1);
X#endif
X#ifdef USE_ATTSELECT
X int nfds, rfds, wfds, to;
X if (!ttysetup) setuptty();
X fflush (stdout);
X rfds = 1 << 0; /* reads are on fd 0 */
X wfds = 0; /* not interested in any write fds */
X nfds = 1; /* check only fd 0 */
X to = 0; /* don't delay - return 0 if nothing pending */
X return (select (nfds, &rfds, &wfds, to) == 0 ? -1 : 0);
X#endif
X#ifdef USE_BSDSELECT
X int nfds, rfds, wfds, xfds;
X struct timeval to;
X if (!ttysetup) setuptty();
X fflush (stdout);
X rfds = 1 << 0; /* reads are on fd 0 */
X wfds = 0; /* not interested in any write fds */
X xfds = 0; /* not interested in any exception fds */
X nfds = 1; /* check only fd 0 */
X to.tv_sec = 0; /* don't delay - return 0 if nothing pending */
X to.tv_usec = 0; /* don't delay - return 0 if nothing pending */
X return (select (nfds, &rfds, &wfds, &xfds, &to) == 0 ? -1 : 0);
X#endif
X#ifdef USE_FIONREAD
X long n;
X if (!ttysetup) setuptty();
X fflush (stdout);
X ioctl (0, FIONREAD, &n);
X return (n > 0 ? 0 : -1);
X#endif
X}
X
X/* read the next char, blocking if necessary, and return it. don't echo.
X * map the arrow keys if we can too into hjkl
X */
Xread_char()
X{
X char c;
X if (!ttysetup) setuptty();
X fflush (stdout);
X#ifdef USE_NDELAY
X fcntl (0, F_SETFL, 0); /* blocking read */
X if (sav_char) {
X c = sav_char;
X sav_char = 0;
X } else
X#endif
X read (0, &c, 1);
X c = chk_arrow (c & 0177); /* just ASCII, please */
X return (c);
X}
X
X/* used to time out of a read */
Xstatic got_alrm;
Xstatic
Xon_alrm()
X{
X got_alrm = 1;
X}
X
X/* see if c is the first of any of the termcap arrow key sequences.
X * if it is, read the rest of the sequence, and return the hjkl code
X * that corresponds.
X * if no match, just return c.
X */
Xstatic
Xchk_arrow (c)
Xregister char c;
X{
X register char *seq;
X
X if (kl && kd && ku && kr &&
X (c == *(seq = kl) || c == *(seq = kd) || c == *(seq = ku)
X || c == *(seq = kr))) {
X char seqa[32]; /* maximum arrow escape sequence ever expected */
X unsigned l = strlen(seq);
X seqa[0] = c;
X if (l > 1) {
X extern unsigned alarm();
X /* cautiously read rest of arrow sequence */
X got_alrm = 0;
X (void) signal (SIGALRM, on_alrm);
X alarm(2);
X read (0, seqa+1, l-1);
X alarm(0);
X if (got_alrm)
X return (c);
X }
X seqa[l] = '\0';
X if (strcmp (seqa, kl) == 0)
X return ('h');
X if (strcmp (seqa, kd) == 0)
X return ('j');
X if (strcmp (seqa, ku) == 0)
X return ('k');
X if (strcmp (seqa, kr) == 0)
X return ('l');
X }
X return (c);
X}
X
X/* do whatever might be necessary to get the screen and/or tty back into shape.
X */
Xbyetty()
X{
X /* if keypad mode switch is used, turn it off now */
X if (ke) {
X fputs (ke, stdout);
X fflush (stdout);
X }
X
X#ifdef USE_TERMIO
X ioctl (0, TCSETA, &orig_tio);
X#endif
X#ifdef USE_SGTTY
X ioctl (0, TIOCSETP, &orig_sgtty);
X#endif
X#ifdef USE_NDELAY
X fcntl (0, F_SETFL, 0); /* be sure to go back to blocking read */
X#endif
X ttysetup = 0;
X}
X
Xstatic
Xtload()
X{
X extern char *getenv(), *tgetstr();
X extern char *UP, *BC;
X char *egetstr();
X static char tbuf[512];
X char rawtbuf[1024];
X char *tp;
X char *ptr;
X
X if (!(tp = getenv ("TERM"))) {
X printf ("no TERM\n");
X exit(1);
X }
X if (tgetent (rawtbuf, tp) != 1) {
X printf ("Can't find termcap for %s\n", tp);
X exit (1);
X }
X
X ptr = tbuf;
X
X ku = egetstr ("ku", &ptr);
X kd = egetstr ("kd", &ptr);
X kl = egetstr ("kl", &ptr);
X kr = egetstr ("kr", &ptr);
X
X if (!(cm = egetstr ("cm", &ptr))) {
X printf ("No termcap cm code\n");
X exit(1);
X }
X if (!(ce = egetstr ("ce", &ptr))) {
X printf ("No termcap ce code\n");
X exit(1);
X }
X if (!(cl = egetstr ("cl", &ptr))) {
X printf ("No termcap cl code\n");
X exit(1);
X }
X
X UP = egetstr ("up", &ptr);
X if (!tgetflag ("bs"))
X BC = egetstr ("bc", &ptr);
X
X if (!ttysetup) setuptty();
X
X /* if keypad mode switch is used, do it now */
X if (ks = egetstr ("ks", &ptr)) {
X ke = egetstr ("ke", &ptr);
X fputs (ks, stdout);
X fflush (stdout);
X }
X
X tloaded = 1;
X}
X
X/* like tgetstr() but discard termcap delay codes, for now anyways */
Xstatic char *
Xegetstr (name, sptr)
Xchar *name;
Xchar **sptr;
X{
X extern char *tgetstr();
X char *s;
X
X if (s = tgetstr (name, sptr)) {
X char c;
X while ((c = *s) == '*' || isdigit(c))
X s += 1;
X }
X return (s);
X}
X
X/* set up tty for char-by-char read, non-blocking */
Xstatic
Xsetuptty()
X{
X#ifdef USE_TERMIO
X struct termio tio;
X
X ioctl (0, TCGETA, &orig_tio);
X tio = orig_tio;
X tio.c_iflag &= ~ICRNL; /* leave CR unchanged */
X tio.c_oflag &= ~OPOST; /* no output processing */
X tio.c_lflag &= ~(ICANON|ECHO); /* no input processing, no echo */
X tio.c_cc[VMIN] = 1; /* return after each char */
X tio.c_cc[VTIME] = 0; /* no read timeout */
X ioctl (0, TCSETA, &tio);
X#endif
X#ifdef USE_SGTTY
X struct sgttyb sg;
X
X ioctl (0, TIOCGETP, &orig_sgtty);
X sg = orig_sgtty;
X sg.sg_flags &= ~ECHO; /* do our own echoing */
X sg.sg_flags &= ~CRMOD; /* leave CR and LF unchanged */
X sg.sg_flags |= XTABS; /* no tabs with termcap */
X sg.sg_flags |= CBREAK; /* wake up on each char but can still kill */
X ioctl (0, TIOCSETP, &sg);
X#endif
X ttysetup = 1;
X}
X/* end of #ifdef UNIX */
X#endif
X
X#ifdef TURBO_C
X#ifdef USE_ANSISYS
X#define ESC '\033'
X/* position cursor.
X * (ANSI: ESC [ r ; c f) (r/c are numbers given in ASCII digits)
X */
Xc_pos (r, c)
Xint r, c;
X{
X printf ("%c[%d;%df", ESC, r, c);
X}
X
X/* erase entire screen. (ANSI: ESC [ 2 J) */
Xc_erase()
X{
X printf ("%c[2J", ESC);
X}
X
X/* erase to end of line. (ANSI: ESC [ K) */
Xc_eol()
X{
X printf ("%c[K", ESC);
X}
X#else
X#include <dos.h>
Xunion REGS rg;
X
X/* position cursor.
X */
Xc_pos (r, c)
Xint r, c;
X{
X rg.h.ah = 2;
X rg.h.bh = 0;
X rg.h.dh = r-1;
X rg.h.dl = c-1;
X int86(16,&rg,&rg);
X}
X
X/* erase entire screen. */
Xc_erase()
X{
X int cur_cursor, i;
X rg.h.ah = 3;
X rg.h.bh = 0;
X int86(16,&rg,&rg);
X cur_cursor = rg.x.dx;
X for(i = 0; i < 25; i++){
X c_pos(i+1,1);
X rg.h.ah = 10;
X rg.h.bh = 0;
X rg.h.al = 32;
X rg.x.cx = 80;
X int86(16,&rg,&rg);
X }
X rg.h.ah = 2;
X rg.h.bh = 0;
X rg.x.dx = cur_cursor;
X int86(16,&rg,&rg);
X
X}
X
X/* erase to end of line.*/
Xc_eol()
X{
X int cur_cursor, i;
X rg.h.ah = 3;
X rg.h.bh = 0;
X int86(16,&rg,&rg);
X cur_cursor = rg.x.dx;
X rg.h.ah = 10;
X rg.h.bh = 0;
X rg.h.al = 32;
X rg.x.cx = 80 - rg.h.dl;
X int86(16,&rg,&rg);
X rg.h.ah = 2;
X rg.h.bh = 0;
X rg.x.dx = cur_cursor;
X int86(16,&rg,&rg);
X
X}
X#endif
X
X/* return 0 if there is a char that may be read without blocking, else -1 */
Xchk_char()
X{
X return (kbhit() == 0 ? -1 : 0);
X}
X
X/* read the next char, blocking if necessary, and return it. don't echo.
X * map the arrow keys if we can too into hjkl
X */
Xread_char()
X{
X int c;
X fflush (stdout);
X c = getch();
X if (c == 0) {
X /* get scan code; convert to direction hjkl if possible */
X c = getch();
X switch (c) {
X case 0x4b: c = 'h'; break;
X case 0x50: c = 'j'; break;
X case 0x48: c = 'k'; break;
X case 0x4d: c = 'l'; break;
X }
X }
X return (c);
X}
X
X/* do whatever might be necessary to get the screen and/or tty back into shape.
X */
Xbyetty()
X{
X}
X/* end of #ifdef TURBO_C */
X#endif
X
X#ifdef VMS
X#include <string.h>
X#include <iodef.h>
X#include <descrip.h>
X#include <dvidef.h>
X#include <smgtrmptr.h>
X#include <starlet.h>
X#include <lib$routines.h>
X#include <smg$routines.h>
X
X/* Structured types for use in system calls */
Xtypedef struct{
X unsigned short status;
X unsigned short count;
X unsigned int info;
X} io_status_block;
Xtypedef struct{
X unsigned short buffer_length;
X unsigned short item_code;
X void *buffer_address;
X unsigned short *return_length_address;
X unsigned long terminator;
X} item_list;
X
Xstatic unsigned short ttchan = 0; /* channel number for terminal */
Xvolatile static io_status_block iosb; /* I/O status block for operation */
X /* currently in progress */
Xvolatile static unsigned char input_buf; /* buffer to recieve input charac-*/
X /* ter when operation completes */
Xstatic void *term_entry; /* pointer to TERMTABLE entry */
X#define MAXCAP 10
Xstatic char ce[MAXCAP]; /* ce and cl capability strings for */
Xstatic char cl[MAXCAP]; /* this terminal type */
X
X/* Declaration of special keys to be recoqnized on input */
X/* Number of special keys defined */
X#define MAXKEY 4
X/* TERMTABLE capability codes for the keys */
Xstatic long capcode[MAXKEY] = {SMG$K_KEY_UP_ARROW,SMG$K_KEY_DOWN_ARROW,
X SMG$K_KEY_RIGHT_ARROW,SMG$K_KEY_LEFT_ARROW};
X/* character codes to be returned by read_char when a special key is presssed */
Xstatic int retcode[MAXKEY] = {'k','j','l','h'};
X/* the actual capability strings from the key */
Xstatic char keycap[MAXKEY][MAXCAP];
X
Xstatic char special_buffer[MAXCAP]; /* buffer for reading special key */
Xstatic int chars_in_buffer; /* number of characters in buffer */
X
X/* set up the structures for this I/O module */
Xinittt()
X{
X unsigned int status; /* system routine return status */
X $DESCRIPTOR(tt,"TT"); /* terminal name */
X item_list itmlst; /* item list for $getdvi obtaining term type */
X unsigned long devtype; /* terminal type returned form $getdvi */
X unsigned short retlen; /* return length from $getdvi */
X unsigned long lenret; /* return length from smg$get_term_data */
X unsigned long maxlen; /* maximum return length */
X unsigned long cap_code;/* capability code */
X#define MAXINIT 20
X char init_string[MAXINIT];/* string to initialize terminal */
X int key;
X
X /* Assign a channel to the terminal */
X if (!((status = sys$assign(&tt,&ttchan,0,0))&1)) lib$signal(status);
X
X /* Get terminal type. Note that it is possible to use the same
X * iosb at this stage, because no I/O is initiated yet.
X */
X itmlst.buffer_length = 4;
X itmlst.item_code = DVI$_DEVTYPE;
X itmlst.buffer_address = &devtype;
X itmlst.return_length_address = &retlen;
X itmlst.terminator = 0;
X if (!((status = sys$getdviw(0,ttchan,0,&itmlst,&iosb,0,0,0))&1))
X lib$signal(status);
X if (!(iosb.status&1)) lib$signal(iosb.status);
X
X /* Get the TERMTABLE entry corresponding to the terminal type */
X if (!((status = smg$init_term_table_by_type(&devtype,
X &term_entry))&1)) lib$signal(status);
X
X /* Get the initialisation string and initialize terminal */
X cap_code = SMG$K_INIT_STRING;
X maxlen = MAXINIT - 1;
X if (!((status = smg$get_term_data(&term_entry,&cap_code,&maxlen,
X &lenret,init_string))&1)) lib$signal(status);
X init_string[lenret] = '\0';
X fputs(init_string,stdout);
X fflush(stdout);
X
X /* Get ce and cl capabilities, these are static */
X cap_code = SMG$K_ERASE_TO_END_LINE;
X maxlen = MAXCAP-1;
X if (!((status = smg$get_term_data(&term_entry,&cap_code,&maxlen,
X &lenret,ce))&1)) lib$signal(status);
X ce[lenret] = '\0';
X
X cap_code = SMG$K_ERASE_WHOLE_DISPLAY;
X maxlen = MAXCAP-1;
X if (!((status = smg$get_term_data(&term_entry,&cap_code,&maxlen,
X &lenret,cl))&1)) lib$signal(status);
X cl[lenret] = '\0';
X
X /* Here one could obtain line drawing sequences, please feel free
X to implement it ... */
X
X /* Get special keys to be recoqnized on input */
X for (key = 0;key<MAXKEY;key++)
X {
X maxlen = MAXCAP-1;
X if (!((status = smg$get_term_data(&term_entry,&capcode[key],
X &maxlen,&lenret,keycap[key]))&1)) lib$signal(status);
X keycap[key][lenret] = '\0';
X }
X
X /* Initiate first input operation, NOECHO.
X * NOFILTR allows any character to get through, this makes it
X * possible to implement arrow recoqnition, and also makes
X * DEL and BS get through.
X * We don't wait for the operation to complete.
X * Note that stdout has already been fflush'ed above.
X */
X if (!((status = sys$qio(0,ttchan,
X IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
X &iosb,0,0,&input_buf,1,0,0,0,0))&1)) lib$signal(status);
X
X /* Initialise special key buffer */
X chars_in_buffer = 0;
X} /* inittt */
X
X
X/* return 0 if there is a char that may be read without blocking, else -1 */
Xchk_char()
X{
X if (!ttchan) inittt();
X
X return ( chars_in_buffer != 0 ? 0 :(iosb.status == 0 ? -1 : 0));
X}
X
X/* read the next char, blocking if necessary, and return it. don't echo.
X * map the arrow keys if we can too into hjkl
X */
Xread_char()
X{
X unsigned int status;
X int buf;
X int i;
X int found_key;
X int key;
X int this_len;
X int match;
X
X if (!ttchan) inittt();
X
X /* If we attempted to read an special key previously, there are characters
X * left in the buffer, return these before doing more I/O
X */
X if (chars_in_buffer!=0){
X buf = special_buffer[0];
X chars_in_buffer--;
X for (i = 0;i<chars_in_buffer;i++)
X {
X special_buffer[i] = special_buffer[i+1];
X }
X special_buffer[chars_in_buffer] = '\0';
X }
X else {
X
X /* Loop over characters read, the loop is terminated when the
X * characters read so far do not match any of the special keys
X * or when the characters read so far is identical to one of
X * the special keys.
X */
X
X do
X {
X /* Wait for I/O to complete */
X if (!((status = sys$synch(0,&iosb))&1)) lib$signal(status);
X special_buffer[chars_in_buffer] = input_buf;
X chars_in_buffer++;
X special_buffer[chars_in_buffer] = '\0';
X
X /* Initiate next input operation */
X fflush (stdout);
X if (!((status = sys$qio(0,ttchan,
X IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
X &iosb,0,0,&input_buf,1,0,0,0,0))&1)) lib$signal(status);
X
X
X /* Check for match with all special strings */
X match = 0;
X found_key = MAXKEY;
X for (key = 0;key<MAXKEY;key++)
X {
X this_len = strlen(keycap[key]);
X if (this_len<chars_in_buffer) continue;
X if (!strncmp(keycap[key],special_buffer,chars_in_buffer)){
X match = -1;
X if (this_len == chars_in_buffer){
X found_key = key;
X break;
X }
X }
X }
X }
X while (match && (found_key == MAXKEY));
X
X /* If one of the keys matches the input string, return the
X * corresponding key code
X */
X if (found_key != MAXKEY)
X {
X buf = retcode[found_key];
X chars_in_buffer = 0;
X }
X else /* return first character and store the rest in the buffer */
X {
X buf = special_buffer[0];
X chars_in_buffer--;
X for (i = 0;i<chars_in_buffer;i++)
X {
X special_buffer[i] = special_buffer[i+1];
X }
X }
X special_buffer[chars_in_buffer] = '\0';
X }
X return(buf);
X}
X
X/* do whatever might be necessary to get the screen and/or tty back into shape.
X */
Xbyetty()
X{
X unsigned int status;
X
X if (ttchan)
X {
X /* There is no string in SMG to send to the terminal when
X * terminating, one could clear the screen, move the cursor to
X * the last line, or whatever. This program clears the screen
X * anyway before calling this routine, so we do nothing.
X */
X
X
X
X /* The following is not really neccessary, it will be done at program
X * termination anyway, but if someone tries to use the I/O routines agai
X n
X * it might prove useful...
X */
X if (!((status = smg$del_term_table())&1)) lib$signal(status);
X if (!((status = sys$dassgn(ttchan))&1)) lib$signal(status);
X /* This also cancels any outstanding I/O on the channel */
X ttchan = 0; /* marks terminal I/O as not initialized */
X }
X}
X
X/* position cursor. */
Xc_pos (r, c)
Xint r, c;
X{
X unsigned long vector[3]; /* argument vector (position) */
X unsigned long status; /* system service return status */
X long lenret; /* length of returned string */
X long maxlen; /* maximum return length */
X unsigned long capcode; /* capability code */
X char seq[2*MAXCAP]; /* returned string */
X
X if (!ttchan) inittt();
X
X /* Set cursor depends on the position, therefore we have to call
X * get_term_data for each operation
X */
X vector[0] = 2;
X vector[1] = r;
X vector[2] = c;
X capcode = SMG$K_SET_CURSOR_ABS;
X maxlen = 2*MAXCAP-1;
X if (!((status = smg$get_term_data(&term_entry,&capcode,&maxlen,
X &lenret,seq,vector))&1)) lib$signal(status);
X seq[lenret] = '\0';
X
X fputs(seq,stdout);
X}
X
X/* erase entire screen. */
Xc_erase()
X{
X if (!ttchan) inittt();
X
X fputs(cl,stdout);
X}
X
X/* erase to end of line. */
Xc_eol()
X{
X if (!ttchan) inittt();
X
X fputs(ce,stdout);
X}
X/* end of #ifdef VMS */
X#endif
X
X/* read up to max chars into buf, with cannonization.
X * add trailing '\0' (buf is really max+1 chars long).
X * return count of chars read (not counting '\0').
X * assume cursor is already positioned as desired.
X * if type END when n==0 then return -1.
X */
Xread_line (buf, max)
Xchar buf[];
Xint max;
X{
X static char erase[] = "\b \b";
X int n, c;
X int done;
X
X#ifdef UNIX
X if (!ttysetup) setuptty();
X#endif
X
X for (done = 0, n = 0; !done; )
X switch (c = read_char()) { /* does not echo */
X case cntrl('h'): /* backspace or */
X case 0177: /* delete are each char erase */
X if (n > 0) {
X fputs (erase, stdout);
X n -= 1;
X }
X break;
X case cntrl('u'): /* line erase */
X while (n > 0) {
X fputs (erase, stdout);
X n -= 1;
X }
X break;
X case '\r': /* EOL */
X done++;
X break;
X default: /* echo and store, if ok */
X if (n == 0 && c == END)
X return (-1);
X if (n >= max)
X putchar (cntrl('g'));
X else if (isprint(c)) {
X putchar (c);
X buf[n++] = c;
X }
X }
X
X buf[n] = '\0';
X return (n);
X}
END_OF_FILE
if test 21617 -ne `wc -c <'io.c'`; then
echo shar: \"'io.c'\" unpacked with wrong size!
fi
# end of 'io.c'
fi
if test -f 'objx.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'objx.c'\"
else
echo shar: Extracting \"'objx.c'\" \(29454 characters\)
sed "s/^X//" >'objx.c' <<'END_OF_FILE'
X/* functions to save the user-definable objects, referred to as "x" and "y".
X * this way, once defined, the objects can be quieried for position just like
X * the other bodies, with obj_cir().
X */
X
X#include <stdio.h>
X#include <math.h>
X#include <ctype.h>
X#ifdef VMS
X#include <stdlib.h>
X#endif
X#include "astro.h"
X#include "circum.h"
X#include "screen.h"
X
Xextern char *strcat(), *strcpy(), *strncpy(), *getenv();
X
Xstatic char *dbfile; /* !0 if set by -d option */
Xstatic char dbfdef[] = "ephem.db"; /* default database file name */
X
X/* structures to describe objects of various types.
X */
X#define MAXNM 16 /* longest allowed object name, inc \0 */
Xtypedef struct {
X double m_m1, m_m2; /* either g/k or H/G, depending on... */
X int m_whichm; /* one of MAG_gk or MAG_HG */
X} Mag;
Xtypedef struct {
X double f_ra; /* ra, rads, at given epoch */
X double f_dec; /* dec, rads, at given epoch */
X double f_mag; /* visual magnitude */
X double f_siz; /* angular size, in arc seconds */
X double f_epoch; /* the given epoch, as an mjd */
X char f_name[MAXNM]; /* name */
X} ObjF; /* fixed object */
Xtypedef struct {
X double e_inc; /* inclination, degrees */
X double e_Om; /* longitude of ascending node, degrees */
X double e_om; /* argument of perihelion, degress */
X double e_a; /* mean distance, aka, semi-maj axis, in AU */
X double e_n; /* daily motion, degrees/day */
X double e_e; /* eccentricity */
X double e_M; /* mean anomaly, ie, degrees from perihelion at... */
X double e_cepoch; /* epoch date (M reference), as an mjd */
X double e_epoch; /* equinox year (inc/Om/om reference), as an mjd */
X Mag e_mag; /* magnitude */
X double e_siz; /* angular size, in arc seconds at 1 AU */
X char e_name[MAXNM]; /* name */
X} ObjE; /* object in heliocentric elliptical orbit */
Xtypedef struct {
X double h_ep; /* epoch of perihelion, as an mjd */
X double h_inc; /* inclination, degs */
X double h_Om; /* longitude of ascending node, degs */
X double h_om; /* argument of perihelion, degs. */
X double h_e; /* eccentricity */
X double h_qp; /* perihelion distance, AU */
X double h_epoch; /* equinox year (inc/Om/om reference), as an mjd */
X double h_g, h_k; /* magnitude model coefficients */
X double h_siz; /* angular size, in arc seconds at 1 AU */
X char h_name[MAXNM]; /* name */
X} ObjH; /* object in heliocentric parabolic trajectory */
Xtypedef struct {
X double p_ep; /* epoch of perihelion, as an mjd */
X double p_inc; /* inclination, degs */
X double p_qp; /* perihelion distance, AU */
X double p_om; /* argument of perihelion, degs. */
X double p_Om; /* longitude of ascending node, degs */
X double p_epoch; /* reference epoch, as an mjd */
X double p_g, p_k; /* magnitude model coefficients */
X double p_siz; /* angular size, in arc seconds at 1 AU */
X char p_name[MAXNM]; /* name */
X} ObjP; /* object in heliocentric parabolic trajectory */
X
Xtypedef struct {
X int o_type; /* current object type; see flags, below */
X int o_on; /* !=0 while current object is active */
X ObjF o_f; /* the fixed object */
X ObjE o_e; /* the elliptical orbit object */
X ObjH o_h; /* the hyperbolic orbit object */
X ObjP o_p; /* the parabolic orbit object */
X} Obj;
X
X/* o_type */
X#define FIXED 1
X#define ELLIPTICAL 2
X#define HYPERBOLIC 3
X#define PARABOLIC 4
X
X/* m_whichm */
X#define MAG_HG 0 /* using 0 makes HG the initial default */
X#define MAG_gk 1
X
Xstatic Obj objx;
Xstatic Obj objy;
X
X#define DY 0 /* decimal year flag for set_year() */
X#define YMD 1 /* year/mon/day flag for set_year() */
X
X/* run when Objx or y is picked from menu.
X * we tell which by the planet code.
X * let op define object and turn it on and off.
X */
Xobj_setup(p)
Xint p;
X{
X static char *pr[6] = { /* leave a slot for "On"/"Off" */
X "Fixed", "Elliptical", "Hyperbolic", "Parabolic", "Lookup"
X };
X int f;
X Obj *op;
X
X op = (p == OBJX) ? &objx : &objy;
X
X rechk:
X /* map o_type to popup choice.
X */
X switch (op->o_type) {
X case FIXED: f = 0; break;
X case ELLIPTICAL: f = 1; break;
X case HYPERBOLIC: f = 2; break;
X case PARABOLIC: f = 3; break;
X default: f = 4; break;
X }
X
X ask:
X pr[5] = op->o_on ? "On" : "Off";
X switch (f = popup (pr, f, 6)) {
X case 0: obj_dfixed(op, 0, (char**)0); goto ask;
X case 1: obj_delliptical(op, 0, (char**)0); goto ask;
X case 2: obj_dhyperbolic(op, 0, (char**)0); goto ask;
X case 3: obj_dparabolic(op, 0, (char**)0); goto ask;
X case 4: if (obj_filelookup(p, (char *)0) == 0) obj_on(p); goto rechk;
X case 5: op->o_on ^= 1; break;
X }
X}
X
X/* turn "on" or "off" but don't forget facts about object the object.
X */
Xobj_on (p)
Xint p;
X{
X if (p == OBJX)
X objx.o_on = 1;
X else
X objy.o_on = 1;
X}
Xobj_off (p)
Xint p;
X{
X if (p == OBJX)
X objx.o_on = 0;
X else
X objy.o_on = 0;
X}
X
X/* return true if object is now on, else 0.
X */
Xobj_ison(p)
Xint p;
X{
X return ((p == OBJX) ? objx.o_on : objy.o_on);
X}
X
X/* set an alternate database file name.
X * N.B. we assume the storage pointed to by name is permanent.
X */
Xobj_setdbfilename (name)
Xchar *name;
X{
X dbfile = name;
X}
X
X/* fill in info about object x or y.
X * most arguments and conditions are the same as for plans().
X * only difference is that mag is already apparent, not absolute magnitude.
X * this is called by body_cir() for object x and y just like plans() is called
X * for the planets.
X */
Xobj_cir (jd, p, lpd0, psi0, rp0, rho0, lam, bet, siz, mag)
Xdouble jd; /* mjd now */
Xint p; /* OBJX or OBJY */
Xdouble *lpd0; /* heliocentric longitude, or NOHELIO */
Xdouble *psi0; /* heliocentric latitude, or 0 if *lpd0 set to NOHELIO */
Xdouble *rp0; /* distance from the sun, or 0 */
Xdouble *rho0; /* true distance from the Earth, or 0 */
Xdouble *lam; /* apparent geocentric ecliptic longitude */
Xdouble *bet; /* apparent geocentric ecliptic latitude */
Xdouble *siz; /* angular size of object, arc seconds */
Xdouble *mag; /* APPARENT magnitude */
X{
X Obj *op = (p == OBJX) ? &objx : &objy;
X
X switch (op->o_type) {
X case FIXED: {
X double xr, xd;
X xr = op->o_f.f_ra;
X xd = op->o_f.f_dec;
X if (op->o_f.f_epoch != jd)
X precess (op->o_f.f_epoch, jd, &xr, &xd);
X eq_ecl (jd, xr, xd, bet, lam);
X
X *lpd0 = NOHELIO;
X *psi0 = *rp0 = *rho0 = 0.0;
X *mag = op->o_f.f_mag;
X *siz = op->o_f.f_siz;
X }
X break;
X
X case ELLIPTICAL: {
X /* this is basically the same code as pelement() and plans()
X * combined and simplified for the special case of osculating
X * (unperturbed) elements.
X * inputs have been changed to match the Astronomical Almanac.
X * we have added reduction of elements using reduce_elements().
X */
X double dt, lg, lsn, rsn;
X double nu, ea;
X double ma, rp, lo, slo, clo;
X double inc, psi, spsi, cpsi;
X double y, lpd, rpd, ll, rho, sll, cll;
X double om; /* arg of perihelion */
X double Om; /* long of ascending node. */
X double e;
X int pass;
X
X dt = 0;
X sunpos (jd, &lsn, &rsn);
X lg = lsn + PI;
X e = op->o_e.e_e;
X
X for (pass = 0; pass < 2; pass++) {
X
X reduce_elements (op->o_e.e_epoch, jd-dt, degrad(op->o_e.e_inc),
X degrad (op->o_e.e_om), degrad (op->o_e.e_Om),
X &inc, &om, &Om);
X
X ma = degrad (op->o_e.e_M
X + (jd - op->o_e.e_cepoch - dt) * op->o_e.e_n);
X anomaly (ma, e, &nu, &ea);
X rp = op->o_e.e_a * (1-e*e) / (1+e*cos(nu));
X lo = nu + om;
X slo = sin(lo);
X clo = cos(lo);
X spsi = slo*sin(inc);
X y = slo*cos(inc);
X psi = asin(spsi);
X lpd = atan(y/clo)+Om;
X if (clo<0) lpd += PI;
X range (&lpd, 2*PI);
X cpsi = cos(psi);
X rpd = rp*cpsi;
X ll = lpd-lg;
X rho = sqrt(rsn*rsn+rp*rp-2*rsn*rp*cpsi*cos(ll));
X dt = rho*5.775518e-3; /* light travel time, in days */
X if (pass == 0) {
X *lpd0 = lpd;
X *psi0 = psi;
X *rp0 = rp;
X *rho0 = rho;
X }
X }
X
X sll = sin(ll);
X cll = cos(ll);
X if (rpd < rsn)
X *lam = atan(-1*rpd*sll/(rsn-rpd*cll))+lg+PI;
X else
X *lam = atan(rsn*sll/(rpd-rsn*cll))+lpd;
X range (lam, 2*PI);
X *bet = atan(rpd*spsi*sin(*lam-lpd)/(cpsi*rsn*sll));
X
X if (op->o_e.e_mag.m_whichm == MAG_HG) {
X /* the H and G parameters from the Astro. Almanac.
X */
X double psi_t, Psi_1, Psi_2, beta;
X beta = acos((rp*rp + rho*rho - rsn*rsn)/ (2*rp*rho));
X psi_t = exp(log(tan(beta/2.0))*0.63);
X Psi_1 = exp(-3.33*psi_t);
X psi_t = exp(log(tan(beta/2.0))*1.22);
X Psi_2 = exp(-1.87*psi_t);
X *mag = op->o_e.e_mag.m_m1 + 5.0*log10(rp*rho)
X - 2.5*log10((1-op->o_e.e_mag.m_m2)*Psi_1
X + op->o_e.e_mag.m_m2*Psi_2);
X } else {
X /* the g/k model of comets */
X *mag = op->o_e.e_mag.m_m1 + 5*log10(rho)
X + 2.5*op->o_e.e_mag.m_m2*log10(rp);
X }
X *siz = op->o_e.e_siz / rho;
X }
X break;
X
X case HYPERBOLIC: {
X double dt, lg, lsn, rsn;
X double nu, ea;
X double ma, rp, lo, slo, clo;
X double inc, psi, spsi, cpsi;
X double y, lpd, rpd, ll, rho, sll, cll;
X double om; /* arg of perihelion */
X double Om; /* long of ascending node. */
X double e;
X double a, n; /* semi-major axis, mean daily motion */
X int pass;
X
X dt = 0;
X sunpos (jd, &lsn, &rsn);
X lg = lsn + PI;
X e = op->o_h.h_e;
X a = op->o_h.h_qp/(e - 1.0);
X n = .98563/sqrt(a*a*a);
X
X for (pass = 0; pass < 2; pass++) {
X
X reduce_elements (op->o_h.h_epoch, jd-dt, degrad(op->o_h.h_inc),
X degrad (op->o_h.h_om), degrad (op->o_h.h_Om),
X &inc, &om, &Om);
X
X ma = degrad ((jd - op->o_h.h_ep - dt) * n);
X anomaly (ma, e, &nu, &ea);
X rp = a * (e*e-1.0) / (1.0+e*cos(nu));
X lo = nu + om;
X slo = sin(lo);
X clo = cos(lo);
X spsi = slo*sin(inc);
X y = slo*cos(inc);
X psi = asin(spsi);
X lpd = atan(y/clo)+Om;
X if (clo<0) lpd += PI;
X range (&lpd, 2*PI);
X cpsi = cos(psi);
X rpd = rp*cpsi;
X ll = lpd-lg;
X rho = sqrt(rsn*rsn+rp*rp-2*rsn*rp*cpsi*cos(ll));
X dt = rho*5.775518e-3; /* light travel time, in days */
X if (pass == 0) {
X *lpd0 = lpd;
X *psi0 = psi;
X *rp0 = rp;
X *rho0 = rho;
X }
X }
X
X sll = sin(ll);
X cll = cos(ll);
X if (rpd < rsn)
X *lam = atan(-1*rpd*sll/(rsn-rpd*cll))+lg+PI;
X else
X *lam = atan(rsn*sll/(rpd-rsn*cll))+lpd;
X range (lam, 2*PI);
X *bet = atan(rpd*spsi*sin(*lam-lpd)/(cpsi*rsn*sll));
X
X *mag = op->o_h.h_g + 5*log10(rho) + 2.5*op->o_h.h_k*log10(rp);
X *siz = op->o_h.h_siz / rho;
X }
X break;
X
X case PARABOLIC: {
X double inc, om, Om;
X double lpd, psi, rp, rho;
X double dt;
X int pass;
X
X /* two passes to correct lam and bet for light travel time. */
X dt = 0.0;
X for (pass = 0; pass < 2; pass++) {
X reduce_elements (op->o_p.p_epoch, jd-dt, degrad(op->o_p.p_inc),
X degrad(op->o_p.p_om), degrad(op->o_p.p_Om), &inc, &om, &Om);
X comet (jd-dt, op->o_p.p_ep, inc, om, op->o_p.p_qp, Om,
X &lpd, &psi, &rp, &rho, lam, bet);
X if (pass == 0) {
X *lpd0 = lpd;
X *psi0 = psi;
X *rp0 = rp;
X *rho0 = rho;
X }
X dt = rho*5.775518e-3; /* au to light-days */
X }
X *mag = op->o_p.p_g + 5*log10(rho) + 2.5*op->o_p.p_k*log10(rp);
X *siz = op->o_p.p_siz / rho;
X }
X break;
X
X default:
X f_msg ((p == OBJX) ? "Obj X is not defined"
X : "Obj Y is not defined");
X break;
X }
X}
X
X/* define obj based on the ephem.db line, s.
X * p is one of OBJX or OBJY.
X * format: name,type,[other fields, as per corresponding ObjX typedef]
X * N.B. we replace all ',' within s with '\0' IN PLACE.
X * return 0 if ok, else print reason why not with f_msg() and return -1.
X */
Xobj_define (p, s)
Xint p; /* OBJX or OBJY */
Xchar *s;
X{
X#define MAXARGS 20
X char *av[MAXARGS]; /* point to each field for easy reference */
X char c;
X int ac;
X Obj *op = (p == OBJX) ? &objx : &objy;
X
X /* parse into comma separated fields */
X ac = 0;
X av[0] = s;
X do {
X c = *s++;
X if (c == ',' || c == '\0') {
X s[-1] = '\0';
X av[++ac] = s;
X }
X } while (c);
X
X if (ac < 2) {
X char buf[NC];
X if (ac > 0)
X (void) sprintf (buf, "No type for Object %s", av[0]);
X else
X (void) sprintf (buf, "No fields in %s", s);
X f_msg (buf);
X return (-1);
X }
X
X /* switch out on type of object - the second field */
X switch (av[1][0]) {
X case 'f':
X if (ac != 6 && ac != 7) {
X char buf[NC];
X (void) sprintf(buf,
X "Need ra,dec,mag,D[,siz] for fixed object %s", av[0]);
X f_msg (buf);
X return (-1);
X }
X obj_dfixed (op, ac, av);
X break;
X
X case 'e':
X if (ac != 13 && ac != 14) {
X char buf[NC];
X (void) sprintf (buf,
X "Need i,O,o,a,n,e,M,E,D,H/g,G/k[,siz] for elliptical object %s",
X av[0]);
X f_msg (buf);
X return (-1);
X }
X obj_delliptical (op, ac, av);
X break;
X
X case 'h':
X if (ac != 11 && ac != 12) {
X char buf[NC];
X (void) sprintf (buf,
X "Need T,i,O,o,e,q,D,g,k[,siz] for hyperbolic object %s", av[0]);
X f_msg (buf);
X return (-1);
X }
X obj_dhyperbolic (op, ac, av);
X break;
X
X case 'p':
X if (ac != 10 && ac != 11) {
X char buf[NC];
X (void) sprintf (buf,
X "Need T,i,o,q,O,D,g,k[,siz] for parabolic object %s", av[0]);
X f_msg (buf);
X return (-1);
X }
X obj_dparabolic (op, ac, av);
X break;
X
X default: {
X char buf[NC];
X (void) sprintf (buf, "Unknown type for Object %s: %s",
X av[0], av[1]);
X f_msg (buf);
X return (-1);
X }
X }
X
X return (0);
X}
X
X/* if name, then look it up in the ephem database file and set p.
X * else display a table of all objects and let op pick one.
X * p is either OBJX or OBJY.
X * if -d was used use it; else if EPHEMDB env set use it, else use default.
X * return 0 if successfully set object p, else -1.
X */
Xobj_filelookup (p, name)
Xint p; /* OBJX or OBJY */
Xchar *name;
X{
X/* redefine RCTN,NTR,NTC for column-major order if you prefer */
X#define NLR (NR-1) /* number of rows of names.
X * leave 1 for prompt
X */
X#define LCW 9 /* screen columns per name */
X#define NLC 9 /* total number of name columns */
X#define NL (NLR*NLC) /* total number of names per screen */
X#define RCTN(r,c) ((r)*NLC+(c)) /* row/col to index */
X#define NTR(n) ((n)/NLC) /* index to row */
X#define NTC(n) ((n)%NLC) /* index to col (0 based) */
X /* N.B. all these are 0-based */
X static char prompt[] =
X "RETURN to select, p/n for previous/next page, q to quit";
X FILE *fp;
X char *fn;
X int i, pgn; /* index on current screen, current page number */
X int r, c;
X char buf[160]; /* longer than any one database line */
X char pb[NC]; /* prompt buffer */
X int readahd; /* 1 if buffer set from previous loop */
X int choice; /* index to selection; -1 until set */
X int roaming; /* 1 while just roaming around screen */
X int abandon; /* 1 if decide to not pick afterall */
X
X /* open the database file */
X if (dbfile)
X fn = dbfile;
X else {
X fn = getenv ("EPHEMDB");
X if (!fn)
X fn = dbfdef;
X }
X fp = fopen (fn, "r");
X if (!fp) {
X (void) sprintf (buf, "Can not open database file %s", fn);
X f_msg(buf);
X return(-1);
X }
X
X /* name is specified so just search for it without any op interaction */
X if (name) {
X int nl = strlen (name);
X int ret = 0;
X while (nxt_db(buf, sizeof(buf), fp) == 0 && strncmp(buf, name, nl))
X continue;
X if (feof(fp)) {
X (void) sprintf (buf, "Object %s not found", name);
X f_msg (buf);
X ret = -1;
X } else
X (void) obj_define (p, buf);
X (void) fclose (fp);
X return (ret);
X }
X
X pgn = 0;
X readahd = 0;
X choice = -1;
X abandon = 0;
X
X /* continue until a choice is made or op abandons the attempt */
X do {
X /* put up next screen full of names.
X * leave top row open for messages.
X */
X c_erase();
X for (i = 0; i < NL; )
X if (readahd || nxt_db (buf, sizeof(buf), fp) == 0) {
X char objname[LCW];
X int ii;
X for (ii = 0; ii < sizeof(objname)-1; ii++)
X if ((objname[ii] = buf[ii]) == ',')
X break;
X objname[ii] = '\0';
X if (i == NL-1)
X objname[LCW-2] = '\0'; /* avoid scroll in low-r corner*/
X f_string (NTR(i)+2, NTC(i)*LCW+1, objname);
X i++;
X readahd = 0;
X } else
X break;
X
X /* read another to check for eof. if valid, set readahd for next
X * time.
X */
X if (nxt_db (buf, sizeof(buf), fp) == 0)
X readahd = 1;
X
X /* let op pick one. set cursor on first one.
X * remember these r/c are 0-based, but c_pos() is 1-based
X */
X (void) sprintf (pb, "Page %d%s. %s", pgn+1,
X feof(fp) ? " (last)" : "", prompt);
X f_prompt(pb);
X r = c = 0;
X roaming = 1;
X do {
X c_pos (r+2, c*LCW+1);
X switch (read_char()) {
X case 'h': /* left */
X if (c == 0) c = NLC;
X c -= 1;
X if (RCTN(r,c) >= i)
X c = NTC(i-1);
X break;
X case 'j': /* down */
X if (++r == NLR) r = 0;
X if (RCTN(r,c) >= i)
X r = 0;
X break;
X case 'k': /* up */
X if (r == 0) r = NLR;
X r -= 1;
X while (RCTN(r,c) >= i)
X r -= 1;
X break;
X case 'l': /* right */
X if (++c == NLC) c = 0;
X if (RCTN(r,c) >= i)
X c = 0;
X break;
X case REDRAW:
X /* start over and skip over prior pages' entries */
X rewind(fp);
X for (i = 0; i < NL*pgn; i++)
X (void) nxt_db (buf, sizeof(buf), fp);
X readahd = 0;
X roaming = 0;
X break;
X case 'p':
X /* if not at first page, start over and skip back one
X * pages' entries
X */
X if (pgn > 0) {
X rewind(fp);
X pgn--;
X for (i = 0; i < NL*pgn; i++)
X (void) nxt_db (buf, sizeof(buf), fp);
X readahd = 0;
X roaming = 0;
X }
X break;
X case 'n':
X /* if not already at eof, we can go ahead another page */
X if (!feof (fp)) {
X pgn++;
X roaming = 0;
X }
X break;
X case END:
X abandon = 1;
X roaming = 0;
X break;
X case ' ': case '\r':
X choice = NL*pgn + RCTN(r,c);
X roaming = 0;
X break;
X }
X } while (roaming);
X } while (choice < 0 && !abandon);
X
X if (choice >= 0) {
X /* skip first choice entries; selection is the next one */
X (void) rewind (fp);
X for (i = 0; i < choice; i++)
X (void) nxt_db (buf, sizeof(buf), fp);
X (void) nxt_db (buf, sizeof(buf), fp);
X (void) obj_define (p, buf);
X }
X (void) fclose (fp);
X redraw_screen (2);
X return (choice >= 0 ? 0 : -1);
X}
X
X/* read database file fp and put next valid entry into buf.
X * return 0 if ok, else -1
X */
Xstatic
Xnxt_db (buf, blen, fp)
Xchar buf[];
Xint blen;
XFILE *fp;
X{
X char s;
X while (1) {
X if (fgets (buf, blen, fp) == 0)
X return (-1);
X s = buf[0];
X if (isalpha(s))
X return (0);
X }
X}
X
X/* define a fixed object.
X * args in av, in order, are name, type, ra, dec, magnitude, reference epoch
X * and optional angular size.
X * if av then it is a list of strings to use for each parameter, else must
X * ask for each (but type). the av option is for cracking the ephem.db line.
X * if asking show current settings and leave unchanged if hit RETURN.
X * END aborts without making any more changes.
X * o_type is set to FIXED.
X * N.B. we don't error check av in any way, not even for length.
X */
Xstatic
Xobj_dfixed (op, ac, av)
XObj *op;
Xint ac;
Xchar *av[];
X{
X char buf[NC];
X char *bp;
X int sts;
X
X op->o_type = FIXED;
X
X if (set_name (av, op->o_f.f_name) < 0)
X return;
X
X if (av) {
X bp = av[2];
X sts = 1;
X } else {
X static char p[] = "RA (h:m:s): (";
X f_prompt (p);
X f_ra (R_PROMPT, C_PROMPT+sizeof(p)-1, op->o_f.f_ra);
X (void) printf (") ");
X sts = read_line (buf, 8+1);
X if (sts < 0)
X return;
X bp = buf;
X }
X if (sts > 0) {
X int h, m, s;
X f_dec_sexsign (radhr(op->o_f.f_ra), &h, &m, &s);
X f_sscansex (bp, &h, &m, &s);
X sex_dec (h, m, s, &op->o_f.f_ra);
X op->o_f.f_ra = hrrad(op->o_f.f_ra);
X }
X
X if (av) {
X bp = av[3];
X sts = 1;
X } else {
X static char p[] = "Dec (d:m:s): (";
X f_prompt (p);
X f_gangle (R_PROMPT, C_PROMPT+sizeof(p)-1, op->o_f.f_dec);
X (void) printf (") ");
X sts = read_line (buf, 9+1);
X if (sts < 0)
X return;
X bp = buf;
X }
X if (sts > 0) {
X int dg, m, s;
X f_dec_sexsign (raddeg(op->o_f.f_dec), &dg, &m, &s);
X f_sscansex (bp, &dg, &m, &s);
X sex_dec (dg, m, s, &op->o_f.f_dec);
X op->o_f.f_dec = degrad(op->o_f.f_dec);
X }
X
X if (set_double (av, 4, "Magnitude: ", &op->o_f.f_mag) < 0)
X return;
X
X if (set_year (av, 5,"Reference epoch (UT Date, m/d.d/y or year.d): ",
X DY, &op->o_f.f_epoch) < 0)
X return;
X
X if (ac == 7 || !av)
X (void) set_double (av, 6, "Angular Size: ", &op->o_f.f_siz);
X else
X op->o_f.f_siz = 0.0;
X
X}
X
X/* define an object in an elliptical heliocentric orbit.
X * 13 or 14 args in av, in order, are name, type, inclination, longitude of
X * ascending node, argument of perihelion, mean distance (aka semi-major
X * axis), daily motion, eccentricity, mean anomaly (ie, degrees from
X * perihelion), epoch date (ie, time of the mean anomaly value), equinox year
X * (ie, time of inc/lon/aop), two magnitude coefficients and optional size.
X * the mag may be H/G or g/k model, set by leading g or H (use H/G if none).
X * if av then it is a list of strings to use for each parameter, else must
X * ask for each. the av option is for cracking the ephem.db line.
X * if asking show current settings and leave unchanged if hit RETURN.
X * END aborts without making any more changes.
X * o_type is set to ELLIPTICAL.
X * N.B. we don't error check av in any way, not even for length.
X */
Xstatic
Xobj_delliptical(op, ac, av)
XObj *op;
Xint ac;
Xchar *av[];
X{
X op->o_type = ELLIPTICAL;
X
X if (set_name (av, op->o_e.e_name) < 0)
X return;
X
X if (set_double (av, 2, "Inclination (degs):", &op->o_e.e_inc) < 0)
X return;
X
X if (set_double (av, 3, "Longitude of ascending node (degs):",
X &op->o_e.e_Om) < 0)
X return;
X
X if (set_double (av, 4, "Argument of Perihelion (degs):",
X &op->o_e.e_om) < 0)
X return;
X
X if (set_double (av, 5, "Mean distance (AU):", &op->o_e.e_a) < 0)
X return;
X
X if (set_double (av, 6, "Daily motion (degs/day):", &op->o_e.e_n) < 0)
X return;
X
X if (set_double (av, 7, "Eccentricity:", &op->o_e.e_e) < 0)
X return;
X
X if (set_double (av, 8, "Mean anomaly (degs):", &op->o_e.e_M) < 0)
X return;
X
X if (set_year (av, 9, "Epoch date (UT Date, m/d.d/y or year.d): ",
X YMD, &op->o_e.e_cepoch) < 0)
X return;
X
X if (set_year (av, 10, "Equinox year (UT Date, m/d.d/y or year.d): ",
X DY, &op->o_e.e_epoch) < 0)
X return;
X
X if (set_mag (av, 11, &op->o_e.e_mag) < 0)
X return;
X
X if (ac == 14 || !av)
X (void) set_double (av, 13, "Angular Size @ 1 AU: ", &op->o_e.e_siz);
X else
X op->o_e.e_siz = 0.0;
X
X}
X
X/* define an object in heliocentric hyperbolic orbit.
X * 11 or 12 args in av, in order, are name, type, epoch of perihelion,
X * inclination, longitude of ascending node, argument of perihelion,
X * eccentricity, perihelion distance, reference epoch, absolute magnitude
X * and luminosity index, and optional size.
X * if av then it is a list of strings to use for each parameter, else must
X * ask for each. the av option is for cracking the ephem.db line.
X * if asking show current settings and leave unchanged if hit RETURN.
X * END aborts without making any more changes.
X * o_type is set to HYPERBOLIC.
X * N.B. we don't error check av in any way, not even for length.
X */
Xstatic
Xobj_dhyperbolic (op, ac, av)
XObj *op;
Xint ac;
Xchar *av[];
X{
X op->o_type = HYPERBOLIC;
X
X if (set_name (av, op->o_h.h_name) < 0)
X return;
X
X if (set_year(av,2,"Epoch of perihelion (UT Date, m/d.d/y or year.d): ",
X YMD, &op->o_h.h_ep) < 0)
X return;
X
X if (set_double (av, 3, "Inclination (degs):", &op->o_h.h_inc) < 0)
X return;
X
X if (set_double (av, 4,
X "Longitude of ascending node (degs):", &op->o_h.h_Om) < 0)
X return;
X
X if (set_double(av,5,"Argument of perihelion (degs):", &op->o_h.h_om) <0)
X return;
X
X if (set_double (av, 6, "Eccentricity:", &op->o_h.h_e) < 0)
X return;
X
X if (set_double (av, 7, "Perihelion distance (AU):", &op->o_h.h_qp) < 0)
X return;
X
X if (set_year (av, 8, "Reference epoch (UT Date, m/d.d/y or year.d): ",
X DY, &op->o_h.h_epoch) < 0)
X return;
X
X if (set_double (av, 9, "g:", &op->o_h.h_g) < 0)
X return;
X
X if (set_double (av, 10, "k:", &op->o_h.h_k) < 0)
X return;
X
X if (ac == 12 || !av)
X (void) set_double (av, 11, "Angular Size @ 1 AU: ", &op->o_h.h_siz);
X else
X op->o_h.h_siz = 0.0;
X}
X
X/* define an object in heliocentric parabolic orbit.
X * 10 or 11 args in av, in order, are name, type, epoch of perihelion,
X * inclination, argument of perihelion, perihelion distance, longitude of
X * ascending node, reference epoch, absolute magnitude and luminosity index,
X * and optional size.
X * if av then it is a list of strings to use for each parameter, else must
X * ask for each. the av option is for cracking the ephem.db line.
X * if asking show current settings and leave unchanged if hit RETURN.
X * END aborts without making any more changes.
X * o_type is set to PARABOLIC.
X * N.B. we don't error check av in any way, not even for length.
X */
Xstatic
Xobj_dparabolic(op, ac, av)
XObj *op;
Xint ac;
Xchar *av[];
X{
X op->o_type = PARABOLIC;
X
X if (set_name (av, op->o_p.p_name) < 0)
X return;
X
X if (set_year(av,2,"Epoch of perihelion (UT Date, m/d.d/y or year.d): ",
X YMD, &op->o_p.p_ep) < 0)
X return;
X
X if (set_double (av, 3, "Inclination (degs):", &op->o_p.p_inc) < 0)
X return;
X
X if (set_double(av,4,"Argument of perihelion (degs):", &op->o_p.p_om) <0)
X return;
X
X if (set_double (av, 5, "Perihelion distance (AU):", &op->o_p.p_qp) < 0)
X return;
X
X if (set_double (av, 6,
X "Longitude of ascending node (degs):", &op->o_p.p_Om) < 0)
X return;
X
X if (set_year (av, 7, "Reference epoch (UT Date, m/d.d/y or year.d): ",
X DY, &op->o_p.p_epoch) < 0)
X return;
X
X if (set_double (av, 8, "g:", &op->o_p.p_g) < 0)
X return;
X
X if (set_double (av, 9, "k:", &op->o_p.p_k) < 0)
X return;
X
X if (ac == 11 || !av)
X (void) set_double (av, 10, "Angular Size @ 1 AU: ", &op->o_p.p_siz);
X else
X op->o_p.p_siz = 0.0;
X}
X
Xstatic
Xset_double (av, vn, pr, fp)
Xchar *av[]; /* arg list */
Xint vn; /* which arg */
Xchar *pr; /* prompt */
Xdouble *fp; /* ptr to double to be set */
X{
X int sts;
X char buf[NC];
X char *bp;
X
X if (av) {
X bp = av[vn];
X sts = 1;
X } else {
X f_prompt (pr);
X f_double (R_PROMPT, C_PROMPT+1+strlen(pr), "(%g) ", *fp);
X sts = read_line (buf, 20);
X if (sts < 0)
X return (-1);
X bp = buf;
X }
X if (sts > 0)
X *fp = atof (bp);
X return (0);
X}
X
Xstatic
Xset_name (av, np)
Xchar *av[]; /* arg list */
Xchar *np; /* name to be set */
X{
X int sts;
X char buf[NC];
X char *bp;
X
X if (av) {
X bp = av[0];
X sts = 1;
X } else {
X (void) sprintf (buf, "Name: (%s) ", np);
X f_prompt (buf);
X sts = read_line (buf, MAXNM-1);
X if (sts < 0)
X return (-1);
X bp = buf;
X }
X if (sts > 0)
X (void) strcpy (np, bp);
X return (0);
X}
X
Xstatic
Xset_year (av, vn, pr, type, yp)
Xchar *av[]; /* arg list */
Xint vn; /* which arg */
Xchar *pr; /* prompt */
Xint type; /* display type: YMD or DY */
Xdouble *yp; /* ptr to year to be set */
X{
X int sts;
X char buf[NC];
X char *bp;
X
X if (av) {
X bp = av[vn];
X sts = 1;
X } else {
X f_prompt (pr);
X if (type == DY) {
X double y;
X mjd_year (*yp, &y);
X (void) printf ("(%g) ", y);
X } else {
X int m, y;
X double d;
X mjd_cal (*yp, &m, &d, &y);
X (void) printf ("(%d/%g/%d) ", m, d, y);
X }
X sts = read_line (buf, 20);
X if (sts < 0)
X return (-1);
X bp = buf;
X }
X if (sts > 0)
X crack_year (bp, yp);
X return (0);
X}
X
X/* given either a decimal year (xxxx. something) or a calendar (x/x/x)
X * convert it to an mjd and store it at *p;
X */
Xstatic
Xcrack_year (bp, p)
Xchar *bp;
Xdouble *p;
X{
X if (decimal_year(bp)) {
X double y = atof (bp);
X year_mjd (y, p);
X } else {
X int m, y;
X double d;
X mjd_cal (*p, &m, &d, &y); /* init with current */
X f_sscandate (bp, &m, &d, &y);
X cal_mjd (m, d, y, p);
X }
X}
X
X/* read next two args from av and load the magnitude members m_m1 and m_m2.
X * also set m_whichm to default if this is from the .db file, ie, if av!=0.
X * #,# -> model is unchanged
X * g#,[k]# -> g/k
X * H#,[G]# -> H/G
X */
Xstatic
Xset_mag (av, vn, mp)
Xchar *av[]; /* arg list */
Xint vn; /* which arg. we use av[vn] and av[vn+1] */
XMag *mp;
X{
X int sts;
X char buf[NC];
X char *bp;
X
X if (av) {
X mp->m_whichm = MAG_HG; /* always the default for the db file */
X bp = av[vn];
X sts = 1;
X } else {
X /* show both the value and the type of the first mag param,
X * as well as a hint as to how to set the type if desired.
X */
X (void) sprintf (buf, "%c: (%g) (g# H# or #) ",
X mp->m_whichm == MAG_HG ? 'H' : 'g', mp->m_m1);
X f_prompt (buf);
X sts = read_line (buf, 9);
X if (sts < 0)
X return (-1);
X bp = buf;
X }
X if (sts > 0) {
X switch (bp[0]) {
X case 'g':
X mp->m_whichm = MAG_gk;
X bp++;
X break;
X case 'H':
X mp->m_whichm = MAG_HG;
X bp++;
X default:
X /* leave type unchanged if no prefix */
X break;
X }
X mp->m_m1 = atof (bp);
X }
X
X if (av) {
X bp = av[vn+1];
X sts = 1;
X } else {
X /* can't change the type in the second param */
X (void) sprintf (buf, "%c: (%g) ",
X mp->m_whichm == MAG_HG ? 'G' : 'k', mp->m_m2);
X f_prompt (buf);
X sts = read_line (buf, 9);
X if (sts < 0)
X return (-1);
X bp = buf;
X }
X if (sts > 0) {
X int ok = 0;
X switch (bp[0]) {
X case 'k':
X if (mp->m_whichm == MAG_gk) {
X bp++;
X ok = 1;
X }
X break;
X case 'G':
X if (mp->m_whichm == MAG_HG) {
X bp++;
X ok = 1;
X }
X break;
X default:
X ok = 1;
X break;
X }
X if (ok)
X mp->m_m2 = atof (bp);
X else {
X f_msg ("Can't switch magnitude models at second parameter.");
X return (-1);
X }
X }
X return (0);
X}
END_OF_FILE
if test 29454 -ne `wc -c <'objx.c'`; then
echo shar: \"'objx.c'\" unpacked with wrong size!
fi
# end of 'objx.c'
fi
echo shar: End of archive 3 \(of 9\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 9 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still must unpack the following archives:
echo " " ${MISSING}
fi
exit 0
exit 0 # Just in case...