source: git/src/message.c @ 45c17c8

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

Added support for MS Windows CP1252 (extended version of iso-8859-1).

(Unix version): now get character set from $LANG.

Transliterate accented characters that can't be represented in the
current character set.

aven: reporting errors in a message box wasn't working (wxWindows
FormatV bug - workaround using PrintfV instead).

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

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