downey@cs.umn.edu@dimed1.UUCP (08/31/90)
Posting-number: Volume 14, Issue 80 Submitted-by: downey@cs.umn.edu@dimed1.UUCP Archive-name: ephem-4.21/part05 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 5 (of 6)." # Contents: io.c objx.c # Wrapped by allbery@uunet on Thu Aug 30 20:46:37 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'io.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'io.c'\" else echo shar: Extracting \"'io.c'\" \(19883 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_NDELAY: does non-blocking tty reads with fcntl(O_NDELAY); otherwise X * this is done with ioctl(..,FIONREAD..). Use which ever works on your X * system. X * USE_TERMIO: use termio.h instead of older generic sgtty.h. 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. also, you don't X * really need to #define VMS since it is inherent in the compiler. X * (thanks to Mr. Karsten Spang, NBI, Copenhagen, spang@nbivax.nbi.dk) X */ X X/* define one of these... */ X#define UNIX X/* #define VMS */ X/* #define TURBO_C */ X X/* then if you defined UNIX you want this too if you don't have FIONREAD */ X/* #define USE_NDELAY */ X X/* and then if you defined UNIX you want this too if using sgtty.h won't compile X * for you. X */ X/* #define USE_TERMIO */ 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 "screen.h" X X#ifdef UNIX X#include <signal.h> X#ifdef USE_TERMIO X#include <termio.h> X#else X#include <sgtty.h> X#endif X#ifdef USE_NDELAY X#include <fcntl.h> X#endif X Xextern char *tgoto(); Xstatic char *cm, *ce, *cl, *kl, *kr, *ku, *kd; /* curses sequences */ Xstatic int tloaded; Xstatic int ttysetup; X#ifdef USE_TERMIO Xstatic struct termio orig_tio; X#else 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 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#else X long n; X if (!ttysetup) setuptty(); 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 curses 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 (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#ifdef USE_TERMIO X ioctl (0, TCSETA, &orig_tio); X#else 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 X if (!ttysetup) setuptty(); X if (tgetent (rawtbuf, tp) != 1) { X printf ("Can't find termcap for %s\n", tp); X exit (1); X } X ptr = tbuf; X ku = egetstr ("ku", &ptr); X kd = egetstr ("kd", &ptr); X kl = egetstr ("kl", &ptr); X kr = egetstr ("kr", &ptr); X cm = egetstr ("cm", &ptr); X ce = egetstr ("ce", &ptr); X cl = egetstr ("cl", &ptr); X UP = egetstr ("up", &ptr); X if (!tgetflag ("bs")) X BC = egetstr ("bc", &ptr); X tloaded = 1; X} X X/* like tgetstr() but discard curses delay codes, for now anyways */ Xstatic char * Xegetstr (name, sptr) Xchar *name; Xchar **sptr; X{ X extern char *tgetstr(); X register char c, *s; X X s = tgetstr (name, sptr); X while (((c = *s) >= '0' && c <= '9') || c == '*') X s += 1; 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#else 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 (c >= ' ') { X putchar (c); X buf[n++] = c; X } X } X X buf[n] = '\0'; X return (n); X} END_OF_FILE if test 19883 -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'\" \(20178 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#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 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_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 double e_m1, e_m2; /* magnitude model coefficients: H/G or g/k */ X int e_whichm; /* MAG_HG (default) or MAG_gk */ X char e_name[MAXNM]; /* name */ X} ObjE; /* object in heliocentric elliptical orbit */ 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_ap; /* 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 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 ObjP o_p; /* the parabolic orbit object */ X} Obj; X#define FIXED 1 X#define ELLIPTICAL 2 X#define PARABOLIC 3 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[5] = { /* leave a slot for "On"/"Off" */ X "Fixed", "Elliptical", "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 PARABOLIC: f = 2; break; X default: f = 3; break; X } X X ask: X pr[4] = op->o_on ? "On" : "Off"; X switch (f = popup (pr, f, 5)) { X case 0: obj_dfixed(op, (char**)0); goto ask; X case 1: obj_delliptical(op, (char**)0); goto ask; X case 2: obj_dparabolic(op, (char**)0); goto ask; X case 3: obj_filelookup (p, (char *)0); goto rechk; X case 4: 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, 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 *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 } X break; X case PARABOLIC: { X double inc, ap, om; X double lpd, psi, rp, rho; X double dt; X int pass; 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_ap), degrad(op->o_p.p_om), &inc, &ap, &om); X comet (jd-dt, op->o_p.p_ep, inc, ap, 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(*rho0) + 2.5*op->o_p.p_k*log10(*rp0); X } X break; 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_whichm == MAG_HG) { X /* this is for 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_m1 + 5.0*log10(rp*rho) X - 2.5*log10((1-op->o_e.e_m2)*Psi_1 + op->o_e.e_m2*Psi_2); X X } else { X /* this uses the g/k model of comets */ X *mag = X op->o_e.e_m1 + 5*log10(*rho0) + 2.5*op->o_e.e_m2*log10(*rp0); X } X } X break; 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) { X char buf[NC]; X (void) sprintf(buf, X "Need ra,dec,mag,epoch for fixed object %s", av[0]); X f_msg (buf); X return (-1); X } X obj_dfixed (op, av); X break; X X case 'e': X if (ac != 13) { X char buf[NC]; X (void) sprintf (buf, X "Need inc,lan,aop,md,dm,ecc,ma,cep,ep,H/g,G/k for elliptical object %s", X av[0]); X f_msg (buf); X return (-1); X } X obj_delliptical (op, av); X break; X X case 'p': X if (ac != 10) { X char buf[NC]; X (void) sprintf (buf, X "Need ep,inc,ap,qp,om,epoch,g,k for parabolic object %s", X av[0]); X f_msg (buf); X return (-1); X } X obj_dparabolic (op, 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/* search through an ephem database file for an entry and use it to define X * either OBJX or OBJY (as set by p). X * if a name, np, is not set then we ask for it. X * if -d was used use it; else if EPHEMDB env set use it, else use default. X * accept first partial match. X */ Xobj_filelookup (p, np) Xint p; /* OBJX or OBJY */ Xchar *np; X{ X FILE *fp; X char *fn; X int nl; X char buf[160]; X char name[64]; X int found; 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; X } X X /* set up object name in name with a trailing ',' */ X if (np) { X (void) strncpy (name, np, sizeof(name)-2); X name[sizeof(name)-2] = '\0'; /* insure trailing '\0' */ X } else { X f_prompt ("Object name: "); X if (read_line (name, sizeof(name)-2) <= 0) X return; X } X nl = strlen (name); X X /* search for first line beginning with name. X * then rest of line is the info. X */ X found = 0; X while (fgets (buf, sizeof(buf), fp)) X if (strncmp (name, buf, nl) == 0) { X found = 1; X break; X } X (void) fclose (fp); X X if (found) X (void) obj_define (p, buf); X else { X (void) sprintf (buf, "Object %s not found", name); X f_msg (buf); X } X} X X/* define a fixed object. X * args in av, in order, are name, type, ra, dec, magnitude and reference epoch. 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, av) XObj *op; 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 (void) set_year (av, 5,"Reference epoch (UT Date, m/d.d/y or year.d): ", X DY, &op->o_f.f_epoch); X X} X X/* define an object in an elliptical heliocentric orbit. X * 13 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), and then two magnitude coefficients. 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, av) XObj *op; 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 (av) X op->o_e.e_whichm = MAG_HG; /* always the default for the db file */ X (void) set_elmag (av, 11, &op->o_e); X X} X X/* define an object in heliocentric parabolic orbit. X * 10 args in av, in order, are name, type, epoch of perihelion, inclination, X * argument of perihelion, perihelion distance, longitude of ascending node, X * reference epoch, absolute magnitude and luminosity index. 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, av) XObj *op; 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_ap) <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 (void) set_double (av, 9, "k:", &op->o_p.p_k); X} 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, 9); 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 two args and load the magnitude members e_m1 and e_m2. X * #,# -> model is unchanged X * g#,[k]# -> g/k X * H#,[G]# -> H/G X */ Xstatic Xset_elmag (av, vn, ep) Xchar *av[]; /* arg list */ Xint vn; /* which arg. we use av[vn] and av[vn+1] */ XObjE *ep; 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 /* 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 ep->e_whichm == MAG_HG ? 'H' : 'g', ep->e_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 ep->e_whichm = MAG_gk; X bp++; X break; X case 'H': X ep->e_whichm = MAG_HG; X bp++; X default: X /* leave type unchanged if no prefix */ X break; X } X ep->e_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 ep->e_whichm == MAG_HG ? 'G' : 'k', ep->e_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 (ep->e_whichm == MAG_gk) { X bp++; X ok = 1; X } X break; X case 'G': X if (ep->e_whichm == MAG_HG) { X bp++; X ok = 1; X } X break; X default: X ok = 1; X break; X } X if (ok) X ep->e_m2 = atof (bp); X else X f_msg ("Can't switch magnitude models at second parameter."); X } X return (0); X} END_OF_FILE if test 20178 -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 5 \(of 6\). cp /dev/null ark5isdone MISSING="" for I in 1 2 3 4 5 6 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 6 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0