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 $"};
|
---|