1 #include <cerrno>
2 #include <clocale>
3 #include <cmath>
4 #include <cstdio>
5 #include <cstdlib>
6 #include <cstring>
7 #include <ctime>
8 #include <iostream>
9 #include <sstream>
10 #include <string>
11 using namespace std;
12
13 #include <unistd.h>
14 extern char **environ;
15
16 #include "config.h"
17
18 #ifdef HAVE_ICONV
19 # include <iconv.h>
20 # ifdef HAVE_LIBCHARSET
21 # include <localcharset.h>
22 # else
23 # ifdef HAVE_LANGINFO_H
24 # include <langinfo.h>
25 # else
26 # define NO_ICONV
27 # endif
28 # endif
29 #else
30 # define NO_ICONV
31 #endif
32
33 #include "Options.h"
34 #include "xpUtil.h"
35
36 void
xpExit(const string & message,const char * file,const int line)37 xpExit(const string &message, const char *file, const int line)
38 {
39 cerr << "Error: " << message;
40 cerr << "Exiting from " << file << " at line " << line << endl;
41
42 #if 0
43 // force a segfault
44 const char *const ptr = NULL;
45 cout << ptr[5000] << endl;
46 cout.flush();
47 #endif
48
49 exit(EXIT_FAILURE);
50 }
51
52 void
xpWarn(const string & message,const char * file,const int line)53 xpWarn(const string &message, const char *file, const int line)
54 {
55 Options *options = Options::getInstance();
56 if (options->Verbosity() >= 0)
57 {
58 cerr << "Warning: " << message;
59 if (options->Verbosity() > 0)
60 cerr << "In " << file << " at line " << line << endl << endl;
61 cerr.flush();
62 }
63 }
64
65 void
xpMsg(const string & message,const char * file,const int line)66 xpMsg(const string &message, const char *file, const int line)
67 {
68 Options *options = Options::getInstance();
69 if (options->Verbosity() > 0)
70 {
71 cout << message;
72 cout.flush();
73 }
74 }
75
76 void
removeFromEnvironment(const char * name)77 removeFromEnvironment(const char *name)
78 {
79 #ifdef HAVE_UNSETENV
80 unsetenv(name);
81 #else
82 string badname = name;
83 badname += "=";
84
85 // I found this useful code on groups.google.com. It's based on
86 // sudo's code, where the environment is cleaned up before
87 // executing anything.
88 char **cur, **move;
89 for (cur = environ; *cur; cur++) {
90 if (strncmp(*cur, badname.c_str(), badname.length()) == 0)
91 {
92 /* Found variable; move subsequent variables over it */
93 for (move = cur; *move; move++)
94 *move = *(move + 1);
95 cur--;
96 }
97 }
98
99 #endif
100 }
101
102 void
unlinkFile(const char * name)103 unlinkFile(const char *name)
104 {
105 if (unlink(name) == -1)
106 {
107 ostringstream errStr;
108 errStr << "Can't remove " << name << "\n";
109 xpWarn(errStr.str(), __FILE__, __LINE__);
110 }
111 }
112
113 void
cross(const double a[3],const double b[3],double c[3])114 cross(const double a[3], const double b[3], double c[3])
115 {
116 c[0] = a[1]*b[2] - b[1]*a[2];
117 c[1] = a[2]*b[0] - b[2]*a[0];
118 c[2] = a[0]*b[1] - b[0]*a[1];
119 }
120
121 double
dot(const double A0,const double A1,const double A2,const double B0,const double B1,const double B2)122 dot(const double A0, const double A1, const double A2,
123 const double B0, const double B1, const double B2)
124 {
125 return(A0 * B0 + A1 * B1 + A2 * B2);
126 }
127
128 double
ndot(const double A0,const double A1,const double A2,const double B0,const double B1,const double B2)129 ndot(const double A0, const double A1, const double A2,
130 const double B0, const double B1, const double B2)
131 {
132 const double len_a = dot(A0, A1, A2, A0, A1, A2);
133 const double len_b = dot(B0, B1, B2, B0, B1, B2);
134 return(dot(A0, A1, A2, B0, B1, B2) / sqrt(len_a * len_b));
135 }
136
137 double
dot(const double a[3],const double b[3])138 dot(const double a[3], const double b[3])
139 {
140 return(a[0] * b[0] + a[1] * b[1] + a[2] * b[2]);
141 }
142
143 double
ndot(const double a[3],const double b[3])144 ndot(const double a[3], const double b[3])
145 {
146 const double len_a = dot(a, a);
147 const double len_b = dot(b, b);
148 return(dot(a, b) / sqrt(len_a * len_b));
149 }
150
151 double
normalize(double a[3])152 normalize(double a[3])
153 {
154 const double length = dot(a, a);
155 if (length > 0)
156 for (int i = 0; i < 3; i++) a[i] /= length;
157
158 return(length);
159 }
160
161 void
invertMatrix(const double in[3][3],double out[3][3])162 invertMatrix(const double in[3][3], double out[3][3])
163 {
164 double a1 = in[0][0];
165 double a2 = in[0][1];
166 double a3 = in[0][2];
167
168 double b1 = in[1][0];
169 double b2 = in[1][1];
170 double b3 = in[1][2];
171
172 double c1 = in[2][0];
173 double c2 = in[2][1];
174 double c3 = in[2][2];
175
176 double det = (a1*(b2*c3 - b3*c2) + a2*(b3*c1 - b1*c3)
177 + a3*(b1*c2 - b2*c1));
178
179 out[0][0] = (b2*c3 - b3*c2)/det;
180 out[0][1] = (a3*c2 - a2*c3)/det;
181 out[0][2] = (a2*b3 - a3*b2)/det;
182
183 out[1][0] = (b3*c1 - b1*c3)/det;
184 out[1][1] = (a1*c3 - a3*c1)/det;
185 out[1][2] = (a3*b1 - a1*b3)/det;
186
187 out[2][0] = (b1*c2 - b2*c1)/det;
188 out[2][1] = (a2*c1 - a1*c2)/det;
189 out[2][2] = (a1*b2 - a2*b1)/det;
190 #if 0
191 printf("in:\n");
192 for (int i = 0; i < 3; i++)
193 {
194 printf("[%14.8e, %14.8e, %14.8e],\n", in[i][0], in[i][1],
195 in[i][2]);
196 }
197
198 printf("det = %14.8e\n", det);
199
200 printf("out:\n");
201 for (int i = 0; i < 3; i++)
202 {
203 printf("[%14.8e, %14.8e, %14.8e],\n", out[i][0], out[i][1],
204 out[i][2]);
205 }
206
207 printf("product:\n");
208 double prod[3][3];
209 for (int i = 0; i < 3; i++)
210 {
211 for (int j = 0; j < 3; j++)
212 {
213 prod[i][j] = 0;
214 for (int ii = 0; ii < 3; ii++)
215 prod[i][j] += in[i][ii] * out[ii][j];
216 }
217 printf("[%14.8e, %14.8e, %14.8e],\n", prod[i][0], prod[i][1],
218 prod[i][2]);
219 }
220
221 #endif
222
223 }
224
225 void
RADecToXYZ(double RA,double Dec,double & X,double & Y,double & Z)226 RADecToXYZ(double RA, double Dec, double &X, double &Y, double &Z)
227 {
228 RA *= 15;
229
230 X = FAR_DISTANCE * cos(Dec) * cos(RA);
231 Y = FAR_DISTANCE * cos(Dec) * sin(RA);
232 Z = FAR_DISTANCE * sin(Dec);
233 }
234
235 void
fromJulian(double jd,int & year,int & month,int & day,int & hour,int & min,double & sec)236 fromJulian(double jd, int &year, int &month, int &day,
237 int &hour, int &min, double &sec)
238 {
239 jd += 0.5;
240 int Z = (int) jd;
241 double F = jd - Z;
242
243 int A = Z;
244 if (Z >= 2291161)
245 {
246 int alpha = (int) ((Z - 1867216.25)/36524.25);
247 A = Z + 1 + alpha - alpha/4;
248 }
249
250 int B = A + 1524;
251 int C = (int) floor((B - 122.1) / 365.25);
252 int D = (int) floor(365.25 * C);
253 int E = (int) floor((B - D)/30.6001);
254
255 double dday = B - D - (int) floor(30.6001 * E) + F;
256
257 day = (int) floor(dday);
258
259 month = E - 13;
260 if (E < 14) month = E - 1;
261
262 year = C - 4715;
263 if (month > 2) year--;
264
265 double dhour = 24 * (dday - day);
266 hour = (int) floor(dhour);
267
268 double dmin = 60 * (dhour - hour);
269 min = (int) floor(dmin);
270 sec = 60 * (dmin - min);
271 }
272
273 string
fromJulian(double date)274 fromJulian(double date)
275 {
276 char timeString[16];
277 int year, month, day, hour, min;
278 double sec;
279
280 fromJulian(date, year, month, day, hour, min, sec);
281 snprintf(timeString, 16,
282 "%4.4d%2.2d%2.2d.%2.2d%2.2d%2.2d",
283 year, month, day,
284 hour, min, (int) floor(sec));
285
286 return(string(timeString));
287 }
288
289 time_t
get_tv_sec(double jd)290 get_tv_sec(double jd)
291 {
292 int year, month, day, hour, min;
293 double sec;
294 fromJulian(jd, year, month, day, hour, min, sec);
295
296 tm tm_struct = { (int) floor(sec + 0.5), min, hour, day,
297 month - 1, year - 1900, 0, 0, -1 };
298
299 #ifdef HAVE_TIMEGM
300 time_t returnval = timegm(&tm_struct);
301 #else
302 string tz_save = "";
303 char *get_tz = getenv("TZ");
304 if (get_tz != NULL)
305 {
306 tz_save = "TZ=";
307 tz_save += get_tz;
308 }
309 putenv("TZ=UTC");
310 tzset();
311
312 time_t returnval = mktime(&tm_struct);
313
314 if (tz_save.empty())
315 removeFromEnvironment("TZ");
316 else
317 putenv((char *) tz_save.c_str());
318 tzset();
319 #endif
320 return(returnval);
321 }
322
323 double
toJulian(int year,int month,int day,int hour,int min,int sec)324 toJulian(int year, int month, int day, int hour, int min, int sec)
325 {
326 // Gregorian calendar (after 1582 Oct 15)
327 const bool gregorian = (year > 1582
328 || (year == 1582 && month > 10)
329 || (year == 1582 && month == 10 && day >= 15));
330
331 if(month < 3)
332 {
333 year -= 1;
334 month += 12;
335 }
336
337 int a = year/100;
338 int b = 0;
339 if (gregorian) b = 2 - a + a/4;
340
341 int c = (int) floor(365.25 * (year + 4716));
342 int d = (int) floor(30.6001 * (month + 1));
343 double e = day + ((sec/60. + min) / 60. + hour) / 24.;
344
345 double jd = b + c + d + e - 1524.5;
346
347 return(jd);
348 }
349
350 double
deltaETpre1838(const double jd)351 deltaETpre1838(const double jd)
352 {
353 // From McCarthy & Babcock (1986)
354 const double j1800 = 2378496.5;
355 const double t = (jd - j1800)/36525;
356 const double delT = 5.156 + 13.3066 * (t - 0.19) * (t - 0.19);
357
358 return(delT);
359 }
360
361 double
deltaETpre1972(const double jd)362 deltaETpre1972(const double jd)
363 {
364 // Valid from 1825 to 2000, Montenbruck & Pfelger (2000), p 188
365 const double T = (jd - 2451545)/36525;
366 const int i = (int) floor(T/0.25);
367
368 const double c[7][4] = {
369 { 10.4, -80.8, 413.9, -572.3 },
370 { 6.6, 46.3, -358.4, 18.8 },
371 { -3.9, -10.8, -166.2, 867.4 },
372 { -2.6, 114.1, 327.5, -1467.4 },
373 { 24.2, -6.3, -8.2, 483.4 },
374 { 29.3, 32.5, -3.8, 550.7 },
375 { 45.3, 130.5, -570.5, 1516.7 }
376 };
377
378 double t = T - i * 0.25;
379
380 int ii = i + 7;
381 if (ii < 0)
382 {
383 t = 0;
384 ii = 0;
385 }
386 else if (ii > 6)
387 {
388 ii = 6;
389 t = 0.25;
390 }
391
392 const double delT = c[ii][0] + t * (c[ii][1]
393 + t * (c[ii][2]
394 + t * c[ii][3]));
395 return delT;
396 }
397
398 double
deltaETpost1972(const double jd)399 deltaETpost1972(const double jd)
400 {
401 // based on JPL's leap seconds kernel file
402 const double delta_t_a = 32.184;
403 const double k = 1.657e-3;
404 const double eb = 1.671e-2;
405 const double m0 = 6.239996;
406 const double m1 = 1.99096871e-7;
407
408 // leap seconds
409 int delta_at = 9;
410 if (jd >= toJulian(1972, 1, 1, 0, 0, 0)) delta_at++; // 10
411 if (jd >= toJulian(1972, 7, 1, 0, 0, 0)) delta_at++; // 11
412 if (jd >= toJulian(1973, 1, 1, 0, 0, 0)) delta_at++; // 12
413 if (jd >= toJulian(1974, 1, 1, 0, 0, 0)) delta_at++; // 13
414 if (jd >= toJulian(1975, 1, 1, 0, 0, 0)) delta_at++; // 14
415 if (jd >= toJulian(1976, 1, 1, 0, 0, 0)) delta_at++; // 15
416 if (jd >= toJulian(1977, 1, 1, 0, 0, 0)) delta_at++; // 16
417 if (jd >= toJulian(1978, 1, 1, 0, 0, 0)) delta_at++; // 17
418 if (jd >= toJulian(1979, 1, 1, 0, 0, 0)) delta_at++; // 18
419 if (jd >= toJulian(1980, 1, 1, 0, 0, 0)) delta_at++; // 19
420 if (jd >= toJulian(1981, 7, 1, 0, 0, 0)) delta_at++; // 20
421 if (jd >= toJulian(1982, 7, 1, 0, 0, 0)) delta_at++; // 21
422 if (jd >= toJulian(1983, 7, 1, 0, 0, 0)) delta_at++; // 22
423 if (jd >= toJulian(1985, 7, 1, 0, 0, 0)) delta_at++; // 23
424 if (jd >= toJulian(1988, 1, 1, 0, 0, 0)) delta_at++; // 24
425 if (jd >= toJulian(1990, 1, 1, 0, 0, 0)) delta_at++; // 25
426 if (jd >= toJulian(1991, 1, 1, 0, 0, 0)) delta_at++; // 26
427 if (jd >= toJulian(1992, 7, 1, 0, 0, 0)) delta_at++; // 27
428 if (jd >= toJulian(1993, 7, 1, 0, 0, 0)) delta_at++; // 28
429 if (jd >= toJulian(1994, 7, 1, 0, 0, 0)) delta_at++; // 29
430 if (jd >= toJulian(1996, 1, 1, 0, 0, 0)) delta_at++; // 30
431 if (jd >= toJulian(1997, 7, 1, 0, 0, 0)) delta_at++; // 31
432 if (jd >= toJulian(1999, 1, 1, 0, 0, 0)) delta_at++; // 32
433 if (jd >= toJulian(2006, 1, 1, 0, 0, 0)) delta_at++; // 33
434 if (jd >= toJulian(2009, 1, 1, 0, 0, 0)) delta_at++; // 34
435 if (jd >= toJulian(2012, 7, 1, 0, 0, 0)) delta_at++; // 35
436 if (jd >= toJulian(2015, 7, 1, 0, 0, 0)) delta_at++; // 36
437
438 const double J2000 = toJulian(2000, 1, 1, 12, 0, 0);
439 const double m = m0 + m1 * (jd - J2000) * 86400;
440 const double e = m + eb * sin(m);
441
442 const double delT = delta_t_a + k * sin(e) + delta_at;
443 return delT;
444 }
445
446 // find the difference between universal and ephemeris time
447 // (delT = ET - UT)
448 double
delT(const double jd)449 delT(const double jd)
450 {
451 double delT;
452 if (jd < toJulian(1838, 1, 1, 0, 0, 0))
453 {
454 delT = deltaETpre1838(jd);
455 }
456 else
457 {
458 if (jd < toJulian(1972, 1, 1, 0, 0, 0))
459 {
460 delT = deltaETpre1972(jd);
461 }
462 else
463 {
464 delT = deltaETpost1972(jd);
465 }
466 }
467
468 /*
469 int year, month, day, hour, min;
470 double sec;
471 fromJulian(jd, year, month, day, hour, min, sec);
472 double thisYear = year + (month-1)/12.;
473
474 printf("%.1f %f %f %f %f\n", thisYear, deltaETpre1838(jd),
475 deltaETpre1972(jd), deltaETpost1972(jd), delT);
476 */
477 return delT;
478 }
479
480 void
rotateX(double & X,double & Y,double & Z,const double theta)481 rotateX(double &X, double &Y, double &Z, const double theta)
482 {
483 const double st = sin(theta);
484 const double ct = cos(theta);
485 const double X0 = X;
486 const double Y0 = Y;
487 const double Z0 = Z;
488
489 X = X0;
490 Y = Y0 * ct + Z0 * st;
491 Z = Z0 * ct - Y0 * st;
492 }
493
494 void
rotateZ(double & X,double & Y,double & Z,const double theta)495 rotateZ(double &X, double &Y, double &Z, const double theta)
496 {
497 const double st = sin(theta);
498 const double ct = cos(theta);
499 const double X0 = X;
500 const double Y0 = Y;
501 const double Z0 = Z;
502
503 X = X0 * ct + Y0 * st;
504 Y = Y0 * ct - X0 * st;
505 Z = Z0;
506 }
507
508 /*
509 x = 0 passes through 0 and 2
510 y = 0 passes through 0 and 1
511
512 Given a point (x, y), compute the area weighting of each pixel.
513
514 --- ---
515 | 0 | 1 |
516 --- ---
517 | 2 | 3 |
518 --- ---
519 */
520 void
getWeights(const double t,const double u,double weights[4])521 getWeights(const double t, const double u, double weights[4])
522 {
523 // Weights are from Numerical Recipes, 2nd Edition
524 // weight[0] = (1 - t) * u;
525 // weight[2] = (1-t) * (1-u);
526 // weight[3] = t * (1-u);
527 weights[1] = t * u;
528 weights[0] = u - weights[1];
529 weights[2] = 1 - t - u + weights[1];
530 weights[3] = t - weights[1];
531 }
532
533 void
calcGreatArc(const double lat1,const double lon1,const double lat2,const double lon2,double & trueCourse,double & dist)534 calcGreatArc(const double lat1, const double lon1,
535 const double lat2, const double lon2,
536 double &trueCourse, double &dist)
537 {
538 /*
539 * Equations are from http://www.best.com/~williams/avform.html
540 * returned trueCourse is relative to latitude north
541 */
542 const double sin_lat1 = sin(lat1);
543 const double cos_lat1 = cos(lat1);
544 const double sin_lat2 = sin(lat2);
545 const double cos_lat2 = cos(lat2);
546 const double dlon = lon1 - lon2;
547
548 // Arc length between points (in radians)
549 double arg = sin_lat1 * sin_lat2 + cos_lat1 * cos_lat2 * cos(dlon);
550 if (arg >= 1)
551 dist = 0;
552 else if (arg <= -1)
553 dist = M_PI;
554 else
555 dist = acos(arg);
556
557 // True course
558 trueCourse = fmod(atan2(sin(dlon) * cos_lat2,
559 cos_lat1 * sin_lat2
560 - sin_lat1 * cos_lat2 * cos(dlon)), TWO_PI);
561 }
562
563 double
kepler(const double e,double M)564 kepler(const double e, double M)
565 {
566 double E = M = fmod(M, TWO_PI);
567 double delta = 1;
568
569 while (fabs(delta) > 1E-10)
570 {
571 delta = (M + e * sin(E) - E)/(1 - e * cos(E));
572 E += delta;
573 }
574 return(E);
575 }
576
577 // Precess rectangular coordinates in B1950 frame to J2000 using
578 // Standish precession matrix from Lieske (1998)
579 void
precessB1950J2000(double & X,double & Y,double & Z)580 precessB1950J2000(double &X, double &Y, double &Z)
581 {
582 static const double p[3][3] =
583 { { 0.9999256791774783, -0.0111815116768724, -0.0048590038154553 },
584 { 0.0111815116959975, 0.9999374845751042, -0.0000271625775175 },
585 { 0.0048590037714450, -0.0000271704492210, 0.9999881946023742 } };
586
587 double newX = p[0][0] * X + p[0][1] * Y + p[0][2] * Z;
588 double newY = p[1][0] * X + p[1][1] * Y + p[1][2] * Z;
589 double newZ = p[2][0] * X + p[2][1] * Y + p[2][2] * Z;
590
591 X = newX;
592 Y = newY;
593 Z = newZ;
594 }
595
596 // Return the shading function. For Lambertian shading, the input
597 // value X is the cosine of the sun-surface-observer angle, and the
598 // return value is just X. Using the sqrt of X brightens the image a
599 // bit.
600 double
photoFunction(const double x)601 photoFunction(const double x)
602 {
603 return(sqrt(x));
604 }
605
606 static void
convertEncoding(const bool toNative,ICONV_CONST char * inBuf,char * outBuf)607 convertEncoding(const bool toNative, ICONV_CONST char *inBuf, char *outBuf)
608 {
609 #ifdef NO_ICONV
610 memcpy(outBuf, inBuf, MAX_LINE_LENGTH);
611 #else
612 #ifdef HAVE_LIBCHARSET
613 const char *encoding = locale_charset();
614 #else
615 const char *encoding = nl_langinfo(CODESET);
616 #endif
617 const char *fromCode = (toNative ? "UTF-8" : encoding);
618 const char *toCode = (toNative ? encoding : "UTF-8");
619 iconv_t conv = iconv_open(toCode, fromCode);
620 if (conv != (iconv_t) -1)
621 {
622 size_t inbytesleft = strlen(inBuf);
623 size_t outbytesleft = MAX_LINE_LENGTH;
624 while (inbytesleft != (size_t) 0)
625 {
626 size_t retVal = iconv(conv, &inBuf, &inbytesleft,
627 &outBuf, &outbytesleft);
628 if (retVal == (size_t) -1)
629 {
630 ostringstream errStr;
631 errStr << "Can't convert sequence " << inBuf
632 << " from encoding " << fromCode
633 << " to encoding " << toCode << endl;
634 switch (errno)
635 {
636 case EINVAL:
637 errStr << "Incomplete character or shift sequence "
638 << "(EINVAL)\n";
639 break;
640 case E2BIG:
641 errStr << "Lack of space in output buffer (E2BIG)\n";
642 break;
643 case EILSEQ:
644 errStr << "Illegal character or shift sequence "
645 << "(EILSEQ)\n";
646 break;
647 case EBADF:
648 errStr << "Invalid conversion descriptor (EBADF)\n";
649 break;
650 default:
651 errStr << "Unknown iconv error\n";
652 }
653 xpWarn(errStr.str(), __FILE__, __LINE__);
654 iconv_close(conv);
655 return;
656 }
657 }
658 iconv_close(conv);
659 }
660 else
661 {
662 ostringstream errStr;
663 errStr << "iconv_open() failed, fromCode is " << fromCode
664 << ", toCode is " << toCode << "\n";
665 xpWarn(errStr.str(), __FILE__, __LINE__);
666 }
667 #endif
668 }
669
670 void
strftimeUTF8(string & timeString)671 strftimeUTF8(string &timeString)
672 {
673 // This is the input string, with formatting characters
674 char buffer_UTF8[MAX_LINE_LENGTH];
675 memset(buffer_UTF8, 0, MAX_LINE_LENGTH);
676 strncpy(buffer_UTF8, timeString.c_str(), MAX_LINE_LENGTH);
677
678 // Convert to native encoding
679 char buffer_native_format[MAX_LINE_LENGTH];
680 memset(buffer_native_format, 0, MAX_LINE_LENGTH);
681 convertEncoding(true, buffer_UTF8, buffer_native_format);
682
683 // Run it through strftime()
684 char buffer_native[MAX_LINE_LENGTH];
685 Options *options = Options::getInstance();
686 time_t tv_sec = options->TVSec();
687 strftime(buffer_native, MAX_LINE_LENGTH,
688 buffer_native_format,
689 localtime((time_t *) &tv_sec));
690
691 // Convert back to UTF8
692 convertEncoding(false, buffer_native, buffer_UTF8);
693 timeString.assign(buffer_UTF8);
694 }
695
696 char *
checkLocale(const int category,const char * locale)697 checkLocale(const int category, const char *locale)
698 {
699 static bool showWarning = true;
700 char *returnVal = setlocale(category, locale);
701 if (locale != NULL)
702 {
703 if (returnVal == NULL)
704 {
705 ostringstream errMsg;
706 errMsg << "setlocale(";
707 switch (category)
708 {
709 case LC_CTYPE:
710 errMsg << "LC_CTYPE";
711 break;
712 case LC_COLLATE:
713 errMsg << "LC_COLLATE";
714 break;
715 case LC_TIME:
716 errMsg << "LC_TIME";
717 break;
718 case LC_NUMERIC:
719 errMsg << "LC_NUMERIC";
720 break;
721 case LC_MONETARY:
722 errMsg << "LC_MONETARY";
723 break;
724 case LC_MESSAGES:
725 errMsg << "LC_MESSAGES";
726 break;
727 case LC_ALL:
728 errMsg << "LC_ALL";
729 break;
730 default:
731 errMsg << "UNKNOWN CATEGORY!";
732 }
733 errMsg << ", ";
734 if (strlen(locale) == 0)
735 {
736 errMsg << "\"\"";
737 }
738 else
739 {
740 errMsg << "\"" << locale << "\"";
741 }
742 errMsg << ") failed! ";
743
744 if (strlen(locale) == 0)
745 {
746 errMsg << "Check your LANG environment variable "
747 << "(currently ";
748 char *lang = getenv("LANG");
749 if (lang == NULL)
750 {
751 errMsg << "NULL";
752 }
753 else
754 {
755 errMsg << "\"" << lang << "\"";
756 }
757 errMsg << "). Setting to \"C\".\n";
758
759 if (showWarning)
760 {
761 xpWarn(errMsg.str(), __FILE__, __LINE__);
762 showWarning = false;
763 }
764 returnVal = setlocale(category, "C");
765 }
766 else
767 {
768 errMsg << "Trying native ...\n";
769 xpWarn(errMsg.str(), __FILE__, __LINE__);
770 showWarning = true;
771 returnVal = checkLocale(category, "");
772 }
773 }
774 }
775 return(returnVal);
776 }
777