source: git/src/message.c @ af1e622

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

aven: Close button in About box is now always right in the bottom right
corner.

Display copyright symbol rather than (C) where the current character set
allows it.

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

  • Property mode set to 100644
File size: 34.9 KB
RevLine 
[fd5f670]1/* message.c
[db75e18]2 * Fairly general purpose message and error routines
[704ad2b]3 * Copyright (C) 1993-2001 Olly Betts
[846746e]4 *
[89231c4]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.
[846746e]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
[89231c4]12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
[846746e]14 *
[89231c4]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
[60f7018]18 */
19
[55de792]20/*#define DEBUG 1*/
21
[db75e18]22#ifdef HAVE_CONFIG_H
23# include <config.h>
24#endif
[60f7018]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>
[f764581]32#include <locale.h>
[60f7018]33
34#include "whichos.h"
[4432f2e]35#include "filename.h"
36#include "message.h"
[60f7018]37#include "osdepend.h"
38#include "filelist.h"
39#include "debug.h"
40
[a4140e9]41#ifdef AVEN
42#include "aven.h"
43#endif
44
[60f7018]45#ifdef HAVE_SIGNAL
[7d5f3c0]46# ifdef HAVE_SETJMP_H
[60f7018]47#  include <setjmp.h>
48static jmp_buf jmpbufSignal;
49#  include <signal.h>
50# else
51#  undef HAVE_SIGNAL
52# endif
53#endif
54
[6754d07]55#if (OS==WIN32)
56#include <windows.h>
[1b92879]57#elif (OS==MSDOS)
58#include <dos.h>
59#elif (OS==RISCOS)
[2163157]60#include "oslib/wimpreadsy.h"
61#endif
62
[60f7018]63/* For funcs which want to be immune from messing around with different
64 * calling conventions */
65#ifndef CDECL
[2ca296b]66# define CDECL
[60f7018]67#endif
68
[25ab06b]69int msg_warnings = 0; /* keep track of how many warnings we've given */
70int msg_errors = 0;   /* and how many (non-fatal) errors */
[60f7018]71
[a4140e9]72/* in case osmalloc() fails before appname_copy is set up */
73static const char *appname_copy = "anonymous program";
[60f7018]74
75/* error code for failed osmalloc and osrealloc calls */
[db75e18]76static void
77outofmem(OSSIZE_T size)
78{
[bd1913f]79   fatalerror(/*Out of memory (couldn't find %lu bytes).*/1,
80              (unsigned long)size);
[60f7018]81}
82
[a420b49]83#ifdef TOMBSTONES
84#define TOMBSTONE_SIZE 16
[bd1913f]85static const char tombstone[TOMBSTONE_SIZE] = "012345\xfftombstone";
[a420b49]86#endif
87
[60f7018]88/* malloc with error catching if it fails. Also allows us to write special
89 * versions easily eg for DOS EMS or MS Windows.
90 */
[bd1913f]91void FAR *
[db75e18]92osmalloc(OSSIZE_T size)
93{
[60f7018]94   void FAR *p;
[a420b49]95#ifdef TOMBSTONES
96   size += TOMBSTONE_SIZE * 2;
97   p = malloc(size);
98#else
[db75e18]99   p = xosmalloc(size);
[a420b49]100#endif
[2ca296b]101   if (p == NULL) outofmem(size);
[a420b49]102#ifdef TOMBSTONES
[bd1913f]103   printf("osmalloc truep=%p truesize=%d\n", p, size);
[a420b49]104   memcpy(p, tombstone, TOMBSTONE_SIZE);
105   memcpy(p + size - TOMBSTONE_SIZE, tombstone, TOMBSTONE_SIZE);
106   *(size_t *)p = size;
107   p += TOMBSTONE_SIZE;
108#endif
[60f7018]109   return p;
110}
111
112/* realloc with error catching if it fails. */
[bd1913f]113void FAR *
[db75e18]114osrealloc(void *p, OSSIZE_T size)
115{
[a420b49]116   /* some pre-ANSI realloc implementations don't cope with a NULL pointer */
117   if (p == NULL) {
118      p = xosmalloc(size);
119   } else {
120#ifdef TOMBSTONES
121      int true_size;
122      size += TOMBSTONE_SIZE * 2;
123      p -= TOMBSTONE_SIZE;
124      true_size = *(size_t *)p;
[bd1913f]125      printf("osrealloc (in truep=%p truesize=%d)\n", p, true_size);
[a420b49]126      if (memcmp(p + sizeof(size_t), tombstone + sizeof(size_t),
127                 TOMBSTONE_SIZE - sizeof(size_t)) != 0) {
128         printf("start tombstone for block %p, size %d corrupted!",
[cb3d1e2]129                p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]130      }
131      if (memcmp(p + true_size - TOMBSTONE_SIZE, tombstone,
132                 TOMBSTONE_SIZE) != 0) {
133         printf("end tombstone for block %p, size %d corrupted!",
[cb3d1e2]134                p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]135      }
136      p = realloc(p, size);
137      if (p == NULL) outofmem(size);
[bd1913f]138      printf("osrealloc truep=%p truesize=%d\n", p, size);
[a420b49]139      memcpy(p, tombstone, TOMBSTONE_SIZE);
140      memcpy(p + size - TOMBSTONE_SIZE, tombstone, TOMBSTONE_SIZE);
141      *(size_t *)p = size;
142      p += TOMBSTONE_SIZE;
143#else
144      p = xosrealloc(p, size);
145#endif
146   }
[2ca296b]147   if (p == NULL) outofmem(size);
[60f7018]148   return p;
149}
150
[b2c945f]151char FAR *
[db75e18]152osstrdup(const char *str)
153{
[60f7018]154   char *p;
[db75e18]155   OSSIZE_T len;
156   len = strlen(str) + 1;
[0a3c5fa]157   p = osmalloc(len);
[db75e18]158   memcpy(p, str, len);
[60f7018]159   return p;
160}
161
[a420b49]162/* osfree is usually just a macro in osalloc.h */
163#ifdef TOMBSTONES
[bd1913f]164void
[a420b49]165osfree(void *p)
166{
167   int true_size;
168   if (!p) return;
169   p -= TOMBSTONE_SIZE;
170   true_size = *(size_t *)p;
[bd1913f]171   printf("osfree truep=%p truesize=%d\n", p, true_size);
[a420b49]172   if (memcmp(p + sizeof(size_t), tombstone + sizeof(size_t),
173              TOMBSTONE_SIZE - sizeof(size_t)) != 0) {
174      printf("start tombstone for block %p, size %d corrupted!",
[cb3d1e2]175             p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]176   }
177   if (memcmp(p + true_size - TOMBSTONE_SIZE, tombstone,
178              TOMBSTONE_SIZE) != 0) {
179      printf("end tombstone for block %p, size %d corrupted!",
[cb3d1e2]180             p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]181   }
182   free(p);
183}
184#endif
[60f7018]185
186#ifdef HAVE_SIGNAL
187
188static int sigReceived;
189
190/* for systems not using autoconf, assume the signal handler returns void
191 * unless specified elsewhere */
192#ifndef RETSIGTYPE
[2ca296b]193# define RETSIGTYPE void
[60f7018]194#endif
195
[bd1913f]196static CDECL RETSIGTYPE FAR
197report_sig(int sig)
198{
[db75e18]199   sigReceived = sig;
[2ca296b]200   longjmp(jmpbufSignal, 1);
[60f7018]201}
202
[db75e18]203static void
204init_signals(void)
205{
[60f7018]206   int en;
207   if (!setjmp(jmpbufSignal)) {
[0a3c5fa]208#if 1 /* disable these to get a core dump */
[db75e18]209      signal(SIGABRT, report_sig); /* abnormal termination eg abort() */
210      signal(SIGFPE,  report_sig); /* arithmetic error eg /0 or overflow */
211      signal(SIGILL,  report_sig); /* illegal function image eg illegal instruction */
212      signal(SIGSEGV, report_sig); /* illegal storage access eg access outside memory limits */
213#endif
[60f7018]214# ifdef SIGSTAK /* only on RISC OS AFAIK */
[db75e18]215      signal(SIGSTAK, report_sig); /* stack overflow */
[60f7018]216# endif
217      return;
218   }
[db75e18]219
[60f7018]220   switch (sigReceived) {
[bd1913f]221      case SIGABRT: en = /*Abnormal termination*/90; break;
222      case SIGFPE:  en = /*Arithmetic error*/91; break;
223      case SIGILL:  en = /*Illegal instruction*/92; break;
224      case SIGSEGV: en = /*Bad memory access*/94; break;
[60f7018]225# ifdef SIGSTAK
[bd1913f]226      case SIGSTAK: en = /*Stack overflow*/96; break;
[60f7018]227# endif
[bd1913f]228      default:      en = /*Unknown signal received*/97; break;
[60f7018]229   }
[db75e18]230   fputsnl(msg(en), STDERR);
[ea816ec]231
[c0a9908]232   /* Any of the signals we catch indicates a bug */
233   fatalerror(/*Bug in program detected! Please report this to the authors*/11);
[db75e18]234
[60f7018]235   exit(EXIT_FAILURE);
236}
237#endif
238
[bd1913f]239static int
240default_charset(void)
241{
[8769f9f]242#if (OS==RISCOS)
[ea816ec]243   /* RISCOS 3.1 and above CHARSET_RISCOS31 (ISO_8859_1 + extras in 128-159)
244    * RISCOS < 3.1 is ISO_8859_1 */
[2163157]245   int version;
[ea816ec]246   if (xwimpreadsysinfo_version(&version) != NULL) {
247      /* RISC OS 2 or some error (don't care which) */
248      return CHARSET_ISO_8859_1;
249   }
250
251   /* oddly wimp_VERSION_RO3 is RISC OS 3.1 */
252   if (version < wimp_VERSION_RO3) return CHARSET_ISO_8859_1;
[2163157]253
[2ca296b]254   return CHARSET_RISCOS31;
[60f7018]255#elif (OS==MSDOS)
256   return CHARSET_DOSCP850;
[a4140e9]257#elif (OS==WIN32)
[d5bd3a7]258# ifdef AVEN
[31ccf72]259#  define CODEPAGE GetACP()
[d5bd3a7]260# else
[31ccf72]261#  define CODEPAGE GetConsoleOutputCP()
262# endif
263   switch (CODEPAGE) {
[dc639a8]264    case 1252: return CHARSET_WINCP1252;
265    case 850: return CHARSET_DOSCP850;
[d5bd3a7]266   }
267   return CHARSET_USASCII;
[a4140e9]268#elif (OS==UNIX)
269#if defined(XCAVEROT) || defined(AVEN)
[8769f9f]270   return CHARSET_ISO_8859_1;
[a4140e9]271#else
[8c15864]272   const char *p = getenv("LC_ALL");
[31ccf72]273   if (p == NULL || p[0] == '\0') {
274      p = getenv("LC_CTYPE");
275      if (p == NULL || p[0] == '\0') {
276         p = msg_lang;
277      }
278   }
279
280   if (p) {
281      char *q = strchr(p, '.');
282      if (q) p = q + 1;
283   }
284
[a4140e9]285   if (p) {
[8c15864]286      const char *chset = p;
[a4140e9]287      size_t name_len;
288
289      while (*p != '\0' && *p != '@') p++;
290
291      name_len = p - chset;
292
293      if (name_len) {
294         int only_digit = 1;
295         size_t cnt;
296       
297         for (cnt = 0; cnt < name_len; ++cnt)
298            if (isalpha(chset[cnt])) {
299               only_digit = 0;
300               break;
301            }
302
303         if (only_digit) goto iso;
304         
305         switch (tolower(chset[0])) {
306          case 'i':
307            if (tolower(chset[1]) == 's' && tolower(chset[2]) == 'o') {
308               chset += 3;
309               iso:
310               if (strncmp(chset, "8859", 4) == 0) {
311                  chset += 4;
312                  while (chset < p && *chset && !isdigit(*chset)) chset++;
313                  switch (atoi(chset)) {
314                   case 1: return CHARSET_ISO_8859_1;
[f8e03f3]315                   case 15: return CHARSET_ISO_8859_15;
[a4140e9]316                   default: return CHARSET_USASCII;               
317                  }
318               }
319            }
320            break;
321          case 'u':
322            if (tolower(chset[1]) == 't' && tolower(chset[2]) == 'f') {
323               chset += 3;
324               while (chset < p && *chset && !isdigit(*chset)) chset++;
325               switch (atoi(chset)) {
326                case 8: return CHARSET_UTF8;
327                default: return CHARSET_USASCII;
328               }
329            }
330         }
331      }
332   }
333   return CHARSET_USASCII;
334#endif
335#else
336# error Do not know operating system 'OS'
[60f7018]337#endif
338}
339
[a4140e9]340/* It seems that Swedish and maybe some other scandanavian languages don't
341 * transliterate &auml; to ae - but it seems there may be conflicting views
342 * on this...
343 */
344#define umlaut_to_e() 1
345
[1b92879]346/* values <= 127 already dealt with */
[db75e18]347static int
[55de792]348add_unicode(int charset, unsigned char *p, int value)
[db75e18]349{
[55de792]350#ifdef DEBUG
351   fprintf(stderr, "add_unicode(%d, %p, %d)\n", charset, p, value);
352#endif
[4432f2e]353   if (value == 0) return 0;
[48e4121]354   switch (charset) {
[db75e18]355   case CHARSET_USASCII:
[6a4871e]356      if (value < 0x80) {
[48e4121]357         *p = value;
358         return 1;
359      }
360      break;
[db75e18]361   case CHARSET_ISO_8859_1:
[6a4871e]362      if (value < 0x100) {
[48e4121]363         *p = value;
364         return 1;
365      }
[ea816ec]366      break;
[f8e03f3]367   case CHARSET_ISO_8859_15:
368      switch (value) {
369       case 0xa4: case 0xa6: case 0xb0: case 0xc4:
370       case 0xd0: case 0xd4: case 0xd5: case 0xd6:
371         goto donthave;
372       case 0x152: value = 0xd4; break; /* &OElig; */
373       case 0x153: value = 0xd5; break; /* &oelig; */
374#if 0
375       case 0x0: value = 0xa4; break; /* euro */
376       case 0x0: value = 0xa6; break; /* Scaron */
377       case 0x0: value = 0xb0; break; /* scaron */
378       case 0x0: value = 0xc4; break; /* Zcaron */
379       case 0x0: value = 0xd0; break; /* zcaron */
380       case 0x0: value = 0xd6; break; /* Ydiersis */
381#endif
382      }
383      if (value < 0x100) {
384         *p = value;
385         return 1;
386      }
387      donthave:
388      break;
[48e4121]389#if (OS==RISCOS)
[ea816ec]390   case CHARSET_RISCOS31:
391      /* RISC OS 3.1 (and later) extensions to ISO-8859-1 */
392      switch (value) {
393       case 0x152: value = 0x9a; break; /* &OElig; */
394       case 0x153: value = 0x9b; break; /* &oelig; */
[f8e03f3]395#if 0
[ea816ec]396       case 0x174: value = 0x81; break; /* &Wcirc; */
397       case 0x175: value = 0x82; break; /* &wcirc; */
398       case 0x176: value = 0x85; break; /* &Ycirc; */
399       case 0x177: value = 0x86; break; /* &ycirc; */
[f8e03f3]400#endif
[ea816ec]401      }
402      if (value < 0x100) {
403         *p = value;
404         return 1;
405      }
[48e4121]406      break;
[a4140e9]407#elif (OS==WIN32)
408   case CHARSET_WINCP1252:
409      /* MS Windows extensions to ISO-8859-1 */
410      switch (value) {
411       case 0x152: value = 0x8c; break; /* &OElig; */
412       case 0x153: value = 0x9c; break; /* &oelig; */
[f8e03f3]413#if 0
414      /* there are a few other obscure ones we don't currently need */
415#endif
[a4140e9]416      }
417      if (value < 0x100) {
418         *p = value;
419         return 1;
420      }
[e2ae719]421      break;
422#endif
423#if (OS==MSDOS || OS==WIN32)
[1b92879]424   case CHARSET_DOSCP850: {
425      unsigned char uni2dostab[] = {
426         255, 173, 189, 156, 207, 190, 221, 245,
427         249, 184, 166, 174, 170, 240, 169, 238,
428         248, 241, 253, 252, 239, 230, 244, 250,
429         247, 251, 167, 175, 172, 171, 243, 168,
430         183, 181, 182, 199, 142, 143, 146, 128,
431         212, 144, 210, 211, 222, 214, 215, 216,
432         209, 165, 227, 224, 226, 229, 153, 158,
433         157, 235, 233, 234, 154, 237, 232, 225,
434         133, 160, 131, 198, 132, 134, 145, 135,
435         138, 130, 136, 137, 141, 161, 140, 139,
436         208, 164, 149, 162, 147, 228, 148, 246,
437         155, 151, 163, 150, 129, 236, 231, 152
438      };
439      if (value >= 160 && value < 256) {
440         *p = (int)uni2dostab[value - 160];
441         return 1;
442      }
443      if (value == 305) {
444         *p = 213;
445         return 1;
446      }
447      if (value == 402) {
448         *p = 159;
[48e4121]449         return 1;
450      }
451      break;
[66f8e13]452   }
[48e4121]453#endif
[4432f2e]454   }
[a4140e9]455   /* Transliterate characters we can't represent */
456#ifdef DEBUG
457   fprintf(stderr, "transliterate `%c' 0x%x\n", value, value);
458#endif
459   switch (value) {
460    case 160:
461      *p = ' '; return 1;
462    case 161 /* ¡ */:
463      *p = '!'; return 1;
464    case 171 /* « */:
465      p[1] = *p = '<'; return 2;
466    case 187 /* » */:
467      p[1] = *p = '>'; return 2;
468    case 191 /* ¿ */:
469      *p = '?'; return 1;
470    case 192 /* À */: case 193 /* Á */: case 194 /* Â */: case 195 /* Ã */:
471      *p = 'A'; return 1;
472    case 197 /* Å */:
473      p[1] = *p = 'A'; return 2;
474    case 196 /* Ä */: /* &Auml; */
475      *p = 'A';
476      if (!umlaut_to_e()) return 1;
477      p[1] = 'E'; return 2;
478    case 198 /* Æ */:
479      *p = 'A'; p[1] = 'E'; return 2;
480    case 199 /* Ç */:
481      *p = 'C'; return 1;
482    case 200 /* È */: case 201 /* É */: case 202 /* Ê */: case 203 /* Ë */:
483      *p = 'E'; return 1;
484    case 204 /* Ì */: case 205 /* Í */: case 206 /* Î */: case 207 /* Ï */:
485      *p = 'I'; return 1;
486    case 208 /* Ð */: case 222 /* Þ */:
487      *p = 'T'; p[1] = 'H'; return 2;
488    case 209 /* Ñ */:
489      *p = 'N'; return 1;
490    case 210 /* Ò */: case 211 /* Ó */: case 212 /* Ô */: case 213 /* Õ */:
491      *p = 'O'; return 1;
492    case 214 /* Ö */: /* &Ouml; */ case 0x152: /* &OElig; */
493      *p = 'O'; p[1] = 'E'; return 2;
494    case 217 /* Ù */: case 218 /* Ú */: case 219 /* Û */:
495      *p = 'U'; return 1;
496    case 220 /* Ü */: /* &Uuml; */
497      *p = 'U'; p[1] = 'E'; return 2;
498    case 221 /* Ý */:
499      *p = 'Y'; return 1;
500    case 223 /* ß */:
501      p[1] = *p = 's'; return 2;
502    case 224 /* à */: case 225 /* á */: case 226 /* â */: case 227 /* ã */:
503      *p = 'a'; return 1;
504    case 228 /* ä */: /* &auml; */ case 230 /* æ */:
505      *p = 'a'; p[1] = 'e'; return 2;
506    case 229 /* å */:
507      p[1] = *p = 'a'; return 2;
508    case 231 /* ç */:
509      *p = 'c'; return 1;
510    case 232 /* è */: case 233 /* é */: case 234 /* ê */: case 235 /* ë */:
511      *p = 'e'; return 1;
512    case 236 /* ì */: case 237 /* í */: case 238 /* î */: case 239 /* ï */:
513      *p = 'i'; return 1;
514    case 241 /* ñ */:
515      *p = 'n'; return 1;
516    case 240 /* ð */: case 254 /* þ */:
517      *p = 't'; p[1] = 'h'; return 2;
518    case 242 /* ò */: case 243 /* ó */: case 244 /* ô */: case 245 /* õ */:
519      *p = 'o'; return 1;
520    case 246 /* ö */: /* &ouml; */ case 0x153: /* &oelig; */
521      *p = 'o'; p[1] = 'e'; return 2;
522    case 249 /* ù */: case 250 /* ú */: case 251 /* û */:
523      *p = 'u'; return 1;
524    case 252 /* ü */: /* &uuml; */
525      *p = 'u'; p[1] = 'e'; return 2;
526    case 253 /* ý */: case 255 /* ÿ */:
527      *p = 'y'; return 1;
528   }
529#ifdef DEBUG
530   fprintf(stderr, "failed to transliterate\n");
531#endif
[f1a5201]532   return 0;
[4432f2e]533}
534
[f2a6ce4]535/* fall back on looking in the current directory */
536static const char *pth_cfg_files = "";
537
[db75e18]538static int num_msgs = 0;
[55de792]539static char **msg_array = NULL;
[db75e18]540
[b83f907]541const char *msg_lang = NULL;
[c0a9908]542const char *msg_lang2 = NULL;
[b83f907]543
[d5bd3a7]544static char **
545parse_msgs(int n, unsigned char *p, int charset_code) {
546   int i;
547
548   char **msgs = osmalloc(n * sizeof(char *));
549
550   for (i = 0; i < n; i++) {
551      unsigned char *to = p;
552      int ch;
553      msgs[i] = (char *)p;
554
555      /* If we want UTF8 anyway, we just need to find the start of each
556       * message */
557      if (charset_code == CHARSET_UTF8) {
558         p += strlen((char *)p) + 1;
559         continue;
560      }
561
562      while ((ch = *p++) != 0) {
563         /* A byte in the range 0x80-0xbf or 0xf0-0xff isn't valid in
564          * this state, (0xf0-0xfd mean values > 0xffff) so treat as
565          * literal and try to resync so we cope better when fed
566          * non-utf-8 data.  Similarly we abandon a multibyte sequence
567          * if we hit an invalid character. */
568         if (ch >= 0xc0 && ch < 0xf0) {
569            int ch1 = *p;
570            if ((ch1 & 0xc0) != 0x80) goto resync;
571
572            if (ch < 0xe0) {
573               /* 2 byte sequence */
574               ch = ((ch & 0x1f) << 6) | (ch1 & 0x3f);
575               p++;
576            } else {
577               /* 3 byte sequence */
578               int ch2 = p[1];
579               if ((ch2 & 0xc0) != 0x80) goto resync;
580               ch = ((ch & 0x1f) << 12) | ((ch1 & 0x3f) << 6) | (ch2 & 0x3f);
581               p += 2;
582            }
583         }
584
585         resync:
586
587         if (ch < 127) {
588            *to++ = (char)ch;
589         } else {
590            /* We assume an N byte UTF-8 code never transliterates to more
591             * than N characters (so we can't transliterate © to (C) or
592             * ® to (R) for example) */
593            to += add_unicode(charset_code, to, ch);
594         }
595      }
596      *to++ = '\0';
597   }
598   return msgs;
599}
600
[0874cd6a]601/* This is the name of the default language.  Add -DDEFAULTLANG to CFLAGS
602 * e.g. with `CFLAGS="-DDEFAULTLANG=fr" ./configure'
603 */
604#ifdef DEFAULTLANG
[d5bd3a7]605/* No point extracting these errors as they won't get used if file opens */
[0874cd6a]606/* FIXME: this works on gcc but not some other compilers (e.g. norcroft),
607 * and also ../lib/fr.h, etc don't go into srcN_NN.zip */
608# define HDR(D) "../lib/"STRING(D)".h"
609# include HDR(DEFAULTLANG)
610#else
611#define N_DONTEXTRACTMSGS 5
612static unsigned char dontextractmsgs[] =
613   "Can't open message file `%s' using path `%s'\0"/*1000*/
614   "Problem with message file `%s'\0"/*1001*/
615   "I don't understand this message file version\0"/*1002*/
616   "Message file truncated?\0"/*1003*/
617   "Out of memory (couldn't find %lu bytes).\0"/*1004*/;
618#endif
[d5bd3a7]619
620static char **dontextract = NULL;
621
[db75e18]622static void
623parse_msg_file(int charset_code)
624{
625   FILE *fh;
626   unsigned char header[20];
[d5bd3a7]627   int i;   
[db75e18]628   unsigned len;
[55de792]629   unsigned char *p;
[b164c18]630   char *fnm, *s;
[d5bd3a7]631   int n;
[cb3d1e2]632
[55de792]633#ifdef DEBUG
634   fprintf(stderr, "parse_msg_file(%d)\n", charset_code);
635#endif
[db75e18]636
[d5bd3a7]637   /* sort out messages we need to print if we can't open the message file */
638   dontextract = parse_msgs(N_DONTEXTRACTMSGS, dontextractmsgs, charset_code);
639
[0a3c5fa]640   fnm = osstrdup(msg_lang);
[b164c18]641   /* trim off charset from stuff like "de_DE.iso8859_1" */
642   s = strchr(fnm, '.');
643   if (s) *s = '\0';
[a2f9d5c]644
[b164c18]645   fh = fopenWithPthAndExt(pth_cfg_files, fnm, EXT_SVX_MSG, "rb", NULL);
[db75e18]646
647   if (!fh) {
[fd5f670]648      /* e.g. if 'en_GB' is unknown, see if we know 'en' */
649      if (strlen(fnm) > 3 && fnm[2] == '_') {
[b164c18]650         fnm[2] = '\0';
651         fh = fopenWithPthAndExt(pth_cfg_files, fnm, EXT_SVX_MSG, "rb", NULL);
[fd5f670]652         if (!fh) fnm[2] = '_'; /* for error reporting */
[db75e18]653      }
[48e4121]654   }
[db75e18]655
656   if (!fh) {
[b07f165]657      fatalerror(/*Can't open message file `%s' using path `%s'*/1000,
658                 fnm, pth_cfg_files);
[4432f2e]659   }
[db75e18]660
661   if (fread(header, 1, 20, fh) < 20 ||
662       memcmp(header, "Svx\nMsg\r\n\xfe\xff", 12) != 0) {
[b07f165]663      fatalerror(/*Problem with message file `%s'*/1001, fnm);
[db75e18]664   }
665
[b07f165]666   if (header[12] != 0)
667      fatalerror(/*I don't understand this message file version*/1002);
[db75e18]668
[d5bd3a7]669   n = (header[14] << 8) | header[15];
[db75e18]670
671   len = 0;
672   for (i = 16; i < 20; i++) len = (len << 8) | header[i];
673
[0a3c5fa]674   p = osmalloc(len);
[b07f165]675   if (fread(p, 1, len, fh) < len)
676      fatalerror(/*Message file truncated?*/1003);
[2163157]677
[a420b49]678   fclose(fh);
[db75e18]679
[55de792]680#ifdef DEBUG
[d5bd3a7]681   fprintf(stderr, "fnm = `%s', n = %d, len = %d\n", fnm, n, len);
[55de792]682#endif
[b164c18]683   osfree(fnm);
[55de792]684
[d5bd3a7]685   msg_array = parse_msgs(n, p, charset_code);
686   num_msgs = n;
[4432f2e]687}
688
[f2a6ce4]689const char *
690msg_cfgpth(void)
691{
692   return pth_cfg_files;
693}
694
[bdfe97f]695const char *
696msg_appname(void)
697{
698   return appname_copy;
699}
700
[f2a6ce4]701void
[bdfe97f]702msg_init(char * const *argv)
[db75e18]703{
704   char *p;
[bdfe97f]705   ASSERT(argv);
[db75e18]706
707#ifdef HAVE_SIGNAL
708   init_signals();
709#endif
[bdfe97f]710   /* Point to argv[0] itself so we report a more helpful error if the
711    * code to work out the clean appname generates a signal */
712   appname_copy = argv[0];
[0a3c5fa]713#if (OS == UNIX)
714   /* use name as-is on Unix - programs run from path get name as supplied */
[bdfe97f]715   appname_copy = osstrdup(argv[0]);
[0a3c5fa]716#else
717   /* use the lower-cased leafname on other platforms */
[bdfe97f]718   appname_copy = p = leaf_from_fnm(argv[0]);
[4bfc8a7]719   while (*p) {
720      *p = tolower(*p);
721      p++;
722   }
[0a3c5fa]723#endif
[db75e18]724
[bdfe97f]725   /* shortcut --version so you can check the version number when the correct
726    * message file can't be found... */
727   if (argv[1] && strcmp(argv[1], "--version") == 0) {
728      cmdline_version();
729      exit(0);
730   }
731
[db75e18]732   /* Look for env. var. "SURVEXHOME" or the like */
733   p = getenv("SURVEXHOME");
734   if (p && *p) {
[0a3c5fa]735      pth_cfg_files = osstrdup(p);
[18f4759]736#if (OS==UNIX) && defined(DATADIR) && defined(PACKAGE)
[a420b49]737   } else {
738      /* under Unix, we compile in the configured path */
[18f4759]739      pth_cfg_files = DATADIR "/" PACKAGE;
[a420b49]740#else
[bdfe97f]741   } else if (argv[0]) {
[db75e18]742      /* else try the path on argv[0] */
[bdfe97f]743      pth_cfg_files = path_from_fnm(argv[0]);
[a420b49]744#endif
[db75e18]745   }
746
[b164c18]747   msg_lang = getenv("SURVEXLANG");
748#ifdef DEBUG
[74044b7]749   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang, msg_lang?msg_lang:"(null)");
[b164c18]750#endif
751
752   if (!msg_lang || !*msg_lang) {
753      msg_lang = getenv("LANG");
[74044b7]754      if (!msg_lang || !*msg_lang) {
755#if (OS==WIN32)
756         LCID locid;
757#endif
[37fca9b]758#ifdef DEFAULTLANG
[d5bd3a7]759         msg_lang = STRING(DEFAULTLANG);
[37fca9b]760#else
761         msg_lang = "en";
762#endif
[74044b7]763#if (OS==WIN32)
764         locid = GetUserDefaultLCID();
765         if (locid) {
766            WORD langid = LANGIDFROMLCID(locid);
767            switch (PRIMARYLANGID(langid)) {
[761c5f9]768/* older mingw compilers don't seem to supply this value */
769#ifndef LANG_CATALAN
770# define LANG_CATALAN 0x03
771#endif
[74044b7]772             case LANG_CATALAN:
773               msg_lang = "ca";
774               break;
775             case LANG_ENGLISH:
776               if (SUBLANGID(langid) == SUBLANG_ENGLISH_US)
777                  msg_lang = "en_US";
778               else
779                  msg_lang = "en";
780               break;
781             case LANG_FRENCH:
782               msg_lang = "fr";
783               break;
784             case LANG_GERMAN:
785               switch (SUBLANGID(langid)) {
786                case SUBLANG_GERMAN_SWISS:
787                  msg_lang = "de_CH";
788                  break;
789                case SUBLANG_GERMAN:
790                  msg_lang = "de_DE";
791                  break;
792                default:
793                  msg_lang = "de";
794               }
795               break;
796             case LANG_ITALIAN:
797               msg_lang = "it";
798               break;
799             case LANG_PORTUGUESE:
800               if (SUBLANGID(langid) == SUBLANG_PORTUGUESE_BRAZILIAN)
801                  msg_lang = "pt_BR";
802               else
803                  msg_lang = "pt";
804               break;
805             case LANG_SPANISH:
806               msg_lang = "es";
807               break;
808            }
809         }
[44740e7]810#elif (OS==RISCOS)
811         switch (xterritory_number()) {
812          case 1: /* UK */
813          case 2: /* Master */
814          case 3: /* Compact */
815          case 17: /* Canada1 */
816          case 19: /* Canada */
817          case 22: /* Ireland */
818            msg_lang = "en";
819            break;
820          case 4: /* Italy */
821            msg_lang = "it";
822            break;
[1b92879]823          case 5: /* Spain (or ca) */
[44740e7]824          case 27: /* Mexico */
[1b92879]825          case 28: /* LatinAm (or pt_BR) */
826            msg_lang = "es";
[44740e7]827            break;
828          case 6: /* France */
829          case 18: /* Canada2 */
830            msg_lang = "fr";
831            break;
832          case 7: /* Germany */
833            msg_lang = "de_DE";
834            break;
835          case 8: /* Portugal */
836            msg_lang = "pt";
837            break;
838          case 48: /* USA */
839            msg_lang = "en_US";
840            break;
841#if 0
842          case 9: /* Esperanto */
843          case 10: /* Greece */
844          case 11: /* Sweden */
845          case 12: /* Finland */
846          case 13: /* Unused */
847          case 14: /* Denmark */
848          case 15: /* Norway */
849          case 16: /* Iceland */
850          case 20: /* Turkey */
851          case 21: /* Arabic */
852          case 23: /* Hong Kong */
853          case 24: /* Russia */
854          case 25: /* Russia2 */
855          case 26: /* Israel */
856#endif     
[84faf78b]857         }
[1b92879]858#elif (OS==MSDOS)
859           {
860              union REGS in, out;
861              in.x.ax = 0x3800; /* get current country info */
862              in.x.dx = 0;
863              intdos(&in, &out);
864              if (!out.x.cflag) {
865                 /* List of country codes taken from:
866                  * http://www.delorie.com/djgpp/doc/rbinter/it/00/14.html */
867                 /* The mappings here are guesses at best in most cases.
868                  * In a lot of cases we pick a language because we have
869                  * a translation in it, rather than because it's the most
870                  * widely used or understood in that country. */
871                 /* Improvements welcome */
872                 switch (out.x.bx) {
873                  case 1: /* United States */
874                  case 670: /* Saipan / N. Mariana Island */
875                  case 671: /* Guam */
876                  case 680: /* Palau */
877                  case 684: /* American Samoa */
878                  case 691: /* Micronesia */
879                  case 692: /* Marshall Islands */
880                    msg_lang = "en_US";
881                    break;
882                  case 4: /* Canada (English) */
883                  case 27: /* South Africa */
884                  case 44: /* United Kingdom */
885                  case 61: /* International English / Australia */
886                  case 64: /* New Zealand */
887                  case 99: /* Asia (English) */
888                  case 220: /* Gambia */
889                  case 231: /* Liberia */
890                  case 232: /* Sierra Leone */
891                  case 233: /* Ghana */
892                  case 254: /* Kenya */
893                  case 256: /* Uganda */
894                  case 260: /* Zambia */
895                  case 263: /* Zimbabwe */
896                  case 264: /* Namibia */
897                  case 267: /* Botswana */
898                  case 268: /* Swaziland */
899                  case 290: /* St. Helena */
900                  case 297: /* Aruba */
901                  case 350: /* Gibraltar */
902                  case 353: /* Ireland */
903                  case 356: /* Malta */
904                  case 500: /* Falkland Islands */
905                  case 501: /* Belize */
906                  case 592: /* Guyana */
907                  case 672: /* Norfolk Island (Australia) / Christmas Island/Cocos Islands / Antartica */
908                  case 673: /* Brunei Darussalam */
909                  case 674: /* Nauru */
910                  case 675: /* Papua New Guinea */
911                  case 676: /* Tonga Islands */
912                  case 677: /* Solomon Islands */
913                  case 679: /* Fiji */
914                  case 682: /* Cook Islands */
915                  case 683: /* Niue */
916                  case 685: /* Western Samoa */
917                  case 686: /* Kiribati */
918                    /* I believe only some of these are English speaking... */
919                  case 809: /* Antigua and Barbuda / Anguilla / Bahamas / Barbados / Bermuda
920                             British Virgin Islands / Cayman Islands / Dominica
921                             Dominican Republic / Grenada / Jamaica / Montserra
922                             St. Kitts and Nevis / St. Lucia / St. Vincent and Grenadines
923                             Trinidad and Tobago / Turks and Caicos */
924                    msg_lang = "en";
925                    break;
926                  case 2: /* Canadian-French */
927                  case 32: /* Belgium */ /* maybe */
928                  case 33: /* France */
929                  case 213: /* Algeria */
930                  case 216: /* Tunisia */
931                  case 221: /* Senegal */
932                  case 223: /* Mali */
933                  case 225: /* Ivory Coast */
934                  case 226: /* Burkina Faso */
935                  case 227: /* Niger */
936                  case 228: /* Togo */
937                  case 229: /* Benin */
938                  case 230: /* Mauritius */
939                  case 235: /* Chad */
940                  case 236: /* Central African Republic */
941                  case 237: /* Cameroon */
942                  case 241: /* Gabon */
943                  case 242: /* Congo */
944                  case 250: /* Rwhanda */
945                  case 253: /* Djibouti */
946                  case 257: /* Burundi */
947                  case 261: /* Madagascar */
948                  case 262: /* Reunion Island */
949                  case 269: /* Comoros */
950                  case 270: /* Mayotte */
951                  case 352: /* Luxembourg (or de or ...) */
952                  case 508: /* St. Pierre and Miquelon */
953                  case 509: /* Haiti */
954                  case 590: /* Guadeloupe */
955                  case 594: /* French Guiana */
956                  case 596: /* Martinique / French Antilles */
957                  case 678: /* Vanuatu */
958                  case 681: /* Wallis & Futuna */
959                  case 687: /* New Caledonia */
960                  case 689: /* French Polynesia */
961                  case 961: /* Lebanon */
962                    msg_lang = "fr";
963                    break;
964                  case 3: /* Latin America */
965                  case 34: /* Spain */
966                  case 51: /* Peru */
967                  case 52: /* Mexico */
968                  case 53: /* Cuba */
969                  case 54: /* Argentina */
970                  case 56: /* Chile */
971                  case 57: /* Columbia */
972                  case 58: /* Venezuela */
973                  case 63: /* Philippines */
974                  case 240: /* Equatorial Guinea */
975                  case 502: /* Guatemala */
976                  case 503: /* El Salvador */
977                  case 504: /* Honduras */
978                  case 505: /* Nicraragua */
979                  case 506: /* Costa Rica */
980                  case 507: /* Panama */
981                  case 591: /* Bolivia */
982                  case 593: /* Ecuador */
983                  case 595: /* Paraguay */
984                  case 598: /* Uruguay */
985                    msg_lang = "es";
986                    break;
987                  case 39: /* Italy / San Marino / Vatican City */
988                    msg_lang = "it";
989                    break;
990                  case 41: /* Switzerland / Liechtenstein */ /* or fr or ... */
991                    msg_lang = "de_CH";
992                    break;
993                  case 43: /* Austria (DR DOS 5.0) */
994                    msg_lang = "de";
995                    break;
996                  case 49: /* Germany */
997                    msg_lang = "de_DE";
998                    break;
999                  case 55: /* Brazil (not supported by DR DOS 5.0) */
1000                    msg_lang = "pt_BR";
1001                    break;
1002                  case 238: /* Cape Verde Islands */
1003                  case 244: /* Angola */
1004                  case 245: /* Guinea-Bissau */
1005                  case 259: /* Mozambique */
1006                  case 351: /* Portugal */
1007                    msg_lang = "pt";
1008                    break;
1009#if 0
1010                  case 7: /* Russia */
1011                  case 20: /* Egypt */
1012                  case 30: /* Greece */
1013                  case 31: /* Netherlands */
1014                  case 35: /* Bulgaria??? */
1015                  case 36: /* Hungary (not supported by DR DOS 5.0) */
1016                  case 38: /* Yugoslavia (not supported by DR DOS 5.0) -- obsolete */
1017                  case 40: /* Romania */
1018                  case 42: /* Czechoslovakia / Tjekia / Slovakia (not supported by DR DOS 5.0) */
1019                  case 45: /* Denmark */
1020                  case 46: /* Sweden */
1021                  case 47: /* Norway */
1022                  case 48: /* Poland (not supported by DR DOS 5.0) */
1023                  case 60: /* Malaysia */
1024                  case 62: /* Indonesia / East Timor */
1025                  case 65: /* Singapore */
1026                  case 66: /* Thailand (or Taiwan???) */
1027                  case 81: /* Japan (DR DOS 5.0, MS-DOS 5.0+) */
1028                  case 82: /* South Korea (DR DOS 5.0) */
1029                  case 84: /* Vietnam */
1030                  case 86: /* China (MS-DOS 5.0+) */
1031                  case 88: /* Taiwan (MS-DOS 5.0+) */
1032                  case 90: /* Turkey (MS-DOS 5.0+) */
1033                  case 91: /* India */
1034                  case 92: /* Pakistan */
1035                  case 93: /* Afghanistan */
1036                  case 94: /* Sri Lanka */
1037                  case 98: /* Iran */
1038                  case 102: /* ??? (Hebrew MS-DOS 5.0) */
1039                  case 112: /* Belarus */
1040                  case 200: /* Thailand (PC DOS 6.1+) (reported as 01due to a bug in PC DOS COUNTRY.SYS) */
1041                  case 212: /* Morocco */
1042                  case 218: /* Libya */
1043                  case 222: /* Maruitania */
1044                  case 224: /* African Guinea */
1045                  case 234: /* Nigeria */
1046                  case 239: /* Sao Tome and Principe */
1047                  case 243: /* Zaire */
1048                  case 246: /* Diego Garcia */
1049                  case 247: /* Ascension Isle */
1050                  case 248: /* Seychelles */
1051                  case 249: /* Sudan */
1052                  case 251: /* Ethiopia */
1053                  case 252: /* Somalia */
1054                  case 255: /* Tanzania */
1055                  case 265: /* Malawi */
1056                  case 266: /* Lesotho */
1057                  case 298: /* Faroe Islands */
1058                  case 299: /* Greenland */
1059                  case 354: /* Iceland */
1060                  case 355: /* Albania */
1061                  case 357: /* Cyprus */
1062                  case 358: /* Finland */
1063                  case 359: /* Bulgaria */
1064                  case 370: /* Lithuania (reported as 372 due to a bug in MS-DOS COUNTRY.SYS) */
1065                  case 371: /* Latvia (reported as 372 due to a bug in MS-DOS COUNTRY.SYS) */
1066                  case 372: /* Estonia */
1067                  case 373: /* Moldova */
1068                  case 375: /* ??? (MS-DOS 7.10 / Windows98) */
1069                  case 380: /* Ukraine */
1070                  case 381: /* Serbia / Montenegro */
1071                  case 384: /* Croatia */
1072                  case 385: /* Croatia (PC DOS 7+) */
1073                  case 386: /* Slovenia */
1074                  case 387: /* Bosnia-Herzegovina (Latin) */
1075                  case 388: /* Bosnia-Herzegovina (Cyrillic) (PC DOS 7+) (reported as 381 due to a bug in PC DOS COUNTRY.SYS) */
1076                  case 389: /* FYR Macedonia */
1077                  case 421: /* Czech Republic / Tjekia (PC DOS 7+) */
1078                  case 422: /* Slovakia (reported as 421 due to a bug in COUNTRY.SYS) */
1079                  case 597: /* Suriname (nl) */
1080                  case 599: /* Netherland Antilles (nl) */
1081                  case 666: /* Russia??? (PTS-DOS 6.51 KEYB) */
1082                  case 667: /* Poland??? (PTS-DOS 6.51 KEYB) */
1083                  case 668: /* Poland??? (Slavic???) (PTS-DOS 6.51 KEYB) */
1084                  case 688: /* Tuvalu */
1085                  case 690: /* Tokealu */
1086                  case 711: /* ??? (currency = EA$, code pages 437,737,850,852,855,857) */
1087                  case 785: /* Arabic (Middle East/Saudi Arabia/etc.) */
1088                  case 804: /* Ukraine */
1089                  case 850: /* North Korea */
1090                  case 852: /* Hong Kong */
1091                  case 853: /* Macao */
1092                  case 855: /* Cambodia */
1093                  case 856: /* Laos */
1094                  case 880: /* Bangladesh */
1095                  case 886: /* Taiwan (MS-DOS 6.22+) */
1096                  case 960: /* Maldives */
1097                  case 962: /* Jordan */
1098                  case 963: /* Syria / Syrian Arab Republic */
1099                  case 964: /* Iraq */
1100                  case 965: /* Kuwait */
1101                  case 966: /* Saudi Arabia */
1102                  case 967: /* Yemen */
1103                  case 968: /* Oman */
1104                  case 969: /* Yemen??? (Arabic MS-DOS 5.0) */
1105                  case 971: /* United Arab Emirates */
1106                  case 972: /* Israel (Hebrew) (DR DOS 5.0,MS-DOS 5.0+) */
1107                  case 973: /* Bahrain */
1108                  case 974: /* Qatar */
1109                  case 975: /* Bhutan */
1110                  case 976: /* Mongolia */
1111                  case 977: /* Nepal */
1112                  case 995: /* Myanmar (Burma) */
[652ef1b]1113#endif
[6e717ae]1114                 }
1115              }
1116           }
[84faf78b]1117#endif
[74044b7]1118      }
[b164c18]1119   }
1120#ifdef DEBUG
1121   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang, msg_lang?msg_lang:"(null)");
1122#endif
1123
1124   /* On Mandrake LANG defaults to C */
1125   if (strcmp(msg_lang, "C") == 0) msg_lang = "en";
1126
[0a3c5fa]1127   msg_lang = osstrdup(msg_lang);
[b164c18]1128
1129   /* Convert en-us to en_US, etc */
1130   p = strchr(msg_lang, '-');
1131   if (p) {
1132      *p++ = '_';
1133      while (*p) {
1134         *p = toupper(*p);
1135         p++;
1136      }
1137   }
1138
1139   p = strchr(msg_lang, '_');
1140   if (p) {
1141      *p = '\0';
[0a3c5fa]1142      msg_lang2 = osstrdup(msg_lang);
[b164c18]1143      *p = '_';
1144   }
1145
1146#ifdef LC_MESSAGES
1147   /* try to setlocale() appropriately too */
1148   if (!setlocale(LC_MESSAGES, msg_lang)) {
1149      if (msg_lang2) setlocale(LC_MESSAGES, msg_lang2);
1150   }
1151#endif
1152
[db75e18]1153   select_charset(default_charset());
1154}
1155
[d5bd3a7]1156/* Message may be overwritten by next call
[bd1913f]1157 * (but not in current implementation) */
1158const char *
[db75e18]1159msg(int en)
1160{
[eee67ab]1161   /* NB can't use ASSERT here! */
1162   static char badbuf[256];
[d5bd3a7]1163   if (en >= 1000 && en < 1000 + N_DONTEXTRACTMSGS)
[b07f165]1164      return dontextract[en - 1000];
[55de792]1165   if (!msg_array) {
[eee67ab]1166      if (en != 1)  {
1167         sprintf(badbuf, "Message %d requested before msg_array initialised\n", en);
1168         return badbuf;
1169      }
[d5bd3a7]1170      /* this should be the only other message which can be requested before
[a420b49]1171       * the message file is opened and read... */
[d5bd3a7]1172      if (!dontextract) return "Out of memory (couldn't find %lu bytes).";
1173      return dontextract[4];
[db75e18]1174   }
1175
[eee67ab]1176   if (en < 0 || en >= num_msgs) {
1177      sprintf(badbuf, "Message %d out of range\n", en);
1178      return badbuf;
1179   }
[db75e18]1180
[90123e8]1181   if (en == 0) {
1182      char *p = msg_array[0];
1183      if (!*p) p = "(C)";
1184      return p;
1185   }
1186
[55de792]1187   return msg_array[en];
[db75e18]1188}
1189
1190/* returns persistent copy of message */
[bd1913f]1191const char *
[db75e18]1192msgPerm(int en)
1193{
1194   return msg(en);
1195}
1196
1197void
1198v_report(int severity, const char *fnm, int line, int en, va_list ap)
1199{
[1f316f3]1200#ifdef AVEN
[2e18955]1201   aven_v_report(severity, fnm, line, en, ap);
[2163157]1202#else
[db75e18]1203   if (fnm) {
1204      fputs(fnm, STDERR);
1205      if (line) fprintf(STDERR, ":%d", line);
1206   } else {
[a4140e9]1207      fputs(appname_copy, STDERR);
[cb3d1e2]1208   }
[db75e18]1209   fputs(": ", STDERR);
1210
1211   if (severity == 0) {
1212      fputs(msg(/*warning*/4), STDERR);
1213      fputs(": ", STDERR);
1214   }
1215
1216   vfprintf(STDERR, msg(en), ap);
1217   fputnl(STDERR);
[1f316f3]1218#endif
[cb3d1e2]1219
[db75e18]1220   switch (severity) {
1221    case 0:
[25ab06b]1222      msg_warnings++;
[db75e18]1223      break;
1224    case 1:
[25ab06b]1225      msg_errors++;
1226      if (msg_errors == 50)
[db75e18]1227         fatalerror_in_file(fnm, 0, /*Too many errors - giving up*/19);
1228      break;
1229    case 2:
1230      exit(EXIT_FAILURE);
1231   }
1232}
1233
1234void
1235warning(int en, ...)
1236{
1237   va_list ap;
1238   va_start(ap, en);
1239   v_report(0, NULL, 0, en, ap);
1240   va_end(ap);
1241}
1242
1243void
1244error(int en, ...)
1245{
1246   va_list ap;
1247   va_start(ap, en);
1248   v_report(1, NULL, 0, en, ap);
1249   va_end(ap);
1250}
1251
1252void
1253fatalerror(int en, ...)
1254{
1255   va_list ap;
1256   va_start(ap, en);
1257   v_report(2, NULL, 0, en, ap);
1258   va_end(ap);
1259}
1260
1261void
1262warning_in_file(const char *fnm, int line, int en, ...)
1263{
1264   va_list ap;
1265   va_start(ap, en);
1266   v_report(0, fnm, line, en, ap);
1267   va_end(ap);
1268}
1269
1270void
1271error_in_file(const char *fnm, int line, int en, ...)
1272{
1273   va_list ap;
1274   va_start(ap, en);
1275   v_report(1, fnm, line, en, ap);
1276   va_end(ap);
1277}
1278
1279void
1280fatalerror_in_file(const char *fnm, int line, int en, ...)
1281{
1282   va_list ap;
1283   va_start(ap, en);
1284   v_report(2, fnm, line, en, ap);
1285   va_end(ap);
1286}
1287
1288/* Code to support switching character set at runtime (e.g. for a printer
1289 * driver to support different character sets on screen and on the printer)
1290 */
1291typedef struct charset_li {
1292   struct charset_li *next;
1293   int code;
[55de792]1294   char **msg_array;
[db75e18]1295} charset_li;
1296
1297static charset_li *charset_head = NULL;
1298
1299static int charset = CHARSET_BAD;
1300
1301int
1302select_charset(int charset_code)
1303{
1304   int old_charset = charset;
1305   charset_li *p;
1306
[55de792]1307#ifdef DEBUG
[bd1913f]1308   fprintf(stderr, "select_charset(%d), old charset = %d\n", charset_code,
1309           charset);
[55de792]1310#endif
[cb3d1e2]1311
[db75e18]1312   charset = charset_code;
1313
1314   /* check if we've already parsed messages for new charset */
1315   for (p = charset_head; p; p = p->next) {
[55de792]1316#ifdef DEBUG
1317      printf("%p: code %d msg_array %p\n", p, p->code, p->msg_array);
1318#endif
[db75e18]1319      if (p->code == charset) {
[55de792]1320         msg_array = p->msg_array;
[db75e18]1321         return old_charset;
1322      }
1323   }
1324
1325   /* nope, got to reparse message file */
1326   parse_msg_file(charset_code);
1327
1328   /* add to list */
1329   p = osnew(charset_li);
1330   p->code = charset;
[55de792]1331   p->msg_array = msg_array;
[db75e18]1332   p->next = charset_head;
1333   charset_head = p;
1334
1335   return old_charset;
1336}
Note: See TracBrowser for help on using the repository browser.