| 1 | #include <stdio.h>
 | 
|---|
| 2 | #include <math.h>
 | 
|---|
| 3 | #include <ctype.h>
 | 
|---|
| 4 | #include <stdlib.h>
 | 
|---|
| 5 | #include <string.h>
 | 
|---|
| 6 | 
 | 
|---|
| 7 | #include "P_.h"
 | 
|---|
| 8 | #include "astro.h"
 | 
|---|
| 9 | #include "preferences.h"
 | 
|---|
| 10 | 
 | 
|---|
| 11 | /* sprint the variable a in sexagesimal format into out[].
 | 
|---|
| 12 |  * w is the number of spaces for the whole part.
 | 
|---|
| 13 |  * fracbase is the number of pieces a whole is to broken into; valid options:
 | 
|---|
| 14 |  *      360000: <w>:mm:ss.ss
 | 
|---|
| 15 |  *      36000:  <w>:mm:ss.s
 | 
|---|
| 16 |  *      3600:   <w>:mm:ss
 | 
|---|
| 17 |  *      600:    <w>:mm.m
 | 
|---|
| 18 |  *      60:     <w>:mm
 | 
|---|
| 19 |  */
 | 
|---|
| 20 | void
 | 
|---|
| 21 | fs_sexa (out, a, w, fracbase)
 | 
|---|
| 22 | char *out;
 | 
|---|
| 23 | double a;
 | 
|---|
| 24 | int w;
 | 
|---|
| 25 | int fracbase;
 | 
|---|
| 26 | {
 | 
|---|
| 27 |         unsigned long n;
 | 
|---|
| 28 |         int d;
 | 
|---|
| 29 |         int f;
 | 
|---|
| 30 |         int m;
 | 
|---|
| 31 |         int s;
 | 
|---|
| 32 |         int isneg;
 | 
|---|
| 33 | 
 | 
|---|
| 34 |         /* save whether it's negative but do all the rest with a positive */
 | 
|---|
| 35 |         isneg = (a < 0);
 | 
|---|
| 36 |         if (isneg)
 | 
|---|
| 37 |             a = -a;
 | 
|---|
| 38 | 
 | 
|---|
| 39 |         /* convert to an integral number of whole portions */
 | 
|---|
| 40 |         n = (unsigned long)(a * fracbase + 0.5);
 | 
|---|
| 41 |         d = n/fracbase;
 | 
|---|
| 42 |         f = n%fracbase;
 | 
|---|
| 43 | 
 | 
|---|
| 44 |         /* form the whole part; "negative 0" is a special case */
 | 
|---|
| 45 |         if (isneg && d == 0)
 | 
|---|
| 46 |             (void) sprintf (out, "%*s-0", w-2, "");
 | 
|---|
| 47 |         else
 | 
|---|
| 48 |             (void) sprintf (out, "%*d", w, isneg ? -d : d);
 | 
|---|
| 49 |         out += w;
 | 
|---|
| 50 | 
 | 
|---|
| 51 |         /* do the rest */
 | 
|---|
| 52 |         switch (fracbase) {
 | 
|---|
| 53 |         case 60:        /* dd:mm */
 | 
|---|
| 54 |             m = f/(fracbase/60);
 | 
|---|
| 55 |             (void) sprintf (out, ":%02d", m);
 | 
|---|
| 56 |             break;
 | 
|---|
| 57 |         case 600:       /* dd:mm.m */
 | 
|---|
| 58 |             (void) sprintf (out, ":%02d.%1d", f/10, f%10);
 | 
|---|
| 59 |             break;
 | 
|---|
| 60 |         case 3600:      /* dd:mm:ss */
 | 
|---|
| 61 |             m = f/(fracbase/60);
 | 
|---|
| 62 |             s = f%(fracbase/60);
 | 
|---|
| 63 |             (void) sprintf (out, ":%02d:%02d", m, s);
 | 
|---|
| 64 |             break;
 | 
|---|
| 65 |         case 36000:     /* dd:mm:ss.s*/
 | 
|---|
| 66 |             m = f/(fracbase/60);
 | 
|---|
| 67 |             s = f%(fracbase/60);
 | 
|---|
| 68 |             (void) sprintf (out, ":%02d:%02d.%1d", m, s/10, s%10);
 | 
|---|
| 69 |             break;
 | 
|---|
| 70 |         case 360000:    /* dd:mm:ss.ss */
 | 
|---|
| 71 |             m = f/(fracbase/60);
 | 
|---|
| 72 |             s = f%(fracbase/60);
 | 
|---|
| 73 |             (void) sprintf (out, ":%02d:%02d.%02d", m, s/100, s%100);
 | 
|---|
| 74 |             break;
 | 
|---|
| 75 |         default:
 | 
|---|
| 76 |             printf ("fs_sexa: unknown fracbase: %d\n", fracbase);
 | 
|---|
| 77 |             exit(1);
 | 
|---|
| 78 |         }
 | 
|---|
| 79 | }
 | 
|---|
| 80 | 
 | 
|---|
| 81 | /* put the given modified Julian date, jd, in out[] according to preference
 | 
|---|
| 82 |  * format.
 | 
|---|
| 83 |  */
 | 
|---|
| 84 | void
 | 
|---|
| 85 | fs_date (out, jd)
 | 
|---|
| 86 | char out[];
 | 
|---|
| 87 | double jd;
 | 
|---|
| 88 | {
 | 
|---|
| 89 |         int p = pref_get (PREF_DATE_FORMAT);
 | 
|---|
| 90 |         int m, y;
 | 
|---|
| 91 |         double d;
 | 
|---|
| 92 | 
 | 
|---|
| 93 |         mjd_cal (jd, &m, &d, &y);
 | 
|---|
| 94 |         /* beware of %g rounding day up */
 | 
|---|
| 95 |         if ((d < 1.0 && d - floor(d) >= .9999995)
 | 
|---|
| 96 |                                     || (d < 10.0 && d - floor(d) >= .999995)
 | 
|---|
| 97 |                                     || (d >= 10.0 && d - floor(d) >= .99995))
 | 
|---|
| 98 |             mjd_cal (mjd_day(jd+0.5), &m, &d, &y);
 | 
|---|
| 99 | 
 | 
|---|
| 100 |         switch (p) {
 | 
|---|
| 101 |         case PREF_YMD:
 | 
|---|
| 102 |             (void) sprintf (out, "%4d/%02d/%02.6g", y, m, d);
 | 
|---|
| 103 |             break;
 | 
|---|
| 104 |         case PREF_DMY:
 | 
|---|
| 105 |             (void) sprintf (out, "%2.6g/%02d/%-4d", d, m, y);
 | 
|---|
| 106 |             break;
 | 
|---|
| 107 |         case PREF_MDY:
 | 
|---|
| 108 |             (void) sprintf (out, "%2d/%02.6g/%-4d", m, d, y);
 | 
|---|
| 109 |             break;
 | 
|---|
| 110 |         default:
 | 
|---|
| 111 |             printf ("fs_date: bad date pref: %d\n", p);
 | 
|---|
| 112 |             exit (1);
 | 
|---|
| 113 |         }
 | 
|---|
| 114 | }
 | 
|---|
| 115 | 
 | 
|---|
| 116 | /* scan a sexagesimal string and update a double. the string is of the form
 | 
|---|
| 117 |  *   H:M:S. a negative value may be indicated by a '-' char before any
 | 
|---|
| 118 |  *   component. All components may be integral or real. In addition to ':' the
 | 
|---|
| 119 |  *    separator may also be '/' or ';' or ',' or '-'.
 | 
|---|
| 120 |  * any components not specified in bp[] are copied from old's.
 | 
|---|
| 121 |  *   eg:  ::10  only changes S
 | 
|---|
| 122 |  *        10    only changes H
 | 
|---|
| 123 |  *        10:0  changes H and M
 | 
|---|
| 124 |  */
 | 
|---|
| 125 | void
 | 
|---|
| 126 | f_scansex (o, bp, np)
 | 
|---|
| 127 | double o;       /* old value */
 | 
|---|
| 128 | char bp[];      /* input string */
 | 
|---|
| 129 | double *np;     /* new value */
 | 
|---|
| 130 | {
 | 
|---|
| 131 |         double oh, om, os;
 | 
|---|
| 132 |         double nh, nm, ns;
 | 
|---|
| 133 |         int nneg;
 | 
|---|
| 134 |         double tmp;
 | 
|---|
| 135 |         char c;
 | 
|---|
| 136 | 
 | 
|---|
| 137 |         /* fast macro to scan each segment of bp */
 | 
|---|
| 138 | #define SCANSEX(new,old)                                                \
 | 
|---|
| 139 |         if (*bp == '-') {nneg = 1; bp++;}                               \
 | 
|---|
| 140 |         if (sscanf (bp, "%lf", &new) != 1) new = old;                   \
 | 
|---|
| 141 |         while ((c=(*bp)) != '\0') {                                     \
 | 
|---|
| 142 |             bp++;                                                       \
 | 
|---|
| 143 |             if (c==':' || c=='/' || c==';' || c==',' || c=='-')         \
 | 
|---|
| 144 |                 break;                                                  \
 | 
|---|
| 145 |         }
 | 
|---|
| 146 | 
 | 
|---|
| 147 |         /* get h:m:s components of o in case bp[] defers.
 | 
|---|
| 148 |          * and constrain to positive for now.
 | 
|---|
| 149 |          */
 | 
|---|
| 150 |         if (o < 0.0)
 | 
|---|
| 151 |             o = -o;
 | 
|---|
| 152 |         oh = floor(o);
 | 
|---|
| 153 |         tmp = (o - oh)*60.0;
 | 
|---|
| 154 |         om = floor(tmp);
 | 
|---|
| 155 |         os = (tmp - om)*60.0;
 | 
|---|
| 156 |         
 | 
|---|
| 157 |         /* round to small portion of a second to reduce differencing errors. */
 | 
|---|
| 158 |         if (os > 59.99999) {
 | 
|---|
| 159 |             os = 0.0;
 | 
|---|
| 160 |             if ((om += 1.0) >= 60.0) {
 | 
|---|
| 161 |                 om = 0.0;
 | 
|---|
| 162 |                 oh += 1.0;
 | 
|---|
| 163 |             }
 | 
|---|
| 164 |         }
 | 
|---|
| 165 | 
 | 
|---|
| 166 |         /* scan each component of the buffer */
 | 
|---|
| 167 |         while (*bp == ' ') bp++;
 | 
|---|
| 168 |         nneg = 0;
 | 
|---|
| 169 |         SCANSEX (nh, oh)
 | 
|---|
| 170 |         SCANSEX (nm, om)
 | 
|---|
| 171 |         SCANSEX (ns, os)
 | 
|---|
| 172 | 
 | 
|---|
| 173 |         /* back to hours */
 | 
|---|
| 174 |         tmp = ns/3600.0 + nm/60.0 + nh;
 | 
|---|
| 175 |         if (nneg)
 | 
|---|
| 176 |             tmp = -tmp;
 | 
|---|
| 177 | 
 | 
|---|
| 178 |         *np = tmp;
 | 
|---|
| 179 | }
 | 
|---|
| 180 | 
 | 
|---|
| 181 | /* crack a floating date string, bp, of the form X/Y/Z determined by the
 | 
|---|
| 182 |  *   PREF_DATE_FORMAT preference into its components. allow the day to be a
 | 
|---|
| 183 |  *   floating point number,
 | 
|---|
| 184 |  * a lone component is always a year if it contains a decimal point or pref
 | 
|---|
| 185 |  *   is MDY or DMY and it is not a reasonable month or day value, respectively.
 | 
|---|
| 186 |  * leave any unspecified component unchanged.
 | 
|---|
| 187 |  * actually, the slashes may be anything but digits or a decimal point.
 | 
|---|
| 188 |  */
 | 
|---|
| 189 | void
 | 
|---|
| 190 | f_sscandate (bp, pref, m, d, y)
 | 
|---|
| 191 | char *bp;
 | 
|---|
| 192 | int pref;       /* one of PREF_X for PREF_DATE_FORMAT */
 | 
|---|
| 193 | int *m, *y;
 | 
|---|
| 194 | double *d;
 | 
|---|
| 195 | {
 | 
|---|
| 196 |         double comp[3]; /* the three components */
 | 
|---|
| 197 |         int set[3];     /* set[i] is 1 if component i is present */
 | 
|---|
| 198 |         int in;         /* scan state: 1 while we are in a component */
 | 
|---|
| 199 |         int ncomp;      /* incremented as each component is discovered */
 | 
|---|
| 200 |         int ndp;        /* number of decimal points in last component */
 | 
|---|
| 201 |         char *bp0 = NULL, c;
 | 
|---|
| 202 | 
 | 
|---|
| 203 |         set[0] = set[1] = set[2] = 0;
 | 
|---|
| 204 |         ncomp = 0;
 | 
|---|
| 205 |         in = 0;
 | 
|---|
| 206 |         ndp = 0;
 | 
|---|
| 207 | 
 | 
|---|
| 208 |         /* scan the input string.
 | 
|---|
| 209 |          * '\0' counts as a component terminator too.
 | 
|---|
| 210 |          */
 | 
|---|
| 211 |         do {
 | 
|---|
| 212 |             /* here, *bp is the next character to be investigated */
 | 
|---|
| 213 |             c = *bp;
 | 
|---|
| 214 |             if (c == '.' || isdigit(c) || (c == '-' && !in)) {
 | 
|---|
| 215 |                 /* found what passes for a floating point number */
 | 
|---|
| 216 |                 if (in == 0) {
 | 
|---|
| 217 |                     /* save the beginning of it in bp0 and init ndp */
 | 
|---|
| 218 |                     bp0 = bp;
 | 
|---|
| 219 |                     in = 1;
 | 
|---|
| 220 |                     ndp = 0;
 | 
|---|
| 221 |                 }
 | 
|---|
| 222 |                 if (c == '.')
 | 
|---|
| 223 |                     ndp++;
 | 
|---|
| 224 |             } else if (c != ' ') {
 | 
|---|
| 225 |                 /* not in a number now ... */
 | 
|---|
| 226 |                 if (in) {
 | 
|---|
| 227 |                     /* ... but we *were* in a number, so it counts */
 | 
|---|
| 228 |                     if (ncomp >= 3)
 | 
|---|
| 229 |                         return; /* too many components.. just bail */
 | 
|---|
| 230 |                     comp[ncomp] = atod (bp0);
 | 
|---|
| 231 |                     set[ncomp] = 1;
 | 
|---|
| 232 |                     in = 0;
 | 
|---|
| 233 |                 }
 | 
|---|
| 234 | 
 | 
|---|
| 235 |                 /* regardless, a non-blank non-float means another component */
 | 
|---|
| 236 |                 ncomp++;
 | 
|---|
| 237 |             }
 | 
|---|
| 238 |             bp++;
 | 
|---|
| 239 |         } while (c);
 | 
|---|
| 240 | 
 | 
|---|
| 241 |         /* it's a decimal year if there is exactly one component and
 | 
|---|
| 242 |          *   it contains a decimal point
 | 
|---|
| 243 |          *   or we are in MDY format and it's not in the range 1..12
 | 
|---|
| 244 |          *   or we are in DMY format and it's not int the rangle 1..31
 | 
|---|
| 245 |          */
 | 
|---|
| 246 |         if (ncomp == 1 &&
 | 
|---|
| 247 |                 (ndp > 0
 | 
|---|
| 248 |                  || (pref == PREF_MDY && !(comp[0] >= 1 && comp[0] <= 12))
 | 
|---|
| 249 |                  || (pref == PREF_DMY && !(comp[0] >= 1 && comp[0] <= 31)))) {
 | 
|---|
| 250 |             double Mjd;
 | 
|---|
| 251 |             year_mjd (comp[0], &Mjd);
 | 
|---|
| 252 |             mjd_cal (Mjd, m, d, y);
 | 
|---|
| 253 |             return;
 | 
|---|
| 254 |         }
 | 
|---|
| 255 | 
 | 
|---|
| 256 |         switch (pref) {
 | 
|---|
| 257 |         case PREF_MDY:
 | 
|---|
| 258 |             if (set[0]) *m = (int)comp[0];
 | 
|---|
| 259 |             if (set[1]) *d = comp[1];
 | 
|---|
| 260 |             if (set[2]) *y = (int)comp[2];
 | 
|---|
| 261 |             break;
 | 
|---|
| 262 |         case PREF_YMD:
 | 
|---|
| 263 |             if (set[0]) *y = (int)comp[0];
 | 
|---|
| 264 |             if (set[1]) *m = (int)comp[1];
 | 
|---|
| 265 |             if (set[2]) *d = comp[2];
 | 
|---|
| 266 |             break;
 | 
|---|
| 267 |         case PREF_DMY:
 | 
|---|
| 268 |             if (set[0]) *d = comp[0];
 | 
|---|
| 269 |             if (set[1]) *m = (int)comp[1];
 | 
|---|
| 270 |             if (set[2]) *y = (int)comp[2];
 | 
|---|
| 271 |             break;
 | 
|---|
| 272 |         }
 | 
|---|
| 273 | }
 | 
|---|
| 274 | 
 | 
|---|
| 275 | /* given a string of the form xx:mm[:ss] or xx:mm.dd, convert it to a double at
 | 
|---|
| 276 |  * *dp. actually, ':' may also be ';', '/' or ',' too. all components may be 
 | 
|---|
| 277 |  * floats.
 | 
|---|
| 278 |  * return -1 if trouble, else 0
 | 
|---|
| 279 |  */
 | 
|---|
| 280 | int
 | 
|---|
| 281 | scansex (str, dp)
 | 
|---|
| 282 | char *str;
 | 
|---|
| 283 | double *dp;
 | 
|---|
| 284 | {
 | 
|---|
| 285 |         double x, m = 0.0, s = 0.0;
 | 
|---|
| 286 |         int isneg;
 | 
|---|
| 287 |         int nf;
 | 
|---|
| 288 | 
 | 
|---|
| 289 |         while (isspace(*str))
 | 
|---|
| 290 |             str++;
 | 
|---|
| 291 |         if (*str == '-') {
 | 
|---|
| 292 |             isneg = 1;
 | 
|---|
| 293 |             str++;
 | 
|---|
| 294 |         } else
 | 
|---|
| 295 |             isneg = 0;
 | 
|---|
| 296 | 
 | 
|---|
| 297 |         nf = sscanf (str, "%lf%*[:;/,]%lf%*[:;/,]%lf", &x, &m, &s);
 | 
|---|
| 298 |         if (nf < 1)
 | 
|---|
| 299 |             return (-1);
 | 
|---|
| 300 |         *dp = x + m/60.0 + s/3600.0;
 | 
|---|
| 301 |         if (isneg)
 | 
|---|
| 302 |             *dp = - *dp;
 | 
|---|
| 303 |         return (0);
 | 
|---|
| 304 | }
 | 
|---|
| 305 | 
 | 
|---|
| 306 | /* For RCS Only -- Do Not Edit */
 | 
|---|
| 307 | static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile: formats.c,v $ $Date: 2001-10-22 12:08:27 $ $Revision: 1.2 $ $Name: not supported by cvs2svn $"};
 | 
|---|