source: git/src/message.c @ bd41a28

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 bd41a28 was 54d6e7d, checked in by Olly Betts <olly@…>, 24 years ago

Break up "??)". It's an ANSI trigraph. It's harmless as it's only used in
comments, but it causes a compiler warning on Norcroft C.

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

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