home *** CD-ROM | disk | FTP | other *** search
- /*
- UTIL.C
- Paul S. Hirose, 1990 Nov 12
- User interface support functions for SEESAT satellite tracking program.
-
- 100 - 199
-
- Library functions and #defines used in this file:
-
- atof, atoi, getchar, isalpha, isspace, NULL, printf, strcmp, strcpy,
- strlen, toupper.
- */
-
- #include "b:seesat.h" /* global header */
-
- extern void printf();
- extern int atoi(), getchar(), isalpha(), isspace(),
- strcmp(), strlen(), toupper();
- extern char *strcpy();
- extern double atof();
-
-
- /* Use 0 for normal operation. Non-zero will make static functions & data
- externally visible for testing */
- #define NSTAT 0
-
- #if NSTAT /* test mode */
- #define STATIC /* precedes static definitions of functions & data */
- #define SC extern /* precedes declarations of static functions */
-
- #else /* normal mode */
- #define STATIC static
- #define SC static
- #endif
-
- /*############################## DATA ##############################*/
-
- struct month {
- char *mname; /* month name */
- int difm; /* days in full months */
- };
-
- /* calendar */
- STATIC struct month calndr[] = {
- {"JAN", 0}, {"FEB", 31}, {"MAR", 59},
- {"APR", 90}, {"MAY", 120}, {"JUN", 151},
- {"JUL", 181}, {"AUG", 212}, {"SEP", 243},
- {"OCT", 273}, {"NOV", 304}, {"DEC", 334}, {NULL, 365}
- };
-
- /*################ FUNCTIONS LOCAL TO THIS FILE ################*/
-
- SC void cpy0p(); /* strncpy() with leading 0 padding */
- SC int leapyr(); /* returns 1 if arg is leap year */
- SC char *s_in(); /* input a string with prompt */
-
- /*############################## CODE ##############################*/
-
- double
- atomin(string)
- char *string;
- /* Returns value (in minutes) of string of form "hhmm:ss.s...". Leading
- minus sign permitted. */
- {
- double time;
- char *ptr, c, buf[5];
- int sign;
-
- if (*string == '-') {
- sign = -1;
- ++string;
- } else
- sign = 1;
- ptr = string;
-
- /* point to the colon (or terminating null if no colon) */
- while ((c = *ptr) && c != ':')
- ++ptr;
-
- /* process seconds */
- if (c) { /* string had a colon */
- time = atof(ptr + 1) / 60.;
- *ptr = '\0'; /* turn ':' to '\0' */
- } else
- time = 0.;
-
- cpy0p(buf, string, 5); /* buf[] = "hhmm" */
-
- time += atof(buf + 2); /* add minutes */
- buf[2] = '\0';
- /* add hours, restore sign */
- return (time + atof(buf) * 60.) * sign;
- }
-
-
- STATIC void
- cpy0p(dest, src, n)
- char *dest, *src;
- int n;
- /* Copy n-1 chars from src[] to dest[]. If src[] is too short, pad dest[]
- with leading '0's. If src[] is too long, not all of src[] will be copied.
- dest[] will always receive n-1 chars followed by null terminator. */
- {
- int i, len;
-
- len = strlen(src);
- for (i = n; --i; )
- *dest++ = (i > len) ? '0' : *src++;
- *dest = '\0';
- }
-
-
- char **
- degdms(pre, x)
- int pre; /* precision */
- double x;
- /* Converts x degrees to 3 strings holding degrees, minutes, seconds. "pre"
- specifies rounding and may be 0 - 4: 0 = nearest deg, 1 = nearest 10 min, 2
- = 1 min, 3 = 10 sec, 4 = 1 sec. Domain of x (after rounding): -1000 < x <
- 10000. Returns pointer to dms[]. If pre was 1 or 2, s[] is garbage. Both
- s[] & m[] are garbage if pre was 0. */
- {
- long int lx;
- int sign;
- static int mult[] = {1, 6, 60, 360, 3600};
- static char
- d[5], m[3], sec[3],
- *dms[] = {d, m, sec};
-
- if (x >= 0.)
- sign = 1;
- else {
- sign = -1;
- x = -x;
- }
-
- lx = (long) (x * mult[pre] + .5) * (((unsigned) pre & 1) ? 10 : 1);
- switch (pre) {
- case 4:
- case 3:
- ITOA(sec, (int) (lx % 60)); /* seconds */
- lx /= 60;
- case 2:
- case 1:
- ITOA(m, (int) (lx % 60)); /* minutes */
- lx /= 60;
- }
- ITOA(d, (int) lx * sign); /* degrees */
- return dms;
- }
-
-
- double
- din(str)
- char *str;
- /* Input a double, with default value. Sends '[', str, then "]: " to the
- console. Then waits for user input. If a only a carriage return is struck,
- returns str converted to a double. If a string is typed, returns the string
- converted to double. Backspacing is allowed. */
- {
- char buffer[30];
-
- printf("[%s]:", str);
- if (strlen(s_in(" ", buffer)))
- return atof(buffer);
- else
- return atof(str);
- }
-
-
- char *
- jdstr(jd)
- long int jd; /* Julian Date, unit = days */
- /* Converts jd to Gregorian calendar date. Good for both BC & AD for
- practically any date one might want. More precisely, domain of jd is limited
- by largest/smallest year an int can hold, as well as size of buffer[].
- Returns pointer to year/month/day string, e.g., "1990 JAN 14". */
- {
- static char buffer[13]; /* space for -yyyy mmm dd */
- struct month *calp; /* pointer into calendar */
- int d, m, n;
- int leap; /* flag; 1 = leap yr */
- char *cp;
-
- /* 1721425 = Julian Date @ 1 BC Dec 31 (Gregorian calendar), 12h UT.
- 365.2425 = days per year (over the 400 yr Gregorian cycle). */
- n = (jd - 1721425) / 365.2425;
- if (n >= 0)
- ++n;
-
- /* n = estimated year. Correct the estimate to actual year. The
- preceding formula can mistakenly yield an AD year from a BC jd, but
- the reverse will never happen. Therefore, we need only guard against
- n being DECREMENTED to 0 (which is an undefined year). */
-
- while (1) {
- d = jd - julday(n, 0, 0);
- leap = leapyr(n); /* true if leap year */
- if (d <= 365 + leap && d >= 1)
- break;
- if (d < 1) {
- --n;
- if (n == 0)
- --n; /* skip year 0 */
- } else
- ++n;
- }
- ITOA(buffer, n); /* write the year */
- cp = buffer + strlen(buffer);
- *cp++ = ' ';
-
- /* determine month by moving forward thru the calendar till we
- overshoot, then back up one month */
- calp = calndr; /* point to Jan */
- m = 0; /* month counter; 0 = Jan */
- do {
- n = (++calp)->difm;
- if (++m >= 2) /* March or later */
- n += leap;
- } while (d > n);
- d -= (--calp)->difm + (m >= 2 && leap);
-
- /* write month & day */
- strcpy(cp, calp->mname);
- cp += 3;
- *cp++ = ' ';
- ITOA(cp, d);
- return buffer;
- }
-
-
- long int
- julday(y, m, d)
- int y, m, d; /* year, month (Jan = 0), day */
- /* Returns Julian Date (unit = days) corresponding to 12h UT on given date,
- Gregorian calendar. Jan = month 0. Use -1 for 1 BC, etc. Any integer
- is legal for d. */
- {
- int bc; /* flag; 1 = BC */
-
- if (m > 1) /* after Feb */
- d += leapyr(y); /* add 1 if leap yr */
-
- if (y >= 0) {
- --y;
- bc = 0;
- } else {
- y = -(y + 1);
- bc = 1;
- }
- return ((bc ? 366 : 0) + y*365L + y/4 - y/100 + y/400) *
- (bc ? -1 : 1) + calndr[m].difm + d + 1721425;
- /* 1721425 = Julian Date for 1 BC Dec 31 12h, Gregorian calendar */
- }
-
-
- STATIC int
- leapyr(y)
- int y;
- /* Returns 1 if y is leap year in Gregorian calendar, 0 otherwise. To
- signify BC year use a negative number, e.g., -1 for 1 BC. */
- {
- /* For leap year determination purposes, 1 BC = 0, 2 BC = -1, etc.
- Therefore, we must make an adjustment to y if it's BC. */
- if (y < 0)
- ++y;
- return !(y%4) && y%100 || !(y%400);
- }
-
-
- char *
- stoup(string)
- char *string;
- /* Converts "string" to all upper case, returns "string". */
- {
- char *cp;
- int i;
-
- for (cp = string; i = *cp; ++cp)
- if (isalpha(i))
- *cp = toupper(i);
- return string;
- }
-
-
- STATIC char *
- s_in(prompt, buffer)
- char *prompt, *buffer;
- /* Prints prompt[] on console, puts typed string in buffer[]. Backspacing
- will correct typing mistakes. Will not allow backspacing past the start of
- buffer. Returns pointer to buffer. */
- {
- static char c, *ptr, last;
-
- for (ptr = prompt; *ptr; ++ptr)
- ; /* point to terminating null of prompt */
- last = *(ptr - 1); /* fetch char before the null */
-
- printf("%s", prompt);
- ptr = buffer;
- while ((c = getchar()) != '\n')
- if (c == '\b')
- if (ptr == buffer)
- printf("%c", last);
- else
- --ptr;
- else
- *ptr++ = c;
-
- *ptr = '\0';
- return buffer;
- }
-
-
- char *
- timstr(m)
- double m; /* minutes */
- /* Turns m into a string of format "hhmm:ss" (or "-hhmm:ss" if m is
- negative), rounded to nearest second. Be sure that hours will not require
- more than two digits. String will be padded with zeros to fill out all six
- digits. Returns the string. */
- {
- static char buf[9];
- char *cp, **cpp;
- int minus; /* flag; 1 = negative */
-
- cp = buf;
- cpp = degdms(4, m / 60.);
-
- if (m < 0.) {
- *cp++ = '-';
- minus = 1;
- } else
- minus = 0;
- cpy0p(cp, cpp[0] + minus, 3);
- cpy0p(cp + 2, cpp[1], 3);
- cp[4] = ':';
- cpy0p(cp + 5, cpp[2], 3);
-
- return buf;
- }
-
-
- void
- tok()
- /* tok() prompts user with '>' and accepts a string. String is converted to
- upper case. Each ' ' in the string is replaced with '\0' & successive
- members of tokens[] point to the sub-strings ("tokens") thus created. A
- character sequence containing spaces is considered a single token if it's
- enclosed in quotes (the quotes will not become part of the token). End of
- tokens[] is marked by NULL. On exit, tokp points to tokens[0]. */
- {
- char *cptr;
- char c;
- int notok; /* flag; 1 = not in a token */
- static char
- *tokens[20], /* pointers to cmd line tokens */
- buffer[85]; /* command line buffer */
-
- /* display '>', accept command line */
- s_in(">", buffer);
- stoup(buffer);
- cptr = buffer - 1;
- tokp = tokens; /* point to 1st element of tokens[] */
- notok = 1; /* set "not in token" flag true */
- while (c = *++cptr) /* tokenize the command line */
- if (isspace(c)) {
- notok = 1;
- *cptr = '\0'; /* replace ' ' with '\0' */
- } else if (notok) { /* first char of a token */
- if (c != '"')
- *tokp++ = cptr;
- else { /* quoted token */
- *tokp++ = ++cptr;
- while (*++cptr != '"')
- ; /* find closing '"' */
- *cptr = '\0';
- } notok = 0;
- }
- *tokp = NULL; /* terminate tokens[] */
- tokp = tokens;
- }
-
-
- void
- tokjum(t)
- struct jdtim *t;
- /* Converts command line arguments (pointed to by global "tokp") into Julian
- Date & minutes. NO conversion to UTC occurs! tokp[1] thru [4] = {year,
- month, day, time}. Month must be first 3 letters of name. Year, month, or
- day may be omitted if the arguments to its left are also omitted. On exit,
- tokp will point to next item following the arguments. Returns JD & minutes
- in struct "t". */
- {
- static int date[3]; /* default year, month (Jan = 0), day */
-
- struct month *calp; /* pointer into calendar */
- int m, n;
- char *cp, **cpp;
-
- /* Set n to # of date arguments. Can be 0 - 3. */
-
- /* point cpp to next arg beginning with a letter, or end of cmd line,
- whichever comes first */
- for (cpp = tokp + 1; (cp = *cpp) && !isalpha(*cp); ++cpp)
- ;
-
- if (cp == NULL) /* reached end of command line */
- n = cpp - tokp - 2;
- else { /* is cp[] a month name? */
- for (calp = calndr + 11, m = 11; m >= 0 &&
- strcmp(cp, calp->mname); --calp, --m)
- ; /* look for cp[] in calendar */
- /* if m >= 0 it's a month name, otherwise it's next cmd */
- n = cpp - tokp + ((m >= 0) ? 1 : -2);
- } if (n > 3 || n < 0) {
- printf("%s: INCORRECT ARGUMENTS\n", *tokp);
- LONGJMP(reset, 1);
- }
- /* if year, month, or day were given, set them as new defaults */
- switch (n) {
- case 3:
- date[0] = atoi(*++tokp); /* year */
- case 2:
- date[1] = m; /* month */
- ++tokp;
- case 1:
- date[2] = atoi(*++tokp); /* day */
- }
- if (date[0] == 0) { /* year = 0, i.e., full date not given yet */
- printf("DATE HAS NOT BEEN SET\n");
- LONGJMP(reset, 1);
- }
- /* compute Julian Date & time of day */
- t->jd = julday(date[0], date[1], date[2]);
- t->time = atomin(*++tokp);
-
- ++tokp; /* point to next cmd line token */
- }
-
-
- double
- tokmin()
- /* Same as tokjum() except returns epoch expressed as minutes instead of
- Julian Date & minutes, and the time zone is Greenwich. */
- {
- struct jdtim t;
-
- tokjum(&t);
- return t.jd * xmnpda - 720. + t.time + zd;
- }
- --m)
- ; /* look for cp[] in calendar */
- /* if m >= 0 it's a month name, otherwise it's next cmd */
- n