1 #include "astro.h"
2 #include "preferences.h"
3
4 #include <stdio.h>
5 #include <math.h>
6 #include <ctype.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 double ascii_strtod(const char *s00, char **se); /* for PyEphem */
11
12 /* sprint the variable a in sexagesimal format into out[].
13 * w is the number of spaces for the whole part.
14 * fracbase is the number of pieces a whole is to broken into; valid options:
15 * 360000: <w>:mm:ss.ss
16 * 36000: <w>:mm:ss.s
17 * 3600: <w>:mm:ss
18 * 600: <w>:mm.m
19 * 60: <w>:mm
20 * return number of characters written to out, not counting final '\0'.
21 */
22 int
fs_sexa(char * out,double a,int w,int fracbase)23 fs_sexa (char *out, double a, int w, int fracbase)
24 {
25 char *out0 = out;
26 unsigned long n;
27 int d;
28 int f;
29 int m;
30 int s;
31 int isneg;
32
33 /* save whether it's negative but do all the rest with a positive */
34 isneg = (a < 0);
35 if (isneg)
36 a = -a;
37
38 /* convert to an integral number of whole portions */
39 n = (unsigned long)(a * fracbase + 0.5);
40 d = n/fracbase;
41 f = n%fracbase;
42
43 /* form the whole part; "negative 0" is a special case */
44 if (isneg && d == 0)
45 out += sprintf (out, "%*s-0", w-2, "");
46 else
47 out += sprintf (out, "%*d", w, isneg ? -d : d);
48
49 /* do the rest */
50 switch (fracbase) {
51 case 60: /* dd:mm */
52 m = f/(fracbase/60);
53 out += sprintf (out, ":%02d", m);
54 break;
55 case 600: /* dd:mm.m */
56 out += sprintf (out, ":%02d.%1d", f/10, f%10);
57 break;
58 case 3600: /* dd:mm:ss */
59 m = f/(fracbase/60);
60 s = f%(fracbase/60);
61 out += sprintf (out, ":%02d:%02d", m, s);
62 break;
63 case 36000: /* dd:mm:ss.s*/
64 m = f/(fracbase/60);
65 s = f%(fracbase/60);
66 out += sprintf (out, ":%02d:%02d.%1d", m, s/10, s%10);
67 break;
68 case 360000: /* dd:mm:ss.ss */
69 m = f/(fracbase/60);
70 s = f%(fracbase/60);
71 out += sprintf (out, ":%02d:%02d.%02d", m, s/100, s%100);
72 break;
73 default:
74 printf ("fs_sexa: unknown fracbase: %d\n", fracbase);
75 abort();
76 }
77
78 return (out - out0);
79 }
80
81 /* put the given modified Julian date, jd, in out[] according to the given
82 * preference format.
83 * return number of characters written to out, not counting final '\0'.
84 */
85 int
fs_date(char out[],int format,double jd)86 fs_date (char out[], int format, double jd)
87 {
88 char *out0 = out;
89 int m, y;
90 double d;
91
92 mjd_cal (jd, &m, &d, &y);
93 /* beware of %g rounding day up */
94 if ((d < 1.0 && d - floor(d) >= .9999995)
95 || (d < 10.0 && d - floor(d) >= .999995)
96 || (d >= 10.0 && d - floor(d) >= .99995))
97 mjd_cal (mjd_day(jd+0.5), &m, &d, &y);
98
99 switch (format) {
100 case PREF_YMD:
101 out += sprintf (out, "%4d/%02d/%02.6g", y, m, d);
102 break;
103 case PREF_DMY:
104 out += sprintf (out, "%2.6g/%02d/%-4d", d, m, y);
105 break;
106 case PREF_MDY:
107 out += sprintf (out, "%2d/%02.6g/%-4d", m, d, y);
108 break;
109 default:
110 printf ("fs_date: bad date pref: %d\n", format);
111 abort();
112 }
113
114 return (out - out0);
115 }
116
117
118 /* convert sexagesimal string str A:B:C to double.
119 * Any missing A, B or C will be assumed 0.
120 * optional - and + can be anywhere.
121 * return 0 if ok, -1 if can't find a thing or A, B or C are invalid numbers.
122 */
123 int
f_scansexa(const char * str0,double * dp)124 f_scansexa (
125 const char *str0, /* input string */
126 double *dp) /* cracked value, if return 0 */
127 {
128 double a, b, c;
129 char str[256];
130 char *neg, *s, *end;
131 int isneg, status;
132
133 /* copy str0 so we can play with it */
134 strncpy (str, str0, sizeof(str)-1);
135 str[sizeof(str)-1] = '\0';
136
137 /* note first negative (but not fooled by neg exponent) */
138 isneg = 0;
139 neg = strchr(str, '-');
140 if (neg && (neg == str || (neg[-1] != 'E' && neg[-1] != 'e'))) {
141 *neg = ' ';
142 isneg = 1;
143 }
144
145 /* These three calls replace an old, locale-sensitive sscanf.
146 Note that, per the semantics of the strtod call, if we run
147 out of valid numbers to parse, then the last few values will
148 just get zero. */
149 status = 0;
150 s = str;
151 a = ascii_strtod(s, &end);
152 if (end == s) { /* since a will be -1 */
153 a = 0.0;
154 /* don't fail if A is an empty string */
155 if ((*end != ':') && (*end != '\0')) status = -1;
156 }
157 s = end;
158 if (*s == ':') s++;
159 b = ascii_strtod(s, &end);
160 if (end == s) { /* since b will be -1 */
161 b = 0.0;
162 /* don't fail if B is an empty string */
163 if ((*end != ':') && (*end != '\0')) status = -1;
164 }
165 s = end;
166 if (*s == ':') s++;
167 c = ascii_strtod(s, &end);
168 if (end == s) { /* since c will be -1 */
169 c = 0.0;
170 /* don't fail if C is an empty string */
171 if ((*end != ':') && (*end != '\0')) status = -1;
172 }
173
174 /* back to one value, restoring neg */
175 *dp = a + b/60.0 + c/3600.0;
176 if (isneg)
177 *dp *= -1;
178 return status;
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 * the slashes may also be spaces or colons.
185 * a lone component with a decimal point is considered a year.
186 * Brandon Rhodes: 2011-11-24 supplemented this to allow dash separators.
187 */
188 void
f_sscandate(char * bp,int pref,int * m,double * d,int * y)189 f_sscandate (
190 char *bp,
191 int pref, /* one of PREF_X for PREF_DATE_FORMAT */
192 int *m,
193 double *d,
194 int *y)
195 {
196 double X,Y,Z; /* the three components */
197 char *s, *end;
198 int n;
199
200 X = Y = Z = 0.0;
201
202 /* This replaces an old, locale-sensitive sscanf(). */
203 X = ascii_strtod(bp, &end);
204 if (bp == end) {
205 n = 0;
206 X = 0.0; /* X will be -1 */
207 } else {
208 s = end;
209 if (*s == '-' || *s == '/' || *s == ':') s++;
210 Y = ascii_strtod(s, &end);
211 if (s == end) {
212 n = 1;
213 Y = 0.0; /* Y will be -1 */
214 } else {
215 s = end;
216 if (*s == '-' || *s == '/' || *s == ':') s++;
217 Z = ascii_strtod(s, &end);
218 if (s == end) {
219 n = 2;
220 Z = 0.0; /* Z will be -1 */
221 } else {
222 n = 3;
223 }
224 }
225 }
226
227
228 if (n == 1 && (strchr(bp, '.')
229 || (pref == PREF_MDY && (X < 1 || X > 12))
230 || (pref == PREF_DMY && (X < 1 || X > 31)))) {
231 double Mjd;
232 year_mjd (X, &Mjd);
233 mjd_cal (Mjd, m, d, y);
234 } else {
235 switch (pref) {
236 case PREF_MDY:
237 if (n > 0 && X != 0)
238 *m = (int)X;
239 if (n > 1 && Y != 0)
240 *d = Y;
241 if (n > 2 && Z != 0)
242 *y = (int)Z;
243 break;
244 case PREF_YMD:
245 if (n > 0 && X != 0)
246 *y = (int)X;
247 if (n > 1 && Y != 0)
248 *m = (int)Y;
249 if (n > 2 && Z != 0)
250 *d = Z;
251 break;
252 case PREF_DMY:
253 if (n > 0 && X != 0)
254 *d = X;
255 if (n > 1 && Y != 0)
256 *m = (int)Y;
257 if (n > 2 && Z != 0)
258 *y = (int)Z;
259 break;
260 }
261 }
262 }
263
264