source: git/src/message.c @ dc639a8

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

Fixes to get a clean compile.

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