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

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 6c0dc95 was 5e14c5f, checked in by Olly Betts <olly@…>, 23 years ago

(Unix version): running an installed program with an explicit path works
again.

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

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