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

RELEASE/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 6d30f38 was 6d30f38, checked in by Olly Betts <olly@…>, 22 years ago

defined WIN32_LEAN_AND_MEAN to trim the worst of the bloat.

git-svn-id: file:///home/survex-svn/survex/branches/survex-1_1@2354 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

  • Property mode set to 100644
File size: 47.5 KB
RevLine 
[fd5f670]1/* message.c
[db75e18]2 * Fairly general purpose message and error routines
[f529444]3 * Copyright (C) 1993-2002 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
[cd620d5]42# include "aven.h"
[a4140e9]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)
[6d30f38]56# define WIN32_LEAN_AND_MEAN
[cd620d5]57# include <windows.h>
[1b92879]58#elif (OS==MSDOS)
[6d30f38]59# include <dos.h>
[cd620d5]60# ifdef __DJGPP__
61#  include <dpmi.h>
[106af12]62#  include <go32.h>
63#  include <sys/movedata.h>
[cd620d5]64# endif
[1b92879]65#elif (OS==RISCOS)
[cd620d5]66# include "oslib/wimpreadsy.h"
[d245d71]67# include "oslib/territory.h"
[2163157]68#endif
69
[60f7018]70/* For funcs which want to be immune from messing around with different
71 * calling conventions */
72#ifndef CDECL
[2ca296b]73# define CDECL
[60f7018]74#endif
75
[25ab06b]76int msg_warnings = 0; /* keep track of how many warnings we've given */
77int msg_errors = 0;   /* and how many (non-fatal) errors */
[60f7018]78
[a4140e9]79/* in case osmalloc() fails before appname_copy is set up */
80static const char *appname_copy = "anonymous program";
[60f7018]81
82/* error code for failed osmalloc and osrealloc calls */
[db75e18]83static void
84outofmem(OSSIZE_T size)
85{
[bd1913f]86   fatalerror(/*Out of memory (couldn't find %lu bytes).*/1,
[421b7d2]87              (unsigned long)size);
[60f7018]88}
89
[a420b49]90#ifdef TOMBSTONES
91#define TOMBSTONE_SIZE 16
[bd1913f]92static const char tombstone[TOMBSTONE_SIZE] = "012345\xfftombstone";
[a420b49]93#endif
94
[60f7018]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 */
[bd1913f]98void FAR *
[db75e18]99osmalloc(OSSIZE_T size)
100{
[60f7018]101   void FAR *p;
[a420b49]102#ifdef TOMBSTONES
103   size += TOMBSTONE_SIZE * 2;
104   p = malloc(size);
105#else
[db75e18]106   p = xosmalloc(size);
[a420b49]107#endif
[2ca296b]108   if (p == NULL) outofmem(size);
[a420b49]109#ifdef TOMBSTONES
[bd1913f]110   printf("osmalloc truep=%p truesize=%d\n", p, size);
[a420b49]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
[60f7018]116   return p;
117}
118
119/* realloc with error catching if it fails. */
[bd1913f]120void FAR *
[db75e18]121osrealloc(void *p, OSSIZE_T size)
122{
[a420b49]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;
[bd1913f]132      printf("osrealloc (in truep=%p truesize=%d)\n", p, true_size);
[a420b49]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!",
[cb3d1e2]136                p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]137      }
138      if (memcmp(p + true_size - TOMBSTONE_SIZE, tombstone,
139                 TOMBSTONE_SIZE) != 0) {
140         printf("end tombstone for block %p, size %d corrupted!",
[cb3d1e2]141                p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]142      }
143      p = realloc(p, size);
144      if (p == NULL) outofmem(size);
[bd1913f]145      printf("osrealloc truep=%p truesize=%d\n", p, size);
[a420b49]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   }
[2ca296b]154   if (p == NULL) outofmem(size);
[60f7018]155   return p;
156}
157
[b2c945f]158char FAR *
[db75e18]159osstrdup(const char *str)
160{
[60f7018]161   char *p;
[db75e18]162   OSSIZE_T len;
163   len = strlen(str) + 1;
[0a3c5fa]164   p = osmalloc(len);
[db75e18]165   memcpy(p, str, len);
[60f7018]166   return p;
167}
168
[a420b49]169/* osfree is usually just a macro in osalloc.h */
170#ifdef TOMBSTONES
[bd1913f]171void
[a420b49]172osfree(void *p)
173{
174   int true_size;
175   if (!p) return;
176   p -= TOMBSTONE_SIZE;
177   true_size = *(size_t *)p;
[bd1913f]178   printf("osfree truep=%p truesize=%d\n", p, true_size);
[a420b49]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!",
[cb3d1e2]182             p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]183   }
184   if (memcmp(p + true_size - TOMBSTONE_SIZE, tombstone,
185              TOMBSTONE_SIZE) != 0) {
186      printf("end tombstone for block %p, size %d corrupted!",
[cb3d1e2]187             p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]188   }
189   free(p);
190}
191#endif
[60f7018]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
[2ca296b]200# define RETSIGTYPE void
[60f7018]201#endif
202
[bd1913f]203static CDECL RETSIGTYPE FAR
204report_sig(int sig)
205{
[db75e18]206   sigReceived = sig;
[2ca296b]207   longjmp(jmpbufSignal, 1);
[60f7018]208}
209
[db75e18]210static void
211init_signals(void)
212{
[60f7018]213   int en;
214   if (!setjmp(jmpbufSignal)) {
[d8331b0]215#if 0 /* disable these to get a core dump */
[db75e18]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
[60f7018]221# ifdef SIGSTAK /* only on RISC OS AFAIK */
[db75e18]222      signal(SIGSTAK, report_sig); /* stack overflow */
[60f7018]223# endif
224      return;
225   }
[db75e18]226
[60f7018]227   switch (sigReceived) {
[bd1913f]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;
[60f7018]232# ifdef SIGSTAK
[bd1913f]233      case SIGSTAK: en = /*Stack overflow*/96; break;
[60f7018]234# endif
[bd1913f]235      default:      en = /*Unknown signal received*/97; break;
[60f7018]236   }
[db75e18]237   fputsnl(msg(en), STDERR);
[ea816ec]238
[c0a9908]239   /* Any of the signals we catch indicates a bug */
240   fatalerror(/*Bug in program detected! Please report this to the authors*/11);
[db75e18]241
[60f7018]242   exit(EXIT_FAILURE);
243}
244#endif
245
[bd1913f]246static int
247default_charset(void)
248{
[8769f9f]249#if (OS==RISCOS)
[ea816ec]250   /* RISCOS 3.1 and above CHARSET_RISCOS31 (ISO_8859_1 + extras in 128-159)
251    * RISCOS < 3.1 is ISO_8859_1 */
[2163157]252   int version;
[ea816ec]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;
[2163157]260
[2ca296b]261   return CHARSET_RISCOS31;
[60f7018]262#elif (OS==MSDOS)
[4ad82e9]263#ifdef __DJGPP__
[106af12]264   __dpmi_regs r;
265   r.x.ax = 0x6501;
266   r.x.bx = 0xffff;
267   r.x.dx = 0xffff;
268   /* Use DJGPP's transfer buffer (which is at least 2K) */
269   r.x.es = __tb >> 4;
270   r.x.di = __tb & 0x0f;
271   r.x.cx = 2048;
272   /* bit 1 is the carry flag */
[7993643]273   if (__dpmi_int(0x21, &r) != -1 && !(r.x.flags & 1)) {
[106af12]274      unsigned short p;
275      dosmemget(__tb + 5, 2, &p);
[4ad82e9]276#else
277   union REGS r;
278   struct SREGS s = { 0 };
[1e275f0]279
[4ad82e9]280   unsigned char buf[48];
281   r.x.ax = 0x6501;
282   r.x.bx = 0xffff;
283   r.x.dx = 0xffff;
284   s.es = FP_SEG(buf);
285   r.x.di = FP_OFF(buf);
286   r.x.cx = 48;
287   intdosx(&r, &r, &s);
288   if (!r.x.cflag) {
289      unsigned short p = buf[5] | (buf[6] << 8);
290#endif
[106af12]291      if (p == 437) return CHARSET_DOSCP437;
292      if (p == 850) return CHARSET_DOSCP850;
[f0a0b05]293      if (p == 912) return CHARSET_ISO_8859_2;
[106af12]294   }
295   return CHARSET_USASCII;
[a4140e9]296#elif (OS==WIN32)
[d5bd3a7]297# ifdef AVEN
[31ccf72]298#  define CODEPAGE GetACP()
[d5bd3a7]299# else
[31ccf72]300#  define CODEPAGE GetConsoleOutputCP()
301# endif
302   switch (CODEPAGE) {
[dc639a8]303    case 1252: return CHARSET_WINCP1252;
304    case 850: return CHARSET_DOSCP850;
[d5bd3a7]305   }
306   return CHARSET_USASCII;
[a4140e9]307#elif (OS==UNIX)
308#if defined(XCAVEROT) || defined(AVEN)
[8769f9f]309   return CHARSET_ISO_8859_1;
[a4140e9]310#else
[8c15864]311   const char *p = getenv("LC_ALL");
[31ccf72]312   if (p == NULL || p[0] == '\0') {
313      p = getenv("LC_CTYPE");
314      if (p == NULL || p[0] == '\0') {
315         p = msg_lang;
316      }
317   }
318
319   if (p) {
320      char *q = strchr(p, '.');
321      if (q) p = q + 1;
322   }
323
[a4140e9]324   if (p) {
[8c15864]325      const char *chset = p;
[a4140e9]326      size_t name_len;
327
328      while (*p != '\0' && *p != '@') p++;
329
330      name_len = p - chset;
331
332      if (name_len) {
333         int only_digit = 1;
334         size_t cnt;
[421b7d2]335
[a4140e9]336         for (cnt = 0; cnt < name_len; ++cnt)
[abd126e]337            if (isalpha((unsigned char)chset[cnt])) {
[a4140e9]338               only_digit = 0;
339               break;
340            }
341
342         if (only_digit) goto iso;
[421b7d2]343
[a4140e9]344         switch (tolower(chset[0])) {
345          case 'i':
346            if (tolower(chset[1]) == 's' && tolower(chset[2]) == 'o') {
347               chset += 3;
348               iso:
349               if (strncmp(chset, "8859", 4) == 0) {
350                  chset += 4;
[abd126e]351                  while (chset < p && *chset && !isdigit((unsigned char)*chset))
352                     chset++;
[a4140e9]353                  switch (atoi(chset)) {
354                   case 1: return CHARSET_ISO_8859_1;
[f0a0b05]355                   case 2: return CHARSET_ISO_8859_2;
[f8e03f3]356                   case 15: return CHARSET_ISO_8859_15;
[421b7d2]357                   default: return CHARSET_USASCII;
[a4140e9]358                  }
359               }
360            }
361            break;
362          case 'u':
363            if (tolower(chset[1]) == 't' && tolower(chset[2]) == 'f') {
364               chset += 3;
[abd126e]365               while (chset < p && *chset && !isdigit((unsigned char)*chset))
366                  chset++;
[a4140e9]367               switch (atoi(chset)) {
368                case 8: return CHARSET_UTF8;
369                default: return CHARSET_USASCII;
370               }
371            }
372         }
373      }
374   }
375   return CHARSET_USASCII;
376#endif
377#else
378# error Do not know operating system 'OS'
[60f7018]379#endif
380}
381
[a4140e9]382/* It seems that Swedish and maybe some other scandanavian languages don't
383 * transliterate &auml; to ae - but it seems there may be conflicting views
384 * on this...
385 */
386#define umlaut_to_e() 1
387
[1b92879]388/* values <= 127 already dealt with */
[db75e18]389static int
[55de792]390add_unicode(int charset, unsigned char *p, int value)
[db75e18]391{
[55de792]392#ifdef DEBUG
393   fprintf(stderr, "add_unicode(%d, %p, %d)\n", charset, p, value);
394#endif
[4432f2e]395   if (value == 0) return 0;
[48e4121]396   switch (charset) {
[db75e18]397   case CHARSET_USASCII:
[6a4871e]398      if (value < 0x80) {
[48e4121]399         *p = value;
400         return 1;
401      }
402      break;
[db75e18]403   case CHARSET_ISO_8859_1:
[6a4871e]404      if (value < 0x100) {
[48e4121]405         *p = value;
406         return 1;
407      }
[ea816ec]408      break;
[f0a0b05]409   case CHARSET_ISO_8859_2:
410      if (value >= 0xa0) {
411         int v = 0;
412         switch (value) {
413            case 0xa0: case 0xa4: case 0xa7: case 0xa8: case 0xad: case 0xb0:
414            case 0xb4: case 0xb8: case 0xc1: case 0xc2: case 0xc4: case 0xc7:
415            case 0xc9: case 0xcb: case 0xcd: case 0xce: case 0xd3: case 0xd4:
416            case 0xd6: case 0xd7: case 0xda: case 0xdc: case 0xdd: case 0xdf:
417            case 0xe1: case 0xe2: case 0xe4: case 0xe7: case 0xe9: case 0xeb:
418            case 0xed: case 0xee: case 0xf3: case 0xf4: case 0xf6: case 0xf7:
419            case 0xfa: case 0xfc: case 0xfd:
420               v = value; break;
421            case 0x104: v = '\xa1'; break;
422            case 0x2d8: v = '\xa2'; break;
423            case 0x141: v = '\xa3'; break;
424            case 0x13d: v = '\xa5'; break;
425            case 0x15a: v = '\xa6'; break;
426            case 0x160: v = '\xa9'; break;
427            case 0x15e: v = '\xaa'; break;
428            case 0x164: v = '\xab'; break;
429            case 0x179: v = '\xac'; break;
430            case 0x17d: v = '\xae'; break;
431            case 0x17b: v = '\xaf'; break;
432            case 0x105: v = '\xb1'; break;
433            case 0x2db: v = '\xb2'; break;
434            case 0x142: v = '\xb3'; break;
435            case 0x13e: v = '\xb5'; break;
436            case 0x15b: v = '\xb6'; break;
437            case 0x2c7: v = '\xb7'; break;
438            case 0x161: v = '\xb9'; break;
439            case 0x15f: v = '\xba'; break;
440            case 0x165: v = '\xbb'; break;
441            case 0x17a: v = '\xbc'; break;
442            case 0x2dd: v = '\xbd'; break;
443            case 0x17e: v = '\xbe'; break;
444            case 0x17c: v = '\xbf'; break;
445            case 0x154: v = '\xc0'; break;
446            case 0x102: v = '\xc3'; break;
447            case 0x139: v = '\xc5'; break;
448            case 0x106: v = '\xc6'; break;
449            case 0x10c: v = '\xc8'; break;
450            case 0x118: v = '\xca'; break;
451            case 0x11a: v = '\xcc'; break;
452            case 0x10e: v = '\xcf'; break;
453            case 0x110: v = '\xd0'; break;
454            case 0x143: v = '\xd1'; break;
455            case 0x147: v = '\xd2'; break;
456            case 0x150: v = '\xd5'; break;
457            case 0x158: v = '\xd8'; break;
458            case 0x16e: v = '\xd9'; break;
459            case 0x170: v = '\xdb'; break;
460            case 0x162: v = '\xde'; break;
461            case 0x155: v = '\xe0'; break;
462            case 0x103: v = '\xe3'; break;
463            case 0x13a: v = '\xe5'; break;
464            case 0x107: v = '\xe6'; break;
465            case 0x10d: v = '\xe8'; break;
466            case 0x119: v = '\xea'; break;
467            case 0x11b: v = '\xec'; break;
468            case 0x10f: v = '\xef'; break;
469            case 0x111: v = '\xf0'; break;
470            case 0x144: v = '\xf1'; break;
471            case 0x148: v = '\xf2'; break;
472            case 0x151: v = '\xf5'; break;
473            case 0x159: v = '\xf8'; break;
474            case 0x16f: v = '\xf9'; break;
475            case 0x171: v = '\xfb'; break;
476            case 0x163: v = '\xfe'; break;
477            case 0x2d9: v = '\xff'; break;
478         }
[abd126e]479         if (v == 0) break;
[f0a0b05]480         value = v;
481      }
482      *p = value;
483      return 1;
[f8e03f3]484   case CHARSET_ISO_8859_15:
485      switch (value) {
486       case 0xa4: case 0xa6: case 0xb0: case 0xc4:
487       case 0xd0: case 0xd4: case 0xd5: case 0xd6:
488         goto donthave;
489       case 0x152: value = 0xd4; break; /* &OElig; */
490       case 0x153: value = 0xd5; break; /* &oelig; */
491#if 0
492       case 0x0: value = 0xa4; break; /* euro */
[f0a0b05]493#endif
494       case 0x160: value = 0xa6; break; /* Scaron */
495       case 0x161: value = 0xb0; break; /* scaron */
496       case 0x17d: value = 0xc4; break; /* Zcaron */
497       case 0x17e: value = 0xd0; break; /* zcaron */
498#if 0
[f8e03f3]499       case 0x0: value = 0xd6; break; /* Ydiersis */
500#endif
501      }
502      if (value < 0x100) {
503         *p = value;
504         return 1;
505      }
506      donthave:
507      break;
[48e4121]508#if (OS==RISCOS)
[ea816ec]509   case CHARSET_RISCOS31:
510      /* RISC OS 3.1 (and later) extensions to ISO-8859-1 */
511      switch (value) {
512       case 0x152: value = 0x9a; break; /* &OElig; */
513       case 0x153: value = 0x9b; break; /* &oelig; */
[f8e03f3]514#if 0
[ea816ec]515       case 0x174: value = 0x81; break; /* &Wcirc; */
516       case 0x175: value = 0x82; break; /* &wcirc; */
517       case 0x176: value = 0x85; break; /* &Ycirc; */
518       case 0x177: value = 0x86; break; /* &ycirc; */
[f8e03f3]519#endif
[ea816ec]520      }
521      if (value < 0x100) {
522         *p = value;
523         return 1;
524      }
[48e4121]525      break;
[a4140e9]526#elif (OS==WIN32)
[f0a0b05]527   case CHARSET_WINCP1250:
528      /* MS Windows rough equivalent to ISO-8859-2 */
529      if (value >= 0x80) {
530         int v = 0;
531         switch (value) {
532            case 0xa0: case 0xa4: case 0xa6: case 0xa7: case 0xa8: case 0xa9:
533            case 0xab: case 0xac: case 0xad: case 0xae: case 0xb0: case 0xb1:
534            case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xbb:
535            case 0xc1: case 0xc2: case 0xc4: case 0xc7: case 0xc9: case 0xcb:
536            case 0xcd: case 0xce: case 0xd3: case 0xd4: case 0xd6: case 0xd7:
537            case 0xda: case 0xdc: case 0xdd: case 0xdf: case 0xe1: case 0xe2:
538            case 0xe4: case 0xe7: case 0xe9: case 0xeb: case 0xed: case 0xee:
539            case 0xf3: case 0xf4: case 0xf6: case 0xf7: case 0xfa: case 0xfc:
540            case 0xfd:
541               v = value; break;
542            case 0x20ac: v = '\x80'; break;
543            case 0x201a: v = '\x82'; break;
544            case 0x201e: v = '\x84'; break;
545            case 0x2026: v = '\x85'; break;
546            case 0x2020: v = '\x86'; break;
547            case 0x2021: v = '\x87'; break;
548            case 0x2030: v = '\x89'; break;
549            case 0x0160: v = '\x8a'; break;
550            case 0x2039: v = '\x8b'; break;
551            case 0x015a: v = '\x8c'; break;
552            case 0x0164: v = '\x8d'; break;
553            case 0x017d: v = '\x8e'; break;
554            case 0x0179: v = '\x8f'; break;
555            case 0x2018: v = '\x91'; break;
556            case 0x2019: v = '\x92'; break;
557            case 0x201c: v = '\x93'; break;
558            case 0x201d: v = '\x94'; break;
559            case 0x2022: v = '\x95'; break;
560            case 0x2013: v = '\x96'; break;
561            case 0x2014: v = '\x97'; break;
562            case 0x2122: v = '\x99'; break;
563            case 0x0161: v = '\x9a'; break;
564            case 0x203a: v = '\x9b'; break;
565            case 0x015b: v = '\x9c'; break;
566            case 0x0165: v = '\x9d'; break;
567            case 0x017e: v = '\x9e'; break;
568            case 0x017a: v = '\x9f'; break;
569            case 0x02c7: v = '\xa1'; break;
570            case 0x02d8: v = '\xa2'; break;
571            case 0x0141: v = '\xa3'; break;
572            case 0x0104: v = '\xa5'; break;
573            case 0x015e: v = '\xaa'; break;
574            case 0x017b: v = '\xaf'; break;
575            case 0x02db: v = '\xb2'; break;
576            case 0x0142: v = '\xb3'; break;
577            case 0x0105: v = '\xb9'; break;
578            case 0x015f: v = '\xba'; break;
579            case 0x013d: v = '\xbc'; break;
580            case 0x02dd: v = '\xbd'; break;
581            case 0x013e: v = '\xbe'; break;
582            case 0x017c: v = '\xbf'; break;
583            case 0x0154: v = '\xc0'; break;
584            case 0x0102: v = '\xc3'; break;
585            case 0x0139: v = '\xc5'; break;
586            case 0x0106: v = '\xc6'; break;
587            case 0x010c: v = '\xc8'; break;
588            case 0x0118: v = '\xca'; break;
589            case 0x011a: v = '\xcc'; break;
590            case 0x010e: v = '\xcf'; break;
591            case 0x0110: v = '\xd0'; break;
592            case 0x0143: v = '\xd1'; break;
593            case 0x0147: v = '\xd2'; break;
594            case 0x0150: v = '\xd5'; break;
595            case 0x0158: v = '\xd8'; break;
596            case 0x016e: v = '\xd9'; break;
597            case 0x0170: v = '\xdb'; break;
598            case 0x0162: v = '\xde'; break;
599            case 0x0155: v = '\xe0'; break;
600            case 0x0103: v = '\xe3'; break;
601            case 0x013a: v = '\xe5'; break;
602            case 0x0107: v = '\xe6'; break;
603            case 0x010d: v = '\xe8'; break;
604            case 0x0119: v = '\xea'; break;
605            case 0x011b: v = '\xec'; break;
606            case 0x010f: v = '\xef'; break;
607            case 0x0111: v = '\xf0'; break;
608            case 0x0144: v = '\xf1'; break;
609            case 0x0148: v = '\xf2'; break;
610            case 0x0151: v = '\xf5'; break;
611            case 0x0159: v = '\xf8'; break;
612            case 0x016f: v = '\xf9'; break;
613            case 0x0171: v = '\xfb'; break;
614            case 0x0163: v = '\xfe'; break;
615            case 0x02d9: v = '\xff'; break;
616         }
[abd126e]617         if (v == 0) break;
[f0a0b05]618         value = v;
619      }
620      *p = value;
621      return 1;
[0af8e31]622   case CHARSET_WINCP1252:
623      /* MS Windows extensions to ISO-8859-1 */
624      switch (value) {
625       case 0x152: value = 0x8c; break; /* &OElig; */
626       case 0x153: value = 0x9c; break; /* &oelig; */
627#if 0
628      /* there are a few other obscure ones we don't currently need */
629#endif
630      }
631      if (value < 0x100) {
632         *p = value;
633         return 1;
634      }
635      break;
[e2ae719]636#endif
[106af12]637#if (OS==MSDOS)
638   case CHARSET_DOSCP437: {
639      unsigned char uni2dostab[] = {
640          255, 173, 155, 156,   0, 157,   0,   0,
641            0,   0, 166, 174, 170,   0,   0,   0,
642          248, 241, 253,   0,   0, 230,   0, 250,
643            0,   0, 167, 175, 172, 171,   0, 168,
644            0,   0,   0,   0, 142, 143, 146, 128,
645            0, 144,   0,   0,   0,   0,   0,   0,
646            0, 165,   0,   0,   0,   0, 153,   0,
647            0,   0,   0,   0, 154,   0,   0, 225,
648          133, 160, 131,   0, 132, 134, 145, 135,
649          138, 130, 136, 137, 141, 161, 140, 139,
650            0, 164, 149, 162, 147,   0, 148, 246,
651            0, 151, 163, 150, 129,   0,   0, 152,
652      };
653      if (value >= 160 && value < 256) {
[7993643]654         int ch = (int)uni2dostab[value - 160];
[106af12]655         if (!ch) break;
656         *p = ch;
657         return 1;
658      }
659#if 0
660      switch (value) {
661          case 8359: *p = 158; return 1; /* PESETA SIGN */
662          case 402: *p = 159; return 1; /* LATIN SMALL LETTER F WITH HOOK */
663          case 8976: *p = 169; return 1; /* REVERSED NOT SIGN */
664          case 945: *p = 224; return 1; /* GREEK SMALL LETTER ALPHA */
665          case 915: *p = 226; return 1; /* GREEK CAPITAL LETTER GAMMA */
666          case 960: *p = 227; return 1; /* GREEK SMALL LETTER PI */
667          case 931: *p = 228; return 1; /* GREEK CAPITAL LETTER SIGMA */
668          case 963: *p = 229; return 1; /* GREEK SMALL LETTER SIGMA */
669          case 964: *p = 231; return 1; /* GREEK SMALL LETTER TAU */
670          case 934: *p = 232; return 1; /* GREEK CAPITAL LETTER PHI */
671          case 920: *p = 233; return 1; /* GREEK CAPITAL LETTER THETA */
672          case 937: *p = 234; return 1; /* GREEK CAPITAL LETTER OMEGA */
673          case 948: *p = 235; return 1; /* GREEK SMALL LETTER DELTA */
674          case 8734: *p = 236; return 1; /* INFINITY */
675          case 966: *p = 237; return 1; /* GREEK SMALL LETTER PHI */
676          case 949: *p = 238; return 1; /* GREEK SMALL LETTER EPSILON */
677          case 8745: *p = 239; return 1; /* INTERSECTION */
678          case 8801: *p = 240; return 1; /* IDENTICAL TO */
679          case 8805: *p = 242; return 1; /* GREATER-THAN OR EQUAL TO */
680          case 8804: *p = 243; return 1; /* LESS-THAN OR EQUAL TO */
681          case 8992: *p = 244; return 1; /* TOP HALF INTEGRAL */
682          case 8993: *p = 245; return 1; /* BOTTOM HALF INTEGRAL */
683          case 8776: *p = 247; return 1; /* ALMOST EQUAL TO */
684          case 8729: *p = 249; return 1; /* BULLET OPERATOR */
685          case 8730: *p = 251; return 1; /* SQUARE ROOT */
686          case 8319: *p = 252; return 1; /* SUPERSCRIPT LATIN SMALL LETTER N */
687          case 9632: *p = 254; return 1; /* BLACK SQUARE */
688      }
689#endif
690      break;
691   }
692#endif
[e2ae719]693#if (OS==MSDOS || OS==WIN32)
[1b92879]694   case CHARSET_DOSCP850: {
695      unsigned char uni2dostab[] = {
696         255, 173, 189, 156, 207, 190, 221, 245,
697         249, 184, 166, 174, 170, 240, 169, 238,
698         248, 241, 253, 252, 239, 230, 244, 250,
699         247, 251, 167, 175, 172, 171, 243, 168,
700         183, 181, 182, 199, 142, 143, 146, 128,
701         212, 144, 210, 211, 222, 214, 215, 216,
702         209, 165, 227, 224, 226, 229, 153, 158,
703         157, 235, 233, 234, 154, 237, 232, 225,
704         133, 160, 131, 198, 132, 134, 145, 135,
705         138, 130, 136, 137, 141, 161, 140, 139,
706         208, 164, 149, 162, 147, 228, 148, 246,
707         155, 151, 163, 150, 129, 236, 231, 152
708      };
709      if (value >= 160 && value < 256) {
710         *p = (int)uni2dostab[value - 160];
711         return 1;
712      }
[106af12]713#if 0
714      if (value == 305) { /* LATIN SMALL LETTER DOTLESS I */
[1b92879]715         *p = 213;
716         return 1;
717      }
[106af12]718      if (value == 402) { /* LATIN SMALL LETTER F WITH HOOK */
[1b92879]719         *p = 159;
[48e4121]720         return 1;
721      }
[106af12]722#endif
[48e4121]723      break;
[66f8e13]724   }
[48e4121]725#endif
[4432f2e]726   }
[a4140e9]727   /* Transliterate characters we can't represent */
728#ifdef DEBUG
729   fprintf(stderr, "transliterate `%c' 0x%x\n", value, value);
730#endif
731   switch (value) {
732    case 160:
733      *p = ' '; return 1;
734    case 161 /* ¡ */:
735      *p = '!'; return 1;
736    case 171 /* « */:
737      p[1] = *p = '<'; return 2;
738    case 187 /* » */:
739      p[1] = *p = '>'; return 2;
740    case 191 /* ¿ */:
741      *p = '?'; return 1;
742    case 192 /* À */: case 193 /* Á */: case 194 /* Â */: case 195 /* Ã */:
743      *p = 'A'; return 1;
744    case 197 /* Å */:
745      p[1] = *p = 'A'; return 2;
746    case 196 /* Ä */: /* &Auml; */
747      *p = 'A';
748      if (!umlaut_to_e()) return 1;
749      p[1] = 'E'; return 2;
750    case 198 /* Æ */:
751      *p = 'A'; p[1] = 'E'; return 2;
[f0a0b05]752    case 199 /* Ç */: case 268: /* &Ccaron; */
[a4140e9]753      *p = 'C'; return 1;
[f0a0b05]754    case 270: /* &Dcaron; */
755      *p = 'D'; return 1;
[a4140e9]756    case 200 /* È */: case 201 /* É */: case 202 /* Ê */: case 203 /* Ë */:
757      *p = 'E'; return 1;
758    case 204 /* Ì */: case 205 /* Í */: case 206 /* Î */: case 207 /* Ï */:
759      *p = 'I'; return 1;
760    case 208 /* Ð */: case 222 /* Þ */:
761      *p = 'T'; p[1] = 'H'; return 2;
[f0a0b05]762    case 315: /* &Lacute; */
763      *p = 'L'; return 1;
[a4140e9]764    case 209 /* Ñ */:
765      *p = 'N'; return 1;
766    case 210 /* Ò */: case 211 /* Ó */: case 212 /* Ô */: case 213 /* Õ */:
767      *p = 'O'; return 1;
768    case 214 /* Ö */: /* &Ouml; */ case 0x152: /* &OElig; */
769      *p = 'O'; p[1] = 'E'; return 2;
[f0a0b05]770    case 352: /* &Scaron; */
771      *p = 'S'; return 1;
[a4140e9]772    case 217 /* Ù */: case 218 /* Ú */: case 219 /* Û */:
773      *p = 'U'; return 1;
774    case 220 /* Ü */: /* &Uuml; */
775      *p = 'U'; p[1] = 'E'; return 2;
776    case 221 /* Ý */:
777      *p = 'Y'; return 1;
[f0a0b05]778    case 381: /* &Zcaron; */
779      *p = 'Z'; return 1;
[a4140e9]780    case 223 /* ß */:
781      p[1] = *p = 's'; return 2;
782    case 224 /* à */: case 225 /* á */: case 226 /* â */: case 227 /* ã */:
783      *p = 'a'; return 1;
784    case 228 /* ä */: /* &auml; */ case 230 /* æ */:
785      *p = 'a'; p[1] = 'e'; return 2;
786    case 229 /* å */:
787      p[1] = *p = 'a'; return 2;
[f0a0b05]788    case 231 /* ç */: case 269 /* &ccaron; */:
[a4140e9]789      *p = 'c'; return 1;
[f0a0b05]790    case 271: /* &dcaron; */
791      *p = 'd'; return 1;
[a4140e9]792    case 232 /* è */: case 233 /* é */: case 234 /* ê */: case 235 /* ë */:
[f0a0b05]793    case 283 /* &ecaron; */:
[a4140e9]794      *p = 'e'; return 1;
795    case 236 /* ì */: case 237 /* í */: case 238 /* î */: case 239 /* ï */:
796      *p = 'i'; return 1;
[f0a0b05]797    case 316 /* &lacute; */:
798      *p = 'l'; return 1;
799    case 241 /* ñ */: case 328 /* &ncaron; */:
[a4140e9]800      *p = 'n'; return 1;
[f0a0b05]801    case 345: /* &rcaron; */
802      *p = 'r'; return 1;
803    case 353: /* &scaron; */
804      *p = 's'; return 1;
805    case 357: /* &tcaron; */
806      *p = 't'; return 1;
[a4140e9]807    case 240 /* ð */: case 254 /* þ */:
808      *p = 't'; p[1] = 'h'; return 2;
[421b7d2]809    case 242 /* ò */: case 243 /* ó */: case 244 /* ô */: case 245 /* õ */:
[a4140e9]810      *p = 'o'; return 1;
811    case 246 /* ö */: /* &ouml; */ case 0x153: /* &oelig; */
812      *p = 'o'; p[1] = 'e'; return 2;
813    case 249 /* ù */: case 250 /* ú */: case 251 /* û */:
[f0a0b05]814    case 367 /* &uring; */:
[a4140e9]815      *p = 'u'; return 1;
816    case 252 /* ü */: /* &uuml; */
817      *p = 'u'; p[1] = 'e'; return 2;
818    case 253 /* ý */: case 255 /* ÿ */:
819      *p = 'y'; return 1;
[f0a0b05]820    case 382: /* &zcaron; */
821      *p = 'z'; return 1;
[a4140e9]822   }
823#ifdef DEBUG
824   fprintf(stderr, "failed to transliterate\n");
825#endif
[f1a5201]826   return 0;
[4432f2e]827}
828
[fa42426]829#if (OS==UNIX) && defined(DATADIR) && defined(PACKAGE)
830/* Under Unix, we compile in the configured path */
831static const char *pth_cfg_files = DATADIR "/" PACKAGE;
832#else
833/* On other platforms, we fall back on looking in the current directory */
[f2a6ce4]834static const char *pth_cfg_files = "";
[fa42426]835#endif
[f2a6ce4]836
[db75e18]837static int num_msgs = 0;
[55de792]838static char **msg_array = NULL;
[db75e18]839
[b83f907]840const char *msg_lang = NULL;
[c0a9908]841const char *msg_lang2 = NULL;
[b83f907]842
[d5bd3a7]843static char **
844parse_msgs(int n, unsigned char *p, int charset_code) {
845   int i;
846
847   char **msgs = osmalloc(n * sizeof(char *));
848
849   for (i = 0; i < n; i++) {
850      unsigned char *to = p;
851      int ch;
852      msgs[i] = (char *)p;
853
854      /* If we want UTF8 anyway, we just need to find the start of each
855       * message */
856      if (charset_code == CHARSET_UTF8) {
857         p += strlen((char *)p) + 1;
858         continue;
859      }
860
861      while ((ch = *p++) != 0) {
862         /* A byte in the range 0x80-0xbf or 0xf0-0xff isn't valid in
863          * this state, (0xf0-0xfd mean values > 0xffff) so treat as
864          * literal and try to resync so we cope better when fed
865          * non-utf-8 data.  Similarly we abandon a multibyte sequence
866          * if we hit an invalid character. */
867         if (ch >= 0xc0 && ch < 0xf0) {
868            int ch1 = *p;
869            if ((ch1 & 0xc0) != 0x80) goto resync;
870
871            if (ch < 0xe0) {
872               /* 2 byte sequence */
873               ch = ((ch & 0x1f) << 6) | (ch1 & 0x3f);
874               p++;
875            } else {
876               /* 3 byte sequence */
877               int ch2 = p[1];
878               if ((ch2 & 0xc0) != 0x80) goto resync;
879               ch = ((ch & 0x1f) << 12) | ((ch1 & 0x3f) << 6) | (ch2 & 0x3f);
880               p += 2;
881            }
882         }
883
[421b7d2]884         resync:
[d5bd3a7]885
886         if (ch < 127) {
887            *to++ = (char)ch;
888         } else {
[421b7d2]889            /* We assume an N byte UTF-8 code never transliterates to more
[d5bd3a7]890             * than N characters (so we can't transliterate © to (C) or
891             * ® to (R) for example) */
892            to += add_unicode(charset_code, to, ch);
893         }
894      }
895      *to++ = '\0';
896   }
897   return msgs;
898}
899
[c8f550b]900/* This is the name of the default language, which can be set like so:
901 * ./configure --enable-defaultlang=fr
[0874cd6a]902 */
903#ifdef DEFAULTLANG
[d5bd3a7]904/* No point extracting these errors as they won't get used if file opens */
[c8f550b]905# include "../lib/defaultlang.h"
[0874cd6a]906#else
907#define N_DONTEXTRACTMSGS 5
908static unsigned char dontextractmsgs[] =
909   "Can't open message file `%s' using path `%s'\0"/*1000*/
910   "Problem with message file `%s'\0"/*1001*/
911   "I don't understand this message file version\0"/*1002*/
912   "Message file truncated?\0"/*1003*/
913   "Out of memory (couldn't find %lu bytes).\0"/*1004*/;
914#endif
[d5bd3a7]915
916static char **dontextract = NULL;
917
[db75e18]918static void
919parse_msg_file(int charset_code)
920{
921   FILE *fh;
922   unsigned char header[20];
[421b7d2]923   int i;
[db75e18]924   unsigned len;
[55de792]925   unsigned char *p;
[b164c18]926   char *fnm, *s;
[d5bd3a7]927   int n;
[cb3d1e2]928
[55de792]929#ifdef DEBUG
930   fprintf(stderr, "parse_msg_file(%d)\n", charset_code);
931#endif
[db75e18]932
[d5bd3a7]933   /* sort out messages we need to print if we can't open the message file */
934   dontextract = parse_msgs(N_DONTEXTRACTMSGS, dontextractmsgs, charset_code);
935
[0a3c5fa]936   fnm = osstrdup(msg_lang);
[b164c18]937   /* trim off charset from stuff like "de_DE.iso8859_1" */
938   s = strchr(fnm, '.');
939   if (s) *s = '\0';
[a2f9d5c]940
[b164c18]941   fh = fopenWithPthAndExt(pth_cfg_files, fnm, EXT_SVX_MSG, "rb", NULL);
[db75e18]942
943   if (!fh) {
[fd5f670]944      /* e.g. if 'en_GB' is unknown, see if we know 'en' */
945      if (strlen(fnm) > 3 && fnm[2] == '_') {
[b164c18]946         fnm[2] = '\0';
947         fh = fopenWithPthAndExt(pth_cfg_files, fnm, EXT_SVX_MSG, "rb", NULL);
[fd5f670]948         if (!fh) fnm[2] = '_'; /* for error reporting */
[db75e18]949      }
[48e4121]950   }
[db75e18]951
952   if (!fh) {
[b07f165]953      fatalerror(/*Can't open message file `%s' using path `%s'*/1000,
954                 fnm, pth_cfg_files);
[4432f2e]955   }
[db75e18]956
957   if (fread(header, 1, 20, fh) < 20 ||
958       memcmp(header, "Svx\nMsg\r\n\xfe\xff", 12) != 0) {
[b07f165]959      fatalerror(/*Problem with message file `%s'*/1001, fnm);
[db75e18]960   }
961
[b07f165]962   if (header[12] != 0)
963      fatalerror(/*I don't understand this message file version*/1002);
[db75e18]964
[d5bd3a7]965   n = (header[14] << 8) | header[15];
[db75e18]966
967   len = 0;
968   for (i = 16; i < 20; i++) len = (len << 8) | header[i];
969
[0a3c5fa]970   p = osmalloc(len);
[b07f165]971   if (fread(p, 1, len, fh) < len)
972      fatalerror(/*Message file truncated?*/1003);
[2163157]973
[a420b49]974   fclose(fh);
[db75e18]975
[55de792]976#ifdef DEBUG
[d5bd3a7]977   fprintf(stderr, "fnm = `%s', n = %d, len = %d\n", fnm, n, len);
[55de792]978#endif
[b164c18]979   osfree(fnm);
[55de792]980
[d5bd3a7]981   msg_array = parse_msgs(n, p, charset_code);
982   num_msgs = n;
[4432f2e]983}
984
[f2a6ce4]985const char *
986msg_cfgpth(void)
987{
988   return pth_cfg_files;
989}
990
[bdfe97f]991const char *
992msg_appname(void)
993{
994   return appname_copy;
995}
996
[f2a6ce4]997void
[bdfe97f]998msg_init(char * const *argv)
[db75e18]999{
1000   char *p;
[4c07c51]1001   SVX_ASSERT(argv);
[db75e18]1002
1003#ifdef HAVE_SIGNAL
1004   init_signals();
1005#endif
[bdfe97f]1006   /* Point to argv[0] itself so we report a more helpful error if the
1007    * code to work out the clean appname generates a signal */
1008   appname_copy = argv[0];
[0a3c5fa]1009#if (OS == UNIX)
1010   /* use name as-is on Unix - programs run from path get name as supplied */
[bdfe97f]1011   appname_copy = osstrdup(argv[0]);
[0a3c5fa]1012#else
1013   /* use the lower-cased leafname on other platforms */
[27b8b59]1014   p = leaf_from_fnm(argv[0]);
1015   appname_copy = p;
[4bfc8a7]1016   while (*p) {
1017      *p = tolower(*p);
[27b8b59]1018      ++p;
[4bfc8a7]1019   }
[0a3c5fa]1020#endif
[db75e18]1021
[5e14c5f]1022   /* shortcut --version so you can check the version number even when the
1023    * correct message file can't be found... */
[bdfe97f]1024   if (argv[1] && strcmp(argv[1], "--version") == 0) {
1025      cmdline_version();
1026      exit(0);
1027   }
1028
[fa42426]1029   if (argv[0]) {
1030#if (OS==UNIX) && defined(DATADIR) && defined(PACKAGE)
[30d0b94]1031      bool free_pth = fFalse;
1032      char *pth = getenv("srcdir");
1033      if (!pth || !pth[0]) {
1034         pth = path_from_fnm(argv[0]);
1035         free_pth = fTrue;
1036      }
[fa42426]1037      if (pth[0]) {
[5e14c5f]1038         /* If we're run with an explicit path, check if "../lib/en.msg"
1039          * from the program's path exists, and if so look there for
[fa42426]1040          * support files - this allows us to test binaries in the build
1041          * tree easily. */
1042         /* May also be useful on MacOS X where the programs may be
1043          * installed anywhere... */
[5e14c5f]1044         char *p = use_path(pth, "../lib/en.msg");
1045         FILE *f = fopen(p, "r");
1046         if (f) {
1047            close(f);
1048            pth_cfg_files = use_path(pth, "../lib");
[fa42426]1049         }
[5e14c5f]1050         osfree(p);
[fa42426]1051      }
[30d0b94]1052      if (free_pth) osfree(pth);
[27b8b59]1053#elif (OS==WIN32)
1054      DWORD len = 256;
1055      char *buf = NULL, *modname;
1056      while (1) {
1057          DWORD got;
1058          buf = osrealloc(buf, len);
1059          got = GetModuleFileName(NULL, buf, len);
1060          if (got < len) break;
1061          len += len;
1062      }
1063      modname = buf;
1064      /* Strange Win32 nastiness - strip prefix "\\?\" if present */
1065      if (strncmp(modname, "\\\\?\\", 4) == 0) modname += 4;
1066      pth_cfg_files = path_from_fnm(modname);
1067      osfree(buf);
[a420b49]1068#else
[fa42426]1069      /* Get the path to the support files from argv[0] */
[bdfe97f]1070      pth_cfg_files = path_from_fnm(argv[0]);
[a420b49]1071#endif
[db75e18]1072   }
1073
[b164c18]1074   msg_lang = getenv("SURVEXLANG");
1075#ifdef DEBUG
[74044b7]1076   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang, msg_lang?msg_lang:"(null)");
[b164c18]1077#endif
1078
1079   if (!msg_lang || !*msg_lang) {
1080      msg_lang = getenv("LANG");
[74044b7]1081      if (!msg_lang || !*msg_lang) {
1082#if (OS==WIN32)
1083         LCID locid;
[1e275f0]1084#elif (OS==RISCOS)
1085         territory_t t;
[74044b7]1086#endif
[37fca9b]1087#ifdef DEFAULTLANG
[d5bd3a7]1088         msg_lang = STRING(DEFAULTLANG);
[37fca9b]1089#else
1090         msg_lang = "en";
1091#endif
[74044b7]1092#if (OS==WIN32)
1093         locid = GetUserDefaultLCID();
1094         if (locid) {
1095            WORD langid = LANGIDFROMLCID(locid);
1096            switch (PRIMARYLANGID(langid)) {
[761c5f9]1097/* older mingw compilers don't seem to supply this value */
1098#ifndef LANG_CATALAN
1099# define LANG_CATALAN 0x03
1100#endif
[74044b7]1101             case LANG_CATALAN:
1102               msg_lang = "ca";
1103               break;
[21c226e]1104             case LANG_CHINESE:
1105               msg_lang = "zh";
1106               break;
[74044b7]1107             case LANG_ENGLISH:
1108               if (SUBLANGID(langid) == SUBLANG_ENGLISH_US)
1109                  msg_lang = "en_US";
1110               else
1111                  msg_lang = "en";
1112               break;
1113             case LANG_FRENCH:
1114               msg_lang = "fr";
1115               break;
1116             case LANG_GERMAN:
1117               switch (SUBLANGID(langid)) {
1118                case SUBLANG_GERMAN_SWISS:
1119                  msg_lang = "de_CH";
1120                  break;
1121                case SUBLANG_GERMAN:
1122                  msg_lang = "de_DE";
1123                  break;
1124                default:
1125                  msg_lang = "de";
1126               }
1127               break;
1128             case LANG_ITALIAN:
1129               msg_lang = "it";
1130               break;
1131             case LANG_PORTUGUESE:
1132               if (SUBLANGID(langid) == SUBLANG_PORTUGUESE_BRAZILIAN)
1133                  msg_lang = "pt_BR";
1134               else
1135                  msg_lang = "pt";
1136               break;
[b6de07d]1137             case LANG_SLOVAK:
1138               msg_lang = "sk";
1139               break;
[74044b7]1140             case LANG_SPANISH:
1141               msg_lang = "es";
1142               break;
1143            }
1144         }
[44740e7]1145#elif (OS==RISCOS)
[1e275f0]1146         if (!xterritory_number(&t)) switch (t) {
[44740e7]1147          case 1: /* UK */
1148          case 2: /* Master */
1149          case 3: /* Compact */
1150          case 17: /* Canada1 */
1151          case 19: /* Canada */
1152          case 22: /* Ireland */
1153            msg_lang = "en";
1154            break;
1155          case 4: /* Italy */
1156            msg_lang = "it";
1157            break;
[1b92879]1158          case 5: /* Spain (or ca) */
[44740e7]1159          case 27: /* Mexico */
[1b92879]1160          case 28: /* LatinAm (or pt_BR) */
1161            msg_lang = "es";
[44740e7]1162            break;
1163          case 6: /* France */
1164          case 18: /* Canada2 */
1165            msg_lang = "fr";
1166            break;
1167          case 7: /* Germany */
1168            msg_lang = "de_DE";
1169            break;
1170          case 8: /* Portugal */
1171            msg_lang = "pt";
1172            break;
[21c226e]1173          case 23: /* Hong Kong */
1174            msg_lang = "zh";
1175            break;
[44740e7]1176          case 48: /* USA */
1177            msg_lang = "en_US";
1178            break;
1179#if 0
1180          case 9: /* Esperanto */
1181          case 10: /* Greece */
1182          case 11: /* Sweden */
1183          case 12: /* Finland */
1184          case 13: /* Unused */
1185          case 14: /* Denmark */
1186          case 15: /* Norway */
1187          case 16: /* Iceland */
1188          case 20: /* Turkey */
1189          case 21: /* Arabic */
1190          case 24: /* Russia */
1191          case 25: /* Russia2 */
1192          case 26: /* Israel */
[421b7d2]1193#endif
[84faf78b]1194         }
[1b92879]1195#elif (OS==MSDOS)
1196           {
[cd620d5]1197              int country_code;
1198# ifdef __DJGPP__
[106af12]1199              __dpmi_regs r;
1200              r.x.ax = 0x6501;
1201              r.x.bx = 0xffff;
1202              r.x.dx = 0xffff;
1203              /* Use DJGPP's transfer buffer (which is at least 2K) */
1204              r.x.es = __tb >> 4;
1205              r.x.di = __tb & 0x0f;
1206              r.x.cx = 2048;
1207              /* bit 1 is the carry flag */
[7993643]1208              if (__dpmi_int(0x21, &r) != -1 && !(r.x.flags & 1)) {
[106af12]1209                 unsigned short p;
[421b7d2]1210                 dosmemget(__tb + 3, 2, &p);
1211                 country_code = p;
[cd620d5]1212# else
[03daa88]1213              union REGS r;
1214              r.x.ax = 0x3800; /* get current country info */
1215              r.x.dx = 0;
1216              intdos(&r, &r);
1217              if (!r.x.cflag) {
[106af12]1218                 country_code = r.x.bx;
[cd620d5]1219# endif
[106af12]1220                 /* List of country codes taken from:
1221                  * http://www.delorie.com/djgpp/doc/rbinter/it/00/14.html */
1222                 /* The mappings here are guesses at best in most cases.
1223                  * In a lot of cases we pick a language because we have
1224                  * a translation in it, rather than because it's the most
1225                  * widely used or understood in that country. */
1226                 /* Improvements welcome */
1227                 switch (country_code) {
[cd620d5]1228                     case 1: /* United States */
1229                     case 670: /* Saipan / N. Mariana Island */
1230                     case 671: /* Guam */
1231                     case 680: /* Palau */
1232                     case 684: /* American Samoa */
1233                     case 691: /* Micronesia */
1234                     case 692: /* Marshall Islands */
[106af12]1235                         msg_lang = "en_US";
1236                         break;
[cd620d5]1237                     case 4: /* Canada (English) */
1238                     case 27: /* South Africa */
1239                     case 44: /* United Kingdom */
1240                     case 61: /* International English / Australia */
1241                     case 64: /* New Zealand */
1242                     case 99: /* Asia (English) */
1243                     case 220: /* Gambia */
1244                     case 231: /* Liberia */
1245                     case 232: /* Sierra Leone */
1246                     case 233: /* Ghana */
1247                     case 254: /* Kenya */
1248                     case 256: /* Uganda */
1249                     case 260: /* Zambia */
1250                     case 263: /* Zimbabwe */
1251                     case 264: /* Namibia */
1252                     case 267: /* Botswana */
1253                     case 268: /* Swaziland */
1254                     case 290: /* St. Helena */
1255                     case 297: /* Aruba */
1256                     case 350: /* Gibraltar */
1257                     case 353: /* Ireland */
1258                     case 356: /* Malta */
1259                     case 500: /* Falkland Islands */
1260                     case 501: /* Belize */
1261                     case 592: /* Guyana */
1262                     case 672: /* Norfolk Island (Australia) / Christmas Island/Cocos Islands / Antartica */
1263                     case 673: /* Brunei Darussalam */
1264                     case 674: /* Nauru */
1265                     case 675: /* Papua New Guinea */
1266                     case 676: /* Tonga Islands */
1267                     case 677: /* Solomon Islands */
1268                     case 679: /* Fiji */
1269                     case 682: /* Cook Islands */
1270                     case 683: /* Niue */
1271                     case 685: /* Western Samoa */
1272                     case 686: /* Kiribati */
[106af12]1273                         /* I believe only some of these are English speaking... */
[cd620d5]1274                     case 809: /* Antigua and Barbuda / Anguilla / Bahamas / Barbados / Bermuda
[106af12]1275                                  British Virgin Islands / Cayman Islands / Dominica
1276                                  Dominican Republic / Grenada / Jamaica / Montserra
1277                                  St. Kitts and Nevis / St. Lucia / St. Vincent and Grenadines
1278                                  Trinidad and Tobago / Turks and Caicos */
1279                         msg_lang = "en";
1280                         break;
[cd620d5]1281                     case 2: /* Canadian-French */
1282                     case 32: /* Belgium */ /* maybe */
1283                     case 33: /* France */
1284                     case 213: /* Algeria */
1285                     case 216: /* Tunisia */
1286                     case 221: /* Senegal */
1287                     case 223: /* Mali */
1288                     case 225: /* Ivory Coast */
1289                     case 226: /* Burkina Faso */
1290                     case 227: /* Niger */
1291                     case 228: /* Togo */
1292                     case 229: /* Benin */
1293                     case 230: /* Mauritius */
1294                     case 235: /* Chad */
1295                     case 236: /* Central African Republic */
1296                     case 237: /* Cameroon */
1297                     case 241: /* Gabon */
1298                     case 242: /* Congo */
1299                     case 250: /* Rwhanda */
1300                     case 253: /* Djibouti */
1301                     case 257: /* Burundi */
1302                     case 261: /* Madagascar */
1303                     case 262: /* Reunion Island */
1304                     case 269: /* Comoros */
1305                     case 270: /* Mayotte */
1306                     case 352: /* Luxembourg (or de or ...) */
1307                     case 508: /* St. Pierre and Miquelon */
1308                     case 509: /* Haiti */
1309                     case 590: /* Guadeloupe */
1310                     case 594: /* French Guiana */
1311                     case 596: /* Martinique / French Antilles */
1312                     case 678: /* Vanuatu */
1313                     case 681: /* Wallis & Futuna */
1314                     case 687: /* New Caledonia */
1315                     case 689: /* French Polynesia */
1316                     case 961: /* Lebanon */
[106af12]1317                         msg_lang = "fr";
1318                         break;
[cd620d5]1319                     case 3: /* Latin America */
1320                     case 34: /* Spain */
1321                     case 51: /* Peru */
1322                     case 52: /* Mexico */
1323                     case 53: /* Cuba */
1324                     case 54: /* Argentina */
1325                     case 56: /* Chile */
1326                     case 57: /* Columbia */
1327                     case 58: /* Venezuela */
1328                     case 63: /* Philippines */
1329                     case 240: /* Equatorial Guinea */
1330                     case 502: /* Guatemala */
1331                     case 503: /* El Salvador */
1332                     case 504: /* Honduras */
1333                     case 505: /* Nicraragua */
1334                     case 506: /* Costa Rica */
1335                     case 507: /* Panama */
1336                     case 591: /* Bolivia */
1337                     case 593: /* Ecuador */
1338                     case 595: /* Paraguay */
1339                     case 598: /* Uruguay */
[106af12]1340                         msg_lang = "es";
1341                         break;
[cd620d5]1342                     case 39: /* Italy / San Marino / Vatican City */
[106af12]1343                         msg_lang = "it";
1344                         break;
[cd620d5]1345                     case 41: /* Switzerland / Liechtenstein */ /* or fr or ... */
[106af12]1346                         msg_lang = "de_CH";
1347                         break;
[cd620d5]1348                     case 43: /* Austria (DR DOS 5.0) */
[106af12]1349                         msg_lang = "de";
1350                         break;
[cd620d5]1351                     case 49: /* Germany */
[106af12]1352                         msg_lang = "de_DE";
1353                         break;
[cd620d5]1354                     case 55: /* Brazil (not supported by DR DOS 5.0) */
[106af12]1355                         msg_lang = "pt_BR";
1356                         break;
[cd620d5]1357                     case 238: /* Cape Verde Islands */
1358                     case 244: /* Angola */
1359                     case 245: /* Guinea-Bissau */
1360                     case 259: /* Mozambique */
1361                     case 351: /* Portugal */
[106af12]1362                         msg_lang = "pt";
1363                         break;
[b6de07d]1364                     case 42: /* Czechoslovakia / Tjekia / Slovakia (not supported by DR DOS 5.0) */
1365                     case 421: /* Czech Republic / Tjekia (PC DOS 7+) */
1366                     case 422: /* Slovakia (reported as 421 due to a bug in COUNTRY.SYS) */
1367                         msg_lang = "sk";
1368                         break;
[21c226e]1369                     case 65: /* Singapore */
1370                     case 86: /* China (MS-DOS 5.0+) */
1371                     case 88: /* Taiwan (MS-DOS 5.0+) */
1372                     case 852: /* Hong Kong */
1373                     case 853: /* Macao */
1374                     case 886: /* Taiwan (MS-DOS 6.22+) */
1375                         msg_lang = "zh";
1376                         break;
[1b92879]1377#if 0
[cd620d5]1378                     case 7: /* Russia */
1379                     case 20: /* Egypt */
1380                     case 30: /* Greece */
1381                     case 31: /* Netherlands */
1382                     case 35: /* Bulgaria??? */
1383                     case 36: /* Hungary (not supported by DR DOS 5.0) */
1384                     case 38: /* Yugoslavia (not supported by DR DOS 5.0) -- obsolete */
1385                     case 40: /* Romania */
1386                     case 45: /* Denmark */
1387                     case 46: /* Sweden */
1388                     case 47: /* Norway */
1389                     case 48: /* Poland (not supported by DR DOS 5.0) */
1390                     case 60: /* Malaysia */
1391                     case 62: /* Indonesia / East Timor */
[54d6e7d]1392                     case 66: /* Thailand (or Taiwan??? ) */
[cd620d5]1393                     case 81: /* Japan (DR DOS 5.0, MS-DOS 5.0+) */
1394                     case 82: /* South Korea (DR DOS 5.0) */
1395                     case 84: /* Vietnam */
1396                     case 90: /* Turkey (MS-DOS 5.0+) */
1397                     case 91: /* India */
1398                     case 92: /* Pakistan */
1399                     case 93: /* Afghanistan */
1400                     case 94: /* Sri Lanka */
1401                     case 98: /* Iran */
1402                     case 102: /* ??? (Hebrew MS-DOS 5.0) */
1403                     case 112: /* Belarus */
1404                     case 200: /* Thailand (PC DOS 6.1+) (reported as 01due to a bug in PC DOS COUNTRY.SYS) */
1405                     case 212: /* Morocco */
1406                     case 218: /* Libya */
1407                     case 222: /* Maruitania */
1408                     case 224: /* African Guinea */
1409                     case 234: /* Nigeria */
1410                     case 239: /* Sao Tome and Principe */
1411                     case 243: /* Zaire */
1412                     case 246: /* Diego Garcia */
1413                     case 247: /* Ascension Isle */
1414                     case 248: /* Seychelles */
1415                     case 249: /* Sudan */
1416                     case 251: /* Ethiopia */
1417                     case 252: /* Somalia */
1418                     case 255: /* Tanzania */
1419                     case 265: /* Malawi */
1420                     case 266: /* Lesotho */
1421                     case 298: /* Faroe Islands */
1422                     case 299: /* Greenland */
1423                     case 354: /* Iceland */
1424                     case 355: /* Albania */
1425                     case 357: /* Cyprus */
1426                     case 358: /* Finland */
1427                     case 359: /* Bulgaria */
1428                     case 370: /* Lithuania (reported as 372 due to a bug in MS-DOS COUNTRY.SYS) */
1429                     case 371: /* Latvia (reported as 372 due to a bug in MS-DOS COUNTRY.SYS) */
1430                     case 372: /* Estonia */
1431                     case 373: /* Moldova */
1432                     case 375: /* ??? (MS-DOS 7.10 / Windows98) */
1433                     case 380: /* Ukraine */
1434                     case 381: /* Serbia / Montenegro */
1435                     case 384: /* Croatia */
1436                     case 385: /* Croatia (PC DOS 7+) */
1437                     case 386: /* Slovenia */
1438                     case 387: /* Bosnia-Herzegovina (Latin) */
1439                     case 388: /* Bosnia-Herzegovina (Cyrillic) (PC DOS 7+) (reported as 381 due to a bug in PC DOS COUNTRY.SYS) */
1440                     case 389: /* FYR Macedonia */
1441                     case 597: /* Suriname (nl) */
1442                     case 599: /* Netherland Antilles (nl) */
1443                     case 666: /* Russia??? (PTS-DOS 6.51 KEYB) */
1444                     case 667: /* Poland??? (PTS-DOS 6.51 KEYB) */
[54d6e7d]1445                     case 668: /* Poland??? (Slavic??? ) (PTS-DOS 6.51 KEYB) */
[cd620d5]1446                     case 688: /* Tuvalu */
1447                     case 690: /* Tokealu */
1448                     case 711: /* ??? (currency = EA$, code pages 437,737,850,852,855,857) */
1449                     case 785: /* Arabic (Middle East/Saudi Arabia/etc.) */
1450                     case 804: /* Ukraine */
1451                     case 850: /* North Korea */
1452                     case 855: /* Cambodia */
1453                     case 856: /* Laos */
1454                     case 880: /* Bangladesh */
1455                     case 960: /* Maldives */
1456                     case 962: /* Jordan */
1457                     case 963: /* Syria / Syrian Arab Republic */
1458                     case 964: /* Iraq */
1459                     case 965: /* Kuwait */
1460                     case 966: /* Saudi Arabia */
1461                     case 967: /* Yemen */
1462                     case 968: /* Oman */
1463                     case 969: /* Yemen??? (Arabic MS-DOS 5.0) */
1464                     case 971: /* United Arab Emirates */
1465                     case 972: /* Israel (Hebrew) (DR DOS 5.0,MS-DOS 5.0+) */
1466                     case 973: /* Bahrain */
1467                     case 974: /* Qatar */
1468                     case 975: /* Bhutan */
1469                     case 976: /* Mongolia */
1470                     case 977: /* Nepal */
1471                     case 995: /* Myanmar (Burma) */
[652ef1b]1472#endif
[106af12]1473                 }
[6e717ae]1474              }
1475           }
[84faf78b]1476#endif
[74044b7]1477      }
[b164c18]1478   }
1479#ifdef DEBUG
1480   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang, msg_lang?msg_lang:"(null)");
1481#endif
1482
1483   /* On Mandrake LANG defaults to C */
1484   if (strcmp(msg_lang, "C") == 0) msg_lang = "en";
1485
[0a3c5fa]1486   msg_lang = osstrdup(msg_lang);
[b164c18]1487
1488   /* Convert en-us to en_US, etc */
1489   p = strchr(msg_lang, '-');
1490   if (p) {
1491      *p++ = '_';
1492      while (*p) {
1493         *p = toupper(*p);
1494         p++;
1495      }
1496   }
1497
1498   p = strchr(msg_lang, '_');
1499   if (p) {
1500      *p = '\0';
[0a3c5fa]1501      msg_lang2 = osstrdup(msg_lang);
[b164c18]1502      *p = '_';
1503   }
1504
1505#ifdef LC_MESSAGES
1506   /* try to setlocale() appropriately too */
1507   if (!setlocale(LC_MESSAGES, msg_lang)) {
1508      if (msg_lang2) setlocale(LC_MESSAGES, msg_lang2);
1509   }
1510#endif
1511
[db75e18]1512   select_charset(default_charset());
1513}
1514
[d5bd3a7]1515/* Message may be overwritten by next call
[bd1913f]1516 * (but not in current implementation) */
1517const char *
[db75e18]1518msg(int en)
1519{
[4c07c51]1520   /* NB can't use SVX_ASSERT here! */
[eee67ab]1521   static char badbuf[256];
[d5bd3a7]1522   if (en >= 1000 && en < 1000 + N_DONTEXTRACTMSGS)
[b07f165]1523      return dontextract[en - 1000];
[55de792]1524   if (!msg_array) {
[eee67ab]1525      if (en != 1)  {
[21c226e]1526         sprintf(badbuf, "Message %d requested before msg_array initialised\n",
1527                 en);
[eee67ab]1528         return badbuf;
1529      }
[d5bd3a7]1530      /* this should be the only other message which can be requested before
[a420b49]1531       * the message file is opened and read... */
[d5bd3a7]1532      if (!dontextract) return "Out of memory (couldn't find %lu bytes).";
[c40038a]1533      return dontextract[(/*Out of memory (couldn't find %lu bytes).*/1004)
1534                         - 1000];
[db75e18]1535   }
1536
[eee67ab]1537   if (en < 0 || en >= num_msgs) {
1538      sprintf(badbuf, "Message %d out of range\n", en);
1539      return badbuf;
1540   }
[db75e18]1541
[90123e8]1542   if (en == 0) {
[7993643]1543      const char *p = msg_array[0];
[90123e8]1544      if (!*p) p = "(C)";
1545      return p;
1546   }
1547
[55de792]1548   return msg_array[en];
[db75e18]1549}
1550
1551/* returns persistent copy of message */
[bd1913f]1552const char *
[db75e18]1553msgPerm(int en)
1554{
1555   return msg(en);
1556}
1557
1558void
1559v_report(int severity, const char *fnm, int line, int en, va_list ap)
1560{
[1f316f3]1561#ifdef AVEN
[2e18955]1562   aven_v_report(severity, fnm, line, en, ap);
[2163157]1563#else
[db75e18]1564   if (fnm) {
1565      fputs(fnm, STDERR);
1566      if (line) fprintf(STDERR, ":%d", line);
1567   } else {
[a4140e9]1568      fputs(appname_copy, STDERR);
[cb3d1e2]1569   }
[db75e18]1570   fputs(": ", STDERR);
1571
1572   if (severity == 0) {
1573      fputs(msg(/*warning*/4), STDERR);
1574      fputs(": ", STDERR);
1575   }
1576
1577   vfprintf(STDERR, msg(en), ap);
1578   fputnl(STDERR);
[1f316f3]1579#endif
[cb3d1e2]1580
[db75e18]1581   switch (severity) {
1582    case 0:
[25ab06b]1583      msg_warnings++;
[db75e18]1584      break;
1585    case 1:
[25ab06b]1586      msg_errors++;
1587      if (msg_errors == 50)
[db75e18]1588         fatalerror_in_file(fnm, 0, /*Too many errors - giving up*/19);
1589      break;
1590    case 2:
1591      exit(EXIT_FAILURE);
1592   }
1593}
1594
1595void
1596warning(int en, ...)
1597{
1598   va_list ap;
1599   va_start(ap, en);
1600   v_report(0, NULL, 0, en, ap);
1601   va_end(ap);
1602}
1603
1604void
1605error(int en, ...)
1606{
1607   va_list ap;
1608   va_start(ap, en);
1609   v_report(1, NULL, 0, en, ap);
1610   va_end(ap);
1611}
1612
1613void
1614fatalerror(int en, ...)
1615{
1616   va_list ap;
1617   va_start(ap, en);
1618   v_report(2, NULL, 0, en, ap);
1619   va_end(ap);
1620}
1621
1622void
1623warning_in_file(const char *fnm, int line, int en, ...)
1624{
1625   va_list ap;
1626   va_start(ap, en);
1627   v_report(0, fnm, line, en, ap);
1628   va_end(ap);
1629}
1630
1631void
1632error_in_file(const char *fnm, int line, int en, ...)
1633{
1634   va_list ap;
1635   va_start(ap, en);
1636   v_report(1, fnm, line, en, ap);
1637   va_end(ap);
1638}
1639
1640void
1641fatalerror_in_file(const char *fnm, int line, int en, ...)
1642{
1643   va_list ap;
1644   va_start(ap, en);
1645   v_report(2, fnm, line, en, ap);
1646   va_end(ap);
1647}
1648
1649/* Code to support switching character set at runtime (e.g. for a printer
1650 * driver to support different character sets on screen and on the printer)
1651 */
1652typedef struct charset_li {
1653   struct charset_li *next;
1654   int code;
[55de792]1655   char **msg_array;
[db75e18]1656} charset_li;
1657
1658static charset_li *charset_head = NULL;
1659
1660static int charset = CHARSET_BAD;
1661
1662int
1663select_charset(int charset_code)
1664{
1665   int old_charset = charset;
1666   charset_li *p;
1667
[55de792]1668#ifdef DEBUG
[bd1913f]1669   fprintf(stderr, "select_charset(%d), old charset = %d\n", charset_code,
[421b7d2]1670           charset);
[55de792]1671#endif
[cb3d1e2]1672
[db75e18]1673   charset = charset_code;
1674
1675   /* check if we've already parsed messages for new charset */
1676   for (p = charset_head; p; p = p->next) {
[55de792]1677#ifdef DEBUG
1678      printf("%p: code %d msg_array %p\n", p, p->code, p->msg_array);
1679#endif
[db75e18]1680      if (p->code == charset) {
[421b7d2]1681         msg_array = p->msg_array;
1682         return old_charset;
[db75e18]1683      }
1684   }
1685
1686   /* nope, got to reparse message file */
1687   parse_msg_file(charset_code);
1688
1689   /* add to list */
1690   p = osnew(charset_li);
1691   p->code = charset;
[55de792]1692   p->msg_array = msg_array;
[db75e18]1693   p->next = charset_head;
1694   charset_head = p;
1695
1696   return old_charset;
1697}
Note: See TracBrowser for help on using the repository browser.