[1457] | 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 */
|
---|
[1719] | 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 $"};
|
---|