source: git/src/message.c @ ab27074

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

Added Slovak i18n.

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

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