source: git/src/message.c @ b6e9e7e

RELEASE/1.0RELEASE/1.1RELEASE/1.2debug-cidebug-ci-sanitisersfaster-cavernloglog-selectstereostereo-2025walls-datawalls-data-hanging-as-warningwarn-only-for-hanging-survey
Last change on this file since b6e9e7e was f8e03f3, checked in by Olly Betts <olly@…>, 24 years ago

Added support for Latin9 (iso-8859-15)

git-svn-id: file:///home/survex-svn/survex/trunk@1004 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

  • Property mode set to 100644
File size: 23.5 KB
Line 
1/* > message.c
2 * Fairly general purpose message and error routines
3 * Copyright (C) 1993-2001 Olly Betts
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20/*#define DEBUG 1*/
21
22#ifdef HAVE_CONFIG_H
23# include <config.h>
24#endif
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <ctype.h>
30#include <limits.h>
31#include <errno.h>
32#include <locale.h>
33
34#include "whichos.h"
35#include "filename.h"
36#include "message.h"
37#include "osdepend.h"
38#include "filelist.h"
39#include "debug.h"
40
41#ifdef AVEN
42#include "aven.h"
43#endif
44
45#ifdef HAVE_SIGNAL
46# ifdef HAVE_SETJMP
47#  include <setjmp.h>
48static jmp_buf jmpbufSignal;
49#  include <signal.h>
50# else
51#  undef HAVE_SIGNAL
52# endif
53#endif
54
55#if (OS==WIN32)
56#include <windows.h>
57#endif
58
59#if (OS==RISCOS)
60#include "oslib/wimpreadsy.h"
61#endif
62
63/* This is the name of the default language.  Add -DDEFAULTLANG to CFLAGS
64 * e.g. with `CFLAGS="-DDEFAULTLANG=fr" ./configure'
65 */
66#ifndef DEFAULTLANG
67# define DEFAULTLANG en
68#endif
69
70/* For funcs which want to be immune from messing around with different
71 * calling conventions */
72#ifndef CDECL
73# define CDECL
74#endif
75
76int msg_warnings = 0; /* keep track of how many warnings we've given */
77int msg_errors = 0;   /* and how many (non-fatal) errors */
78
79/* in case osmalloc() fails before appname_copy is set up */
80static const char *appname_copy = "anonymous program";
81
82/* error code for failed osmalloc and osrealloc calls */
83static void
84outofmem(OSSIZE_T size)
85{
86   fatalerror(/*Out of memory (couldn't find %lu bytes).*/1,
87              (unsigned long)size);
88}
89
90#ifdef TOMBSTONES
91#define TOMBSTONE_SIZE 16
92static const char tombstone[TOMBSTONE_SIZE] = "012345\xfftombstone";
93#endif
94
95/* malloc with error catching if it fails. Also allows us to write special
96 * versions easily eg for DOS EMS or MS Windows.
97 */
98void FAR *
99osmalloc(OSSIZE_T size)
100{
101   void FAR *p;
102#ifdef TOMBSTONES
103   size += TOMBSTONE_SIZE * 2;
104   p = malloc(size);
105#else
106   p = xosmalloc(size);
107#endif
108   if (p == NULL) outofmem(size);
109#ifdef TOMBSTONES
110   printf("osmalloc truep=%p truesize=%d\n", p, size);
111   memcpy(p, tombstone, TOMBSTONE_SIZE);
112   memcpy(p + size - TOMBSTONE_SIZE, tombstone, TOMBSTONE_SIZE);
113   *(size_t *)p = size;
114   p += TOMBSTONE_SIZE;
115#endif
116   return p;
117}
118
119/* realloc with error catching if it fails. */
120void FAR *
121osrealloc(void *p, OSSIZE_T size)
122{
123   /* some pre-ANSI realloc implementations don't cope with a NULL pointer */
124   if (p == NULL) {
125      p = xosmalloc(size);
126   } else {
127#ifdef TOMBSTONES
128      int true_size;
129      size += TOMBSTONE_SIZE * 2;
130      p -= TOMBSTONE_SIZE;
131      true_size = *(size_t *)p;
132      printf("osrealloc (in truep=%p truesize=%d)\n", p, true_size);
133      if (memcmp(p + sizeof(size_t), tombstone + sizeof(size_t),
134                 TOMBSTONE_SIZE - sizeof(size_t)) != 0) {
135         printf("start tombstone for block %p, size %d corrupted!",
136                p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
137      }
138      if (memcmp(p + true_size - TOMBSTONE_SIZE, tombstone,
139                 TOMBSTONE_SIZE) != 0) {
140         printf("end tombstone for block %p, size %d corrupted!",
141                p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
142      }
143      p = realloc(p, size);
144      if (p == NULL) outofmem(size);
145      printf("osrealloc truep=%p truesize=%d\n", p, size);
146      memcpy(p, tombstone, TOMBSTONE_SIZE);
147      memcpy(p + size - TOMBSTONE_SIZE, tombstone, TOMBSTONE_SIZE);
148      *(size_t *)p = size;
149      p += TOMBSTONE_SIZE;
150#else
151      p = xosrealloc(p, size);
152#endif
153   }
154   if (p == NULL) outofmem(size);
155   return p;
156}
157
158char FAR *
159osstrdup(const char *str)
160{
161   char *p;
162   OSSIZE_T len;
163   len = strlen(str) + 1;
164   p = osmalloc(len);
165   memcpy(p, str, len);
166   return p;
167}
168
169/* osfree is usually just a macro in osalloc.h */
170#ifdef TOMBSTONES
171void
172osfree(void *p)
173{
174   int true_size;
175   if (!p) return;
176   p -= TOMBSTONE_SIZE;
177   true_size = *(size_t *)p;
178   printf("osfree truep=%p truesize=%d\n", p, true_size);
179   if (memcmp(p + sizeof(size_t), tombstone + sizeof(size_t),
180              TOMBSTONE_SIZE - sizeof(size_t)) != 0) {
181      printf("start tombstone for block %p, size %d corrupted!",
182             p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
183   }
184   if (memcmp(p + true_size - TOMBSTONE_SIZE, tombstone,
185              TOMBSTONE_SIZE) != 0) {
186      printf("end tombstone for block %p, size %d corrupted!",
187             p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
188   }
189   free(p);
190}
191#endif
192
193#ifdef HAVE_SIGNAL
194
195static int sigReceived;
196
197/* for systems not using autoconf, assume the signal handler returns void
198 * unless specified elsewhere */
199#ifndef RETSIGTYPE
200# define RETSIGTYPE void
201#endif
202
203static CDECL RETSIGTYPE FAR
204report_sig(int sig)
205{
206   sigReceived = sig;
207   longjmp(jmpbufSignal, 1);
208}
209
210static void
211init_signals(void)
212{
213   int en;
214   if (!setjmp(jmpbufSignal)) {
215#if 1 /* disable these to get a core dump */
216      signal(SIGABRT, report_sig); /* abnormal termination eg abort() */
217      signal(SIGFPE,  report_sig); /* arithmetic error eg /0 or overflow */
218      signal(SIGILL,  report_sig); /* illegal function image eg illegal instruction */
219      signal(SIGSEGV, report_sig); /* illegal storage access eg access outside memory limits */
220#endif
221# ifdef SIGSTAK /* only on RISC OS AFAIK */
222      signal(SIGSTAK, report_sig); /* stack overflow */
223# endif
224      return;
225   }
226
227   switch (sigReceived) {
228      case SIGABRT: en = /*Abnormal termination*/90; break;
229      case SIGFPE:  en = /*Arithmetic error*/91; break;
230      case SIGILL:  en = /*Illegal instruction*/92; break;
231      case SIGSEGV: en = /*Bad memory access*/94; break;
232# ifdef SIGSTAK
233      case SIGSTAK: en = /*Stack overflow*/96; break;
234# endif
235      default:      en = /*Unknown signal received*/97; break;
236   }
237   fputsnl(msg(en), STDERR);
238
239   /* Any of the signals we catch indicates a bug */
240   fatalerror(/*Bug in program detected! Please report this to the authors*/11);
241
242   exit(EXIT_FAILURE);
243}
244#endif
245
246static int
247default_charset(void)
248{
249#if (OS==RISCOS)
250   /* RISCOS 3.1 and above CHARSET_RISCOS31 (ISO_8859_1 + extras in 128-159)
251    * RISCOS < 3.1 is ISO_8859_1 */
252   int version;
253   if (xwimpreadsysinfo_version(&version) != NULL) {
254      /* RISC OS 2 or some error (don't care which) */
255      return CHARSET_ISO_8859_1;
256   }
257
258   /* oddly wimp_VERSION_RO3 is RISC OS 3.1 */
259   if (version < wimp_VERSION_RO3) return CHARSET_ISO_8859_1;
260
261   return CHARSET_RISCOS31;
262#elif (OS==MSDOS)
263   return CHARSET_DOSCP850;
264#elif (OS==WIN32)
265# ifdef AVEN
266   return CHARSET_WINCP1252;
267# else
268   switch (GetConsoleOutputCP()) {
269    case 1252: return CHARSET_WINCP1252;
270    case 850: return CHARSET_DOSCP850;
271   }
272   return CHARSET_USASCII;
273# endif
274#elif (OS==UNIX)
275#if defined(XCAVEROT) || defined(AVEN)
276   return CHARSET_ISO_8859_1;
277#else
278   char *p = strchr(msg_lang, '.');
279   if (p) {
280      char *chset = ++p;
281      size_t name_len;
282
283      while (*p != '\0' && *p != '@') p++;
284
285      name_len = p - chset;
286
287      if (name_len) {
288         int only_digit = 1;
289         size_t cnt;
290       
291         for (cnt = 0; cnt < name_len; ++cnt)
292            if (isalpha(chset[cnt])) {
293               only_digit = 0;
294               break;
295            }
296
297         if (only_digit) goto iso;
298         
299         switch (tolower(chset[0])) {
300          case 'i':
301            if (tolower(chset[1]) == 's' && tolower(chset[2]) == 'o') {
302               chset += 3;
303               iso:
304               if (strncmp(chset, "8859", 4) == 0) {
305                  chset += 4;
306                  while (chset < p && *chset && !isdigit(*chset)) chset++;
307                  switch (atoi(chset)) {
308                   case 1: return CHARSET_ISO_8859_1;
309                   case 15: return CHARSET_ISO_8859_15;
310                   default: return CHARSET_USASCII;               
311                  }
312               }
313            }
314            break;
315          case 'u':
316            if (tolower(chset[1]) == 't' && tolower(chset[2]) == 'f') {
317               chset += 3;
318               while (chset < p && *chset && !isdigit(*chset)) chset++;
319               switch (atoi(chset)) {
320                case 8: return CHARSET_UTF8;
321                default: return CHARSET_USASCII;
322               }
323            }
324         }
325      }
326   }
327   return CHARSET_USASCII;
328#endif
329#else
330# error Do not know operating system 'OS'
331#endif
332}
333
334#if (OS==MSDOS || OS==WIN32)
335static int
336xlate_dos_cp850(int unicode)
337{
338   switch (unicode) {
339#include "uni2dos.h"
340   }
341   return 0;
342}
343#endif
344
345/* It seems that Swedish and maybe some other scandanavian languages don't
346 * transliterate &auml; to ae - but it seems there may be conflicting views
347 * on this...
348 */
349#define umlaut_to_e() 1
350
351static int
352add_unicode(int charset, unsigned char *p, int value)
353{
354#ifdef DEBUG
355   fprintf(stderr, "add_unicode(%d, %p, %d)\n", charset, p, value);
356#endif
357   if (value == 0) return 0;
358   switch (charset) {
359   case CHARSET_USASCII:
360      if (value < 0x80) {
361         *p = value;
362         return 1;
363      }
364      break;
365   case CHARSET_ISO_8859_1:
366      if (value < 0x100) {
367         *p = value;
368         return 1;
369      }
370      break;
371   case CHARSET_ISO_8859_15:
372      switch (value) {
373       case 0xa4: case 0xa6: case 0xb0: case 0xc4:
374       case 0xd0: case 0xd4: case 0xd5: case 0xd6:
375         goto donthave;
376       case 0x152: value = 0xd4; break; /* &OElig; */
377       case 0x153: value = 0xd5; break; /* &oelig; */
378#if 0
379       case 0x0: value = 0xa4; break; /* euro */
380       case 0x0: value = 0xa6; break; /* Scaron */
381       case 0x0: value = 0xb0; break; /* scaron */
382       case 0x0: value = 0xc4; break; /* Zcaron */
383       case 0x0: value = 0xd0; break; /* zcaron */
384       case 0x0: value = 0xd6; break; /* Ydiersis */
385#endif
386      }
387      if (value < 0x100) {
388         *p = value;
389         return 1;
390      }
391      donthave:
392      break;
393#if (OS==RISCOS)
394   case CHARSET_RISCOS31:
395      /* RISC OS 3.1 (and later) extensions to ISO-8859-1 */
396      switch (value) {
397       case 0x152: value = 0x9a; break; /* &OElig; */
398       case 0x153: value = 0x9b; break; /* &oelig; */
399#if 0
400       case 0x174: value = 0x81; break; /* &Wcirc; */
401       case 0x175: value = 0x82; break; /* &wcirc; */
402       case 0x176: value = 0x85; break; /* &Ycirc; */
403       case 0x177: value = 0x86; break; /* &ycirc; */
404#endif
405      }
406      if (value < 0x100) {
407         *p = value;
408         return 1;
409      }
410      break;
411#elif (OS==WIN32)
412   case CHARSET_WINCP1252:
413      /* MS Windows extensions to ISO-8859-1 */
414      switch (value) {
415       case 0x152: value = 0x8c; break; /* &OElig; */
416       case 0x153: value = 0x9c; break; /* &oelig; */
417#if 0
418      /* there are a few other obscure ones we don't currently need */
419#endif
420      }
421      if (value < 0x100) {
422         *p = value;
423         return 1;
424      }
425      break;
426#endif
427#if (OS==MSDOS || OS==WIN32)
428   case CHARSET_DOSCP850:
429      value = xlate_dos_cp850(value);
430      if (value) {
431         *p = value;
432         return 1;
433      }
434      break;
435#endif
436   }
437   /* Transliterate characters we can't represent */
438#ifdef DEBUG
439   fprintf(stderr, "transliterate `%c' 0x%x\n", value, value);
440#endif
441   switch (value) {
442    case 160:
443      *p = ' '; return 1;
444    case 161 /* ¡ */:
445      *p = '!'; return 1;
446    case 171 /* « */:
447      p[1] = *p = '<'; return 2;
448    case 187 /* » */:
449      p[1] = *p = '>'; return 2;
450    case 191 /* ¿ */:
451      *p = '?'; return 1;
452    case 192 /* À */: case 193 /* Á */: case 194 /* Â */: case 195 /* Ã */:
453      *p = 'A'; return 1;
454    case 197 /* Å */:
455      p[1] = *p = 'A'; return 2;
456    case 196 /* Ä */: /* &Auml; */
457      *p = 'A';
458      if (!umlaut_to_e()) return 1;
459      p[1] = 'E'; return 2;
460    case 198 /* Æ */:
461      *p = 'A'; p[1] = 'E'; return 2;
462    case 199 /* Ç */:
463      *p = 'C'; return 1;
464    case 200 /* È */: case 201 /* É */: case 202 /* Ê */: case 203 /* Ë */:
465      *p = 'E'; return 1;
466    case 204 /* Ì */: case 205 /* Í */: case 206 /* Î */: case 207 /* Ï */:
467      *p = 'I'; return 1;
468    case 208 /* Ð */: case 222 /* Þ */:
469      *p = 'T'; p[1] = 'H'; return 2;
470    case 209 /* Ñ */:
471      *p = 'N'; return 1;
472    case 210 /* Ò */: case 211 /* Ó */: case 212 /* Ô */: case 213 /* Õ */:
473      *p = 'O'; return 1;
474    case 214 /* Ö */: /* &Ouml; */ case 0x152: /* &OElig; */
475      *p = 'O'; p[1] = 'E'; return 2;
476    case 217 /* Ù */: case 218 /* Ú */: case 219 /* Û */:
477      *p = 'U'; return 1;
478    case 220 /* Ü */: /* &Uuml; */
479      *p = 'U'; p[1] = 'E'; return 2;
480    case 221 /* Ý */:
481      *p = 'Y'; return 1;
482    case 223 /* ß */:
483      p[1] = *p = 's'; return 2;
484    case 224 /* à */: case 225 /* á */: case 226 /* â */: case 227 /* ã */:
485      *p = 'a'; return 1;
486    case 228 /* ä */: /* &auml; */ case 230 /* æ */:
487      *p = 'a'; p[1] = 'e'; return 2;
488    case 229 /* å */:
489      p[1] = *p = 'a'; return 2;
490    case 231 /* ç */:
491      *p = 'c'; return 1;
492    case 232 /* è */: case 233 /* é */: case 234 /* ê */: case 235 /* ë */:
493      *p = 'e'; return 1;
494    case 236 /* ì */: case 237 /* í */: case 238 /* î */: case 239 /* ï */:
495      *p = 'i'; return 1;
496    case 241 /* ñ */:
497      *p = 'n'; return 1;
498    case 240 /* ð */: case 254 /* þ */:
499      *p = 't'; p[1] = 'h'; return 2;
500    case 242 /* ò */: case 243 /* ó */: case 244 /* ô */: case 245 /* õ */:
501      *p = 'o'; return 1;
502    case 246 /* ö */: /* &ouml; */ case 0x153: /* &oelig; */
503      *p = 'o'; p[1] = 'e'; return 2;
504    case 249 /* ù */: case 250 /* ú */: case 251 /* û */:
505      *p = 'u'; return 1;
506    case 252 /* ü */: /* &uuml; */
507      *p = 'u'; p[1] = 'e'; return 2;
508    case 253 /* ý */: case 255 /* ÿ */:
509      *p = 'y'; return 1;
510   }
511#ifdef DEBUG
512   fprintf(stderr, "failed to transliterate\n");
513#endif
514   return 0;
515}
516
517/* fall back on looking in the current directory */
518static const char *pth_cfg_files = "";
519
520static int num_msgs = 0;
521static char **msg_array = NULL;
522
523const char *msg_lang = NULL;
524const char *msg_lang2 = NULL;
525
526static char **
527parse_msgs(int n, unsigned char *p, int charset_code) {
528   int i;
529
530   char **msgs = osmalloc(n * sizeof(char *));
531
532   for (i = 0; i < n; i++) {
533      unsigned char *to = p;
534      int ch;
535      msgs[i] = (char *)p;
536
537      /* If we want UTF8 anyway, we just need to find the start of each
538       * message */
539      if (charset_code == CHARSET_UTF8) {
540         p += strlen((char *)p) + 1;
541         continue;
542      }
543
544      while ((ch = *p++) != 0) {
545         /* A byte in the range 0x80-0xbf or 0xf0-0xff isn't valid in
546          * this state, (0xf0-0xfd mean values > 0xffff) so treat as
547          * literal and try to resync so we cope better when fed
548          * non-utf-8 data.  Similarly we abandon a multibyte sequence
549          * if we hit an invalid character. */
550         if (ch >= 0xc0 && ch < 0xf0) {
551            int ch1 = *p;
552            if ((ch1 & 0xc0) != 0x80) goto resync;
553
554            if (ch < 0xe0) {
555               /* 2 byte sequence */
556               ch = ((ch & 0x1f) << 6) | (ch1 & 0x3f);
557               p++;
558            } else {
559               /* 3 byte sequence */
560               int ch2 = p[1];
561               if ((ch2 & 0xc0) != 0x80) goto resync;
562               ch = ((ch & 0x1f) << 12) | ((ch1 & 0x3f) << 6) | (ch2 & 0x3f);
563               p += 2;
564            }
565         }
566
567         resync:
568
569         if (ch < 127) {
570            *to++ = (char)ch;
571         } else {
572            /* We assume an N byte UTF-8 code never transliterates to more
573             * than N characters (so we can't transliterate © to (C) or
574             * ® to (R) for example) */
575            to += add_unicode(charset_code, to, ch);
576         }
577      }
578      *to++ = '\0';
579   }
580   return msgs;
581}
582
583/* No point extracting these errors as they won't get used if file opens */
584#define HDR(D) "../lib/"STRING(D)".h"
585#include HDR(DEFAULTLANG)
586
587static char **dontextract = NULL;
588
589static void
590parse_msg_file(int charset_code)
591{
592   FILE *fh;
593   unsigned char header[20];
594   int i;   
595   unsigned len;
596   unsigned char *p;
597   char *fnm, *s;
598   int n;
599
600#ifdef DEBUG
601   fprintf(stderr, "parse_msg_file(%d)\n", charset_code);
602#endif
603
604   /* sort out messages we need to print if we can't open the message file */
605   dontextract = parse_msgs(N_DONTEXTRACTMSGS, dontextractmsgs, charset_code);
606
607   fnm = osstrdup(msg_lang);
608   /* trim off charset from stuff like "de_DE.iso8859_1" */
609   s = strchr(fnm, '.');
610   if (s) *s = '\0';
611
612   fh = fopenWithPthAndExt(pth_cfg_files, fnm, EXT_SVX_MSG, "rb", NULL);
613
614   if (!fh) {
615      /* e.g. if 'en-COCKNEY' is unknown, see if we know 'en' */
616      if (strlen(fnm) > 3 && fnm[2] == '-') {
617         fnm[2] = '\0';
618         fh = fopenWithPthAndExt(pth_cfg_files, fnm, EXT_SVX_MSG, "rb", NULL);
619         if (!fh) fnm[2] = '-'; /* for error reporting */
620      }
621   }
622
623   if (!fh) {
624      fatalerror(/*Can't open message file `%s' using path `%s'*/1000,
625                 fnm, pth_cfg_files);
626   }
627
628   if (fread(header, 1, 20, fh) < 20 ||
629       memcmp(header, "Svx\nMsg\r\n\xfe\xff", 12) != 0) {
630      fatalerror(/*Problem with message file `%s'*/1001, fnm);
631   }
632
633   if (header[12] != 0)
634      fatalerror(/*I don't understand this message file version*/1002);
635
636   n = (header[14] << 8) | header[15];
637
638   len = 0;
639   for (i = 16; i < 20; i++) len = (len << 8) | header[i];
640
641   p = osmalloc(len);
642   if (fread(p, 1, len, fh) < len)
643      fatalerror(/*Message file truncated?*/1003);
644
645   fclose(fh);
646
647#ifdef DEBUG
648   fprintf(stderr, "fnm = `%s', n = %d, len = %d\n", fnm, n, len);
649#endif
650   osfree(fnm);
651
652   msg_array = parse_msgs(n, p, charset_code);
653   num_msgs = n;
654}
655
656const char *
657msg_cfgpth(void)
658{
659   return pth_cfg_files;
660}
661
662void
663msg_init(const char *argv0)
664{
665   char *p;
666
667#ifdef HAVE_SIGNAL
668   init_signals();
669#endif
670   /* Point to argv0 itself so we report a more helpful error if the code to work
671    * out the clean appname generates a signal */
672   appname_copy = argv0;
673#if (OS == UNIX)
674   /* use name as-is on Unix - programs run from path get name as supplied */
675   appname_copy = osstrdup(argv0);
676#else
677   /* use the lower-cased leafname on other platforms */
678   appname_copy = p = leaf_from_fnm(argv0);
679   while (*p) {
680      *p = tolower(*p);
681      p++;
682   }
683#endif
684
685   /* Look for env. var. "SURVEXHOME" or the like */
686   p = getenv("SURVEXHOME");
687   if (p && *p) {
688      pth_cfg_files = osstrdup(p);
689#if (OS==UNIX) && defined(DATADIR) && defined(PACKAGE)
690   } else {
691      /* under Unix, we compile in the configured path */
692      pth_cfg_files = DATADIR "/" PACKAGE;
693#else
694   } else if (argv0) {
695      /* else try the path on argv[0] */
696      pth_cfg_files = path_from_fnm(argv0);
697#endif
698   }
699
700   msg_lang = getenv("SURVEXLANG");
701#ifdef DEBUG
702   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang, msg_lang?msg_lang:"(null)");
703#endif
704
705   if (!msg_lang || !*msg_lang) {
706      msg_lang = getenv("LANG");
707      if (!msg_lang || !*msg_lang) {
708#if (OS==WIN32)
709         LCID locid;
710#endif
711         msg_lang = STRING(DEFAULTLANG);
712#if (OS==WIN32)
713         locid = GetUserDefaultLCID();
714         if (locid) {
715            WORD langid = LANGIDFROMLCID(locid);
716            switch (PRIMARYLANGID(langid)) {
717             case LANG_CATALAN:
718               msg_lang = "ca";
719               break;
720             case LANG_ENGLISH:
721               if (SUBLANGID(langid) == SUBLANG_ENGLISH_US)
722                  msg_lang = "en_US";
723               else
724                  msg_lang = "en";
725               break;
726             case LANG_FRENCH:
727               msg_lang = "fr";
728               break;
729             case LANG_GERMAN:
730               switch (SUBLANGID(langid)) {
731                case SUBLANG_GERMAN_SWISS:
732                  msg_lang = "de_CH";
733                  break;
734                case SUBLANG_GERMAN:
735                  msg_lang = "de_DE";
736                  break;
737                default:
738                  msg_lang = "de";
739               }
740               break;
741             case LANG_ITALIAN:
742               msg_lang = "it";
743               break;
744             case LANG_PORTUGUESE:
745               if (SUBLANGID(langid) == SUBLANG_PORTUGUESE_BRAZILIAN)
746                  msg_lang = "pt_BR";
747               else
748                  msg_lang = "pt";
749               break;
750             case LANG_SPANISH:
751               msg_lang = "es";
752               break;
753            }
754         }
755#endif
756      }
757   }
758#ifdef DEBUG
759   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang, msg_lang?msg_lang:"(null)");
760#endif
761
762   /* On Mandrake LANG defaults to C */
763   if (strcmp(msg_lang, "C") == 0) msg_lang = "en";
764
765   msg_lang = osstrdup(msg_lang);
766
767   /* Convert en-us to en_US, etc */
768   p = strchr(msg_lang, '-');
769   if (p) {
770      *p++ = '_';
771      while (*p) {
772         *p = toupper(*p);
773         p++;
774      }
775   }
776
777   p = strchr(msg_lang, '_');
778   if (p) {
779      *p = '\0';
780      msg_lang2 = osstrdup(msg_lang);
781      *p = '_';
782   }
783
784#ifdef LC_MESSAGES
785   /* try to setlocale() appropriately too */
786   if (!setlocale(LC_MESSAGES, msg_lang)) {
787      if (msg_lang2) setlocale(LC_MESSAGES, msg_lang2);
788   }
789#endif
790
791   select_charset(default_charset());
792}
793
794/* Message may be overwritten by next call
795 * (but not in current implementation) */
796const char *
797msg(int en)
798{
799   /* NB can't use ASSERT here! */
800   static char badbuf[256];
801   if (en >= 1000 && en < 1000 + N_DONTEXTRACTMSGS)
802      return dontextract[en - 1000];
803   if (!msg_array) {
804      if (en != 1)  {
805         sprintf(badbuf, "Message %d requested before msg_array initialised\n", en);
806         return badbuf;
807      }
808      /* this should be the only other message which can be requested before
809       * the message file is opened and read... */
810      if (!dontextract) return "Out of memory (couldn't find %lu bytes).";
811      return dontextract[4];
812   }
813
814   if (en < 0 || en >= num_msgs) {
815      sprintf(badbuf, "Message %d out of range\n", en);
816      return badbuf;
817   }
818
819   return msg_array[en];
820}
821
822/* returns persistent copy of message */
823const char *
824msgPerm(int en)
825{
826   return msg(en);
827}
828
829void
830v_report(int severity, const char *fnm, int line, int en, va_list ap)
831{
832#ifdef AVEN
833   aven_v_report(severity, fnm, line, en, ap);
834#else
835   if (fnm) {
836      fputs(fnm, STDERR);
837      if (line) fprintf(STDERR, ":%d", line);
838   } else {
839      fputs(appname_copy, STDERR);
840   }
841   fputs(": ", STDERR);
842
843   if (severity == 0) {
844      fputs(msg(/*warning*/4), STDERR);
845      fputs(": ", STDERR);
846   }
847
848   vfprintf(STDERR, msg(en), ap);
849   fputnl(STDERR);
850#endif
851
852   switch (severity) {
853    case 0:
854      msg_warnings++;
855      break;
856    case 1:
857      msg_errors++;
858      if (msg_errors == 50)
859         fatalerror_in_file(fnm, 0, /*Too many errors - giving up*/19);
860      break;
861    case 2:
862      exit(EXIT_FAILURE);
863   }
864}
865
866void
867warning(int en, ...)
868{
869   va_list ap;
870   va_start(ap, en);
871   v_report(0, NULL, 0, en, ap);
872   va_end(ap);
873}
874
875void
876error(int en, ...)
877{
878   va_list ap;
879   va_start(ap, en);
880   v_report(1, NULL, 0, en, ap);
881   va_end(ap);
882}
883
884void
885fatalerror(int en, ...)
886{
887   va_list ap;
888   va_start(ap, en);
889   v_report(2, NULL, 0, en, ap);
890   va_end(ap);
891}
892
893void
894warning_in_file(const char *fnm, int line, int en, ...)
895{
896   va_list ap;
897   va_start(ap, en);
898   v_report(0, fnm, line, en, ap);
899   va_end(ap);
900}
901
902void
903error_in_file(const char *fnm, int line, int en, ...)
904{
905   va_list ap;
906   va_start(ap, en);
907   v_report(1, fnm, line, en, ap);
908   va_end(ap);
909}
910
911void
912fatalerror_in_file(const char *fnm, int line, int en, ...)
913{
914   va_list ap;
915   va_start(ap, en);
916   v_report(2, fnm, line, en, ap);
917   va_end(ap);
918}
919
920/* Code to support switching character set at runtime (e.g. for a printer
921 * driver to support different character sets on screen and on the printer)
922 */
923typedef struct charset_li {
924   struct charset_li *next;
925   int code;
926   char **msg_array;
927} charset_li;
928
929static charset_li *charset_head = NULL;
930
931static int charset = CHARSET_BAD;
932
933int
934select_charset(int charset_code)
935{
936   int old_charset = charset;
937   charset_li *p;
938
939#ifdef DEBUG
940   fprintf(stderr, "select_charset(%d), old charset = %d\n", charset_code,
941           charset);
942#endif
943
944   charset = charset_code;
945
946   /* check if we've already parsed messages for new charset */
947   for (p = charset_head; p; p = p->next) {
948#ifdef DEBUG
949      printf("%p: code %d msg_array %p\n", p, p->code, p->msg_array);
950#endif
951      if (p->code == charset) {
952         msg_array = p->msg_array;
953         return old_charset;
954      }
955   }
956
957   /* nope, got to reparse message file */
958   parse_msg_file(charset_code);
959
960   /* add to list */
961   p = osnew(charset_li);
962   p->code = charset;
963   p->msg_array = msg_array;
964   p->next = charset_head;
965   charset_head = p;
966
967   return old_charset;
968}
Note: See TracBrowser for help on using the repository browser.