| 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-04-10 14:40:46 $ $Revision: 1.1.1.1 $ $Name: not supported by cvs2svn $"}; | 
|---|