source: git/src/message.c @ 6d9426d

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 6d9426d was e2ae719, checked in by Olly Betts <olly@…>, 24 years ago

DOS CP 850 translation should be compiled into win32 build too.

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

  • Property mode set to 100644
File size: 22.7 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                   default: return CHARSET_USASCII;               
310                  }
311               }
312            }
313            break;
314          case 'u':
315            if (tolower(chset[1]) == 't' && tolower(chset[2]) == 'f') {
316               chset += 3;
317               while (chset < p && *chset && !isdigit(*chset)) chset++;
318               switch (atoi(chset)) {
319                case 8: return CHARSET_UTF8;
320                default: return CHARSET_USASCII;
321               }
322            }
323         }
324      }
325   }
326   return CHARSET_USASCII;
327#endif
328#else
329# error Do not know operating system 'OS'
330#endif
331}
332
333#if (OS==MSDOS || OS==WIN32)
334static int
335xlate_dos_cp850(int unicode)
336{
337   switch (unicode) {
338#include "uni2dos.h"
339   }
340   return 0;
341}
342#endif
343
344/* It seems that Swedish and maybe some other scandanavian languages don't
345 * transliterate &auml; to ae - but it seems there may be conflicting views
346 * on this...
347 */
348#define umlaut_to_e() 1
349
350static int
351add_unicode(int charset, unsigned char *p, int value)
352{
353#ifdef DEBUG
354   fprintf(stderr, "add_unicode(%d, %p, %d)\n", charset, p, value);
355#endif
356   if (value == 0) return 0;
357   switch (charset) {
358   case CHARSET_USASCII:
359      if (value < 0x80) {
360         *p = value;
361         return 1;
362      }
363      break;
364   case CHARSET_ISO_8859_1:
365      if (value < 0x100) {
366         *p = value;
367         return 1;
368      }
369      break;
370#if (OS==RISCOS)
371   case CHARSET_RISCOS31:
372      /* RISC OS 3.1 (and later) extensions to ISO-8859-1 */
373      switch (value) {
374       case 0x152: value = 0x9a; break; /* &OElig; */
375       case 0x153: value = 0x9b; break; /* &oelig; */
376       case 0x174: value = 0x81; break; /* &Wcirc; */
377       case 0x175: value = 0x82; break; /* &wcirc; */
378       case 0x176: value = 0x85; break; /* &Ycirc; */
379       case 0x177: value = 0x86; break; /* &ycirc; */
380      }
381      if (value < 0x100) {
382         *p = value;
383         return 1;
384      }
385      break;
386#elif (OS==WIN32)
387   case CHARSET_WINCP1252:
388      /* MS Windows extensions to ISO-8859-1 */
389      /* there are a few other obscure ones we don't currently need */
390      switch (value) {
391       case 0x152: value = 0x8c; break; /* &OElig; */
392       case 0x153: value = 0x9c; break; /* &oelig; */
393      }
394      if (value < 0x100) {
395         *p = value;
396         return 1;
397      }
398      break;
399#endif
400#if (OS==MSDOS || OS==WIN32)
401   case CHARSET_DOSCP850:
402      value = xlate_dos_cp850(value);
403      if (value) {
404         *p = value;
405         return 1;
406      }
407      break;
408#endif
409   }
410   /* Transliterate characters we can't represent */
411#ifdef DEBUG
412   fprintf(stderr, "transliterate `%c' 0x%x\n", value, value);
413#endif
414   switch (value) {
415    case 160:
416      *p = ' '; return 1;
417    case 161 /* ¡ */:
418      *p = '!'; return 1;
419    case 171 /* « */:
420      p[1] = *p = '<'; return 2;
421    case 187 /* » */:
422      p[1] = *p = '>'; return 2;
423    case 191 /* ¿ */:
424      *p = '?'; return 1;
425    case 192 /* À */: case 193 /* Á */: case 194 /* Â */: case 195 /* Ã */:
426      *p = 'A'; return 1;
427    case 197 /* Å */:
428      p[1] = *p = 'A'; return 2;
429    case 196 /* Ä */: /* &Auml; */
430      *p = 'A';
431      if (!umlaut_to_e()) return 1;
432      p[1] = 'E'; return 2;
433    case 198 /* Æ */:
434      *p = 'A'; p[1] = 'E'; return 2;
435    case 199 /* Ç */:
436      *p = 'C'; return 1;
437    case 200 /* È */: case 201 /* É */: case 202 /* Ê */: case 203 /* Ë */:
438      *p = 'E'; return 1;
439    case 204 /* Ì */: case 205 /* Í */: case 206 /* Î */: case 207 /* Ï */:
440      *p = 'I'; return 1;
441    case 208 /* Ð */: case 222 /* Þ */:
442      *p = 'T'; p[1] = 'H'; return 2;
443    case 209 /* Ñ */:
444      *p = 'N'; return 1;
445    case 210 /* Ò */: case 211 /* Ó */: case 212 /* Ô */: case 213 /* Õ */:
446      *p = 'O'; return 1;
447    case 214 /* Ö */: /* &Ouml; */ case 0x152: /* &OElig; */
448      *p = 'O'; p[1] = 'E'; return 2;
449    case 217 /* Ù */: case 218 /* Ú */: case 219 /* Û */:
450      *p = 'U'; return 1;
451    case 220 /* Ü */: /* &Uuml; */
452      *p = 'U'; p[1] = 'E'; return 2;
453    case 221 /* Ý */:
454      *p = 'Y'; return 1;
455    case 223 /* ß */:
456      p[1] = *p = 's'; return 2;
457    case 224 /* à */: case 225 /* á */: case 226 /* â */: case 227 /* ã */:
458      *p = 'a'; return 1;
459    case 228 /* ä */: /* &auml; */ case 230 /* æ */:
460      *p = 'a'; p[1] = 'e'; return 2;
461    case 229 /* å */:
462      p[1] = *p = 'a'; return 2;
463    case 231 /* ç */:
464      *p = 'c'; return 1;
465    case 232 /* è */: case 233 /* é */: case 234 /* ê */: case 235 /* ë */:
466      *p = 'e'; return 1;
467    case 236 /* ì */: case 237 /* í */: case 238 /* î */: case 239 /* ï */:
468      *p = 'i'; return 1;
469    case 241 /* ñ */:
470      *p = 'n'; return 1;
471    case 240 /* ð */: case 254 /* þ */:
472      *p = 't'; p[1] = 'h'; return 2;
473    case 242 /* ò */: case 243 /* ó */: case 244 /* ô */: case 245 /* õ */:
474      *p = 'o'; return 1;
475    case 246 /* ö */: /* &ouml; */ case 0x153: /* &oelig; */
476      *p = 'o'; p[1] = 'e'; return 2;
477    case 249 /* ù */: case 250 /* ú */: case 251 /* û */:
478      *p = 'u'; return 1;
479    case 252 /* ü */: /* &uuml; */
480      *p = 'u'; p[1] = 'e'; return 2;
481    case 253 /* ý */: case 255 /* ÿ */:
482      *p = 'y'; return 1;
483   }
484#ifdef DEBUG
485   fprintf(stderr, "failed to transliterate\n");
486#endif
487   return 0;
488}
489
490/* fall back on looking in the current directory */
491static const char *pth_cfg_files = "";
492
493static int num_msgs = 0;
494static char **msg_array = NULL;
495
496const char *msg_lang = NULL;
497const char *msg_lang2 = NULL;
498
499static char **
500parse_msgs(int n, unsigned char *p, int charset_code) {
501   int i;
502
503   char **msgs = osmalloc(n * sizeof(char *));
504
505   for (i = 0; i < n; i++) {
506      unsigned char *to = p;
507      int ch;
508      msgs[i] = (char *)p;
509
510      /* If we want UTF8 anyway, we just need to find the start of each
511       * message */
512      if (charset_code == CHARSET_UTF8) {
513         p += strlen((char *)p) + 1;
514         continue;
515      }
516
517      while ((ch = *p++) != 0) {
518         /* A byte in the range 0x80-0xbf or 0xf0-0xff isn't valid in
519          * this state, (0xf0-0xfd mean values > 0xffff) so treat as
520          * literal and try to resync so we cope better when fed
521          * non-utf-8 data.  Similarly we abandon a multibyte sequence
522          * if we hit an invalid character. */
523         if (ch >= 0xc0 && ch < 0xf0) {
524            int ch1 = *p;
525            if ((ch1 & 0xc0) != 0x80) goto resync;
526
527            if (ch < 0xe0) {
528               /* 2 byte sequence */
529               ch = ((ch & 0x1f) << 6) | (ch1 & 0x3f);
530               p++;
531            } else {
532               /* 3 byte sequence */
533               int ch2 = p[1];
534               if ((ch2 & 0xc0) != 0x80) goto resync;
535               ch = ((ch & 0x1f) << 12) | ((ch1 & 0x3f) << 6) | (ch2 & 0x3f);
536               p += 2;
537            }
538         }
539
540         resync:
541
542         if (ch < 127) {
543            *to++ = (char)ch;
544         } else {
545            /* We assume an N byte UTF-8 code never transliterates to more
546             * than N characters (so we can't transliterate © to (C) or
547             * ® to (R) for example) */
548            to += add_unicode(charset_code, to, ch);
549         }
550      }
551      *to++ = '\0';
552   }
553   return msgs;
554}
555
556/* No point extracting these errors as they won't get used if file opens */
557#define HDR(D) "../lib/"STRING(D)".h"
558#include HDR(DEFAULTLANG)
559
560static char **dontextract = NULL;
561
562static void
563parse_msg_file(int charset_code)
564{
565   FILE *fh;
566   unsigned char header[20];
567   int i;   
568   unsigned len;
569   unsigned char *p;
570   char *fnm, *s;
571   int n;
572
573#ifdef DEBUG
574   fprintf(stderr, "parse_msg_file(%d)\n", charset_code);
575#endif
576
577   /* sort out messages we need to print if we can't open the message file */
578   dontextract = parse_msgs(N_DONTEXTRACTMSGS, dontextractmsgs, charset_code);
579
580   fnm = osstrdup(msg_lang);
581   /* trim off charset from stuff like "de_DE.iso8859_1" */
582   s = strchr(fnm, '.');
583   if (s) *s = '\0';
584
585   fh = fopenWithPthAndExt(pth_cfg_files, fnm, EXT_SVX_MSG, "rb", NULL);
586
587   if (!fh) {
588      /* e.g. if 'en-COCKNEY' is unknown, see if we know 'en' */
589      if (strlen(fnm) > 3 && fnm[2] == '-') {
590         fnm[2] = '\0';
591         fh = fopenWithPthAndExt(pth_cfg_files, fnm, EXT_SVX_MSG, "rb", NULL);
592         if (!fh) fnm[2] = '-'; /* for error reporting */
593      }
594   }
595
596   if (!fh) {
597      fatalerror(/*Can't open message file `%s' using path `%s'*/1000,
598                 fnm, pth_cfg_files);
599   }
600
601   if (fread(header, 1, 20, fh) < 20 ||
602       memcmp(header, "Svx\nMsg\r\n\xfe\xff", 12) != 0) {
603      fatalerror(/*Problem with message file `%s'*/1001, fnm);
604   }
605
606   if (header[12] != 0)
607      fatalerror(/*I don't understand this message file version*/1002);
608
609   n = (header[14] << 8) | header[15];
610
611   len = 0;
612   for (i = 16; i < 20; i++) len = (len << 8) | header[i];
613
614   p = osmalloc(len);
615   if (fread(p, 1, len, fh) < len)
616      fatalerror(/*Message file truncated?*/1003);
617
618   fclose(fh);
619
620#ifdef DEBUG
621   fprintf(stderr, "fnm = `%s', n = %d, len = %d\n", fnm, n, len);
622#endif
623   osfree(fnm);
624
625   msg_array = parse_msgs(n, p, charset_code);
626   num_msgs = n;
627}
628
629const char *
630msg_cfgpth(void)
631{
632   return pth_cfg_files;
633}
634
635void
636msg_init(const char *argv0)
637{
638   char *p;
639
640#ifdef HAVE_SIGNAL
641   init_signals();
642#endif
643   /* Point to argv0 itself so we report a more helpful error if the code to work
644    * out the clean appname generates a signal */
645   appname_copy = argv0;
646#if (OS == UNIX)
647   /* use name as-is on Unix - programs run from path get name as supplied */
648   appname_copy = osstrdup(argv0);
649#else
650   /* use the lower-cased leafname on other platforms */
651   appname_copy = p = leaf_from_fnm(argv0);
652   while (*p) {
653      *p = tolower(*p);
654      p++;
655   }
656#endif
657
658   /* Look for env. var. "SURVEXHOME" or the like */
659   p = getenv("SURVEXHOME");
660   if (p && *p) {
661      pth_cfg_files = osstrdup(p);
662#if (OS==UNIX) && defined(DATADIR) && defined(PACKAGE)
663   } else {
664      /* under Unix, we compile in the configured path */
665      pth_cfg_files = DATADIR "/" PACKAGE;
666#else
667   } else if (argv0) {
668      /* else try the path on argv[0] */
669      pth_cfg_files = path_from_fnm(argv0);
670#endif
671   }
672
673   msg_lang = getenv("SURVEXLANG");
674#ifdef DEBUG
675   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang, msg_lang?msg_lang:"(null)");
676#endif
677
678   if (!msg_lang || !*msg_lang) {
679      msg_lang = getenv("LANG");
680      if (!msg_lang || !*msg_lang) {
681#if (OS==WIN32)
682         LCID locid;
683#endif
684         msg_lang = STRING(DEFAULTLANG);
685#if (OS==WIN32)
686         locid = GetUserDefaultLCID();
687         if (locid) {
688            WORD langid = LANGIDFROMLCID(locid);
689            switch (PRIMARYLANGID(langid)) {
690             case LANG_CATALAN:
691               msg_lang = "ca";
692               break;
693             case LANG_ENGLISH:
694               if (SUBLANGID(langid) == SUBLANG_ENGLISH_US)
695                  msg_lang = "en_US";
696               else
697                  msg_lang = "en";
698               break;
699             case LANG_FRENCH:
700               msg_lang = "fr";
701               break;
702             case LANG_GERMAN:
703               switch (SUBLANGID(langid)) {
704                case SUBLANG_GERMAN_SWISS:
705                  msg_lang = "de_CH";
706                  break;
707                case SUBLANG_GERMAN:
708                  msg_lang = "de_DE";
709                  break;
710                default:
711                  msg_lang = "de";
712               }
713               break;
714             case LANG_ITALIAN:
715               msg_lang = "it";
716               break;
717             case LANG_PORTUGUESE:
718               if (SUBLANGID(langid) == SUBLANG_PORTUGUESE_BRAZILIAN)
719                  msg_lang = "pt_BR";
720               else
721                  msg_lang = "pt";
722               break;
723             case LANG_SPANISH:
724               msg_lang = "es";
725               break;
726            }
727         }
728#endif
729      }
730   }
731#ifdef DEBUG
732   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang, msg_lang?msg_lang:"(null)");
733#endif
734
735   /* On Mandrake LANG defaults to C */
736   if (strcmp(msg_lang, "C") == 0) msg_lang = "en";
737
738   msg_lang = osstrdup(msg_lang);
739
740   /* Convert en-us to en_US, etc */
741   p = strchr(msg_lang, '-');
742   if (p) {
743      *p++ = '_';
744      while (*p) {
745         *p = toupper(*p);
746         p++;
747      }
748   }
749
750   p = strchr(msg_lang, '_');
751   if (p) {
752      *p = '\0';
753      msg_lang2 = osstrdup(msg_lang);
754      *p = '_';
755   }
756
757#ifdef LC_MESSAGES
758   /* try to setlocale() appropriately too */
759   if (!setlocale(LC_MESSAGES, msg_lang)) {
760      if (msg_lang2) setlocale(LC_MESSAGES, msg_lang2);
761   }
762#endif
763
764   select_charset(default_charset());
765}
766
767/* Message may be overwritten by next call
768 * (but not in current implementation) */
769const char *
770msg(int en)
771{
772   /* NB can't use ASSERT here! */
773   static char badbuf[256];
774   if (en >= 1000 && en < 1000 + N_DONTEXTRACTMSGS)
775      return dontextract[en - 1000];
776   if (!msg_array) {
777      if (en != 1)  {
778         sprintf(badbuf, "Message %d requested before msg_array initialised\n", en);
779         return badbuf;
780      }
781      /* this should be the only other message which can be requested before
782       * the message file is opened and read... */
783      if (!dontextract) return "Out of memory (couldn't find %lu bytes).";
784      return dontextract[4];
785   }
786
787   if (en < 0 || en >= num_msgs) {
788      sprintf(badbuf, "Message %d out of range\n", en);
789      return badbuf;
790   }
791
792   return msg_array[en];
793}
794
795/* returns persistent copy of message */
796const char *
797msgPerm(int en)
798{
799   return msg(en);
800}
801
802void
803v_report(int severity, const char *fnm, int line, int en, va_list ap)
804{
805#ifdef AVEN
806   aven_v_report(severity, fnm, line, en, ap);
807#else
808   if (fnm) {
809      fputs(fnm, STDERR);
810      if (line) fprintf(STDERR, ":%d", line);
811   } else {
812      fputs(appname_copy, STDERR);
813   }
814   fputs(": ", STDERR);
815
816   if (severity == 0) {
817      fputs(msg(/*warning*/4), STDERR);
818      fputs(": ", STDERR);
819   }
820
821   vfprintf(STDERR, msg(en), ap);
822   fputnl(STDERR);
823#endif
824
825   switch (severity) {
826    case 0:
827      msg_warnings++;
828      break;
829    case 1:
830      msg_errors++;
831      if (msg_errors == 50)
832         fatalerror_in_file(fnm, 0, /*Too many errors - giving up*/19);
833      break;
834    case 2:
835      exit(EXIT_FAILURE);
836   }
837}
838
839void
840warning(int en, ...)
841{
842   va_list ap;
843   va_start(ap, en);
844   v_report(0, NULL, 0, en, ap);
845   va_end(ap);
846}
847
848void
849error(int en, ...)
850{
851   va_list ap;
852   va_start(ap, en);
853   v_report(1, NULL, 0, en, ap);
854   va_end(ap);
855}
856
857void
858fatalerror(int en, ...)
859{
860   va_list ap;
861   va_start(ap, en);
862   v_report(2, NULL, 0, en, ap);
863   va_end(ap);
864}
865
866void
867warning_in_file(const char *fnm, int line, int en, ...)
868{
869   va_list ap;
870   va_start(ap, en);
871   v_report(0, fnm, line, en, ap);
872   va_end(ap);
873}
874
875void
876error_in_file(const char *fnm, int line, int en, ...)
877{
878   va_list ap;
879   va_start(ap, en);
880   v_report(1, fnm, line, en, ap);
881   va_end(ap);
882}
883
884void
885fatalerror_in_file(const char *fnm, int line, int en, ...)
886{
887   va_list ap;
888   va_start(ap, en);
889   v_report(2, fnm, line, en, ap);
890   va_end(ap);
891}
892
893/* Code to support switching character set at runtime (e.g. for a printer
894 * driver to support different character sets on screen and on the printer)
895 */
896typedef struct charset_li {
897   struct charset_li *next;
898   int code;
899   char **msg_array;
900} charset_li;
901
902static charset_li *charset_head = NULL;
903
904static int charset = CHARSET_BAD;
905
906int
907select_charset(int charset_code)
908{
909   int old_charset = charset;
910   charset_li *p;
911
912#ifdef DEBUG
913   fprintf(stderr, "select_charset(%d), old charset = %d\n", charset_code,
914           charset);
915#endif
916
917   charset = charset_code;
918
919   /* check if we've already parsed messages for new charset */
920   for (p = charset_head; p; p = p->next) {
921#ifdef DEBUG
922      printf("%p: code %d msg_array %p\n", p, p->code, p->msg_array);
923#endif
924      if (p->code == charset) {
925         msg_array = p->msg_array;
926         return old_charset;
927      }
928   }
929
930   /* nope, got to reparse message file */
931   parse_msg_file(charset_code);
932
933   /* add to list */
934   p = osnew(charset_li);
935   p->code = charset;
936   p->msg_array = msg_array;
937   p->next = charset_head;
938   charset_head = p;
939
940   return old_charset;
941}
Note: See TracBrowser for help on using the repository browser.