source: Sophya/trunk/SophyaExt/XephemAstroLib/formats.c@ 1783

Last change on this file since 1783 was 1719, checked in by cmv, 24 years ago

Adapted to version 3.5 xephem cmv 22/10/2001

File size: 7.5 KB
Line 
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 */
20void
21fs_sexa (out, a, w, fracbase)
22char *out;
23double a;
24int w;
25int 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 */
84void
85fs_date (out, jd)
86char out[];
87double 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 */
125void
126f_scansex (o, bp, np)
127double o; /* old value */
128char bp[]; /* input string */
129double *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 */
189void
190f_sscandate (bp, pref, m, d, y)
191char *bp;
192int pref; /* one of PREF_X for PREF_DATE_FORMAT */
193int *m, *y;
194double *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 */
280int
281scansex (str, dp)
282char *str;
283double *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 */
307static char *rcsid[2] = {(char *)rcsid, "@(#) $RCSfile: formats.c,v $ $Date: 2001-10-22 12:08:27 $ $Revision: 1.2 $ $Name: not supported by cvs2svn $"};
Note: See TracBrowser for help on using the repository browser.