source: git/src/message.c @ 804dfd9

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

aven: cleaned up plotting of crosses, special points, and highlighted points;
measuring line now snaps to the nearest point to the mouse pointer, not just
*a* point near the mouse pointer.

printps/printhpgl: Fixed --skip-blanks which would incorrectly skip non-blank
pages on rare occasions.

cavern: implemented "*units clino percent".

cavern: added error if the *units factor is zero (e.g. "*units tape 0 feet").

cavern: removed the ill-thought-out and never implemented LENGTHOUTPUT
and ANGLEOUTPUT quantities.

(Unix version): uninstalled binaries now use the path they are run with to
find support files, which means SURVEXHOME is no longer required, and has
been removed.

Rearranged messages a little to remove a few cavern messages in the middle
of the aven ones.

Removed a few needless inclusions of header files, and unused #define-s.

compile_error_skip() added to do compile_error() then skipline().

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

  • Property mode set to 100644
File size: 46.6 KB
Line 
1/* message.c
2 * Fairly general purpose message and error routines
3 * Copyright (C) 1993-2002 Olly Betts
4 *
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.
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
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
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
18 */
19
20/*#define DEBUG 1*/
21
22#ifdef HAVE_CONFIG_H
23# include <config.h>
24#endif
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>
32#include <locale.h>
33
34#include "whichos.h"
35#include "filename.h"
36#include "message.h"
37#include "osdepend.h"
38#include "filelist.h"
39#include "debug.h"
40
41#ifdef AVEN
42# include "aven.h"
43#endif
44
45#ifdef HAVE_SIGNAL
46# ifdef HAVE_SETJMP_H
47#  include <setjmp.h>
48static jmp_buf jmpbufSignal;
49#  include <signal.h>
50# else
51#  undef HAVE_SIGNAL
52# endif
53#endif
54
55#if (OS==WIN32)
56# include <windows.h>
57#elif (OS==MSDOS)
58#include <dos.h>
59# ifdef __DJGPP__
60#  include <dpmi.h>
61#  include <go32.h>
62#  include <sys/movedata.h>
63# endif
64#elif (OS==RISCOS)
65# include "oslib/wimpreadsy.h"
66# include "oslib/territory.h"
67#endif
68
69/* For funcs which want to be immune from messing around with different
70 * calling conventions */
71#ifndef CDECL
72# define CDECL
73#endif
74
75int msg_warnings = 0; /* keep track of how many warnings we've given */
76int msg_errors = 0;   /* and how many (non-fatal) errors */
77
78/* in case osmalloc() fails before appname_copy is set up */
79static const char *appname_copy = "anonymous program";
80
81/* error code for failed osmalloc and osrealloc calls */
82static void
83outofmem(OSSIZE_T size)
84{
85   fatalerror(/*Out of memory (couldn't find %lu bytes).*/1,
86              (unsigned long)size);
87}
88
89#ifdef TOMBSTONES
90#define TOMBSTONE_SIZE 16
91static const char tombstone[TOMBSTONE_SIZE] = "012345\xfftombstone";
92#endif
93
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 */
97void FAR *
98osmalloc(OSSIZE_T size)
99{
100   void FAR *p;
101#ifdef TOMBSTONES
102   size += TOMBSTONE_SIZE * 2;
103   p = malloc(size);
104#else
105   p = xosmalloc(size);
106#endif
107   if (p == NULL) outofmem(size);
108#ifdef TOMBSTONES
109   printf("osmalloc truep=%p truesize=%d\n", p, size);
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
115   return p;
116}
117
118/* realloc with error catching if it fails. */
119void FAR *
120osrealloc(void *p, OSSIZE_T size)
121{
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;
131      printf("osrealloc (in truep=%p truesize=%d)\n", p, true_size);
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!",
135                p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
136      }
137      if (memcmp(p + true_size - TOMBSTONE_SIZE, tombstone,
138                 TOMBSTONE_SIZE) != 0) {
139         printf("end tombstone for block %p, size %d corrupted!",
140                p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
141      }
142      p = realloc(p, size);
143      if (p == NULL) outofmem(size);
144      printf("osrealloc truep=%p truesize=%d\n", p, size);
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   }
153   if (p == NULL) outofmem(size);
154   return p;
155}
156
157char FAR *
158osstrdup(const char *str)
159{
160   char *p;
161   OSSIZE_T len;
162   len = strlen(str) + 1;
163   p = osmalloc(len);
164   memcpy(p, str, len);
165   return p;
166}
167
168/* osfree is usually just a macro in osalloc.h */
169#ifdef TOMBSTONES
170void
171osfree(void *p)
172{
173   int true_size;
174   if (!p) return;
175   p -= TOMBSTONE_SIZE;
176   true_size = *(size_t *)p;
177   printf("osfree truep=%p truesize=%d\n", p, true_size);
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!",
181             p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
182   }
183   if (memcmp(p + true_size - TOMBSTONE_SIZE, tombstone,
184              TOMBSTONE_SIZE) != 0) {
185      printf("end tombstone for block %p, size %d corrupted!",
186             p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
187   }
188   free(p);
189}
190#endif
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
199# define RETSIGTYPE void
200#endif
201
202static CDECL RETSIGTYPE FAR
203report_sig(int sig)
204{
205   sigReceived = sig;
206   longjmp(jmpbufSignal, 1);
207}
208
209static void
210init_signals(void)
211{
212   int en;
213   if (!setjmp(jmpbufSignal)) {
214#if 0 /* disable these to get a core dump */
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
220# ifdef SIGSTAK /* only on RISC OS AFAIK */
221      signal(SIGSTAK, report_sig); /* stack overflow */
222# endif
223      return;
224   }
225
226   switch (sigReceived) {
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;
231# ifdef SIGSTAK
232      case SIGSTAK: en = /*Stack overflow*/96; break;
233# endif
234      default:      en = /*Unknown signal received*/97; break;
235   }
236   fputsnl(msg(en), STDERR);
237
238   /* Any of the signals we catch indicates a bug */
239   fatalerror(/*Bug in program detected! Please report this to the authors*/11);
240
241   exit(EXIT_FAILURE);
242}
243#endif
244
245static int
246default_charset(void)
247{
248#if (OS==RISCOS)
249   /* RISCOS 3.1 and above CHARSET_RISCOS31 (ISO_8859_1 + extras in 128-159)
250    * RISCOS < 3.1 is ISO_8859_1 */
251   int version;
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;
259
260   return CHARSET_RISCOS31;
261#elif (OS==MSDOS)
262#ifdef __DJGPP__
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 */
272   if (__dpmi_int(0x21, &r) != -1 && !(r.x.flags & 1)) {
273      unsigned short p;
274      dosmemget(__tb + 5, 2, &p);
275#else
276   union REGS r;
277   struct SREGS s = { 0 };
278
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
290      if (p == 437) return CHARSET_DOSCP437;
291      if (p == 850) return CHARSET_DOSCP850;
292      if (p == 912) return CHARSET_ISO_8859_2;
293   }
294   return CHARSET_USASCII;
295#elif (OS==WIN32)
296# ifdef AVEN
297#  define CODEPAGE GetACP()
298# else
299#  define CODEPAGE GetConsoleOutputCP()
300# endif
301   switch (CODEPAGE) {
302    case 1252: return CHARSET_WINCP1252;
303    case 850: return CHARSET_DOSCP850;
304   }
305   return CHARSET_USASCII;
306#elif (OS==UNIX)
307#if defined(XCAVEROT) || defined(AVEN)
308   return CHARSET_ISO_8859_1;
309#else
310   const char *p = getenv("LC_ALL");
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
323   if (p) {
324      const char *chset = p;
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;
334
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;
342
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;
353                   case 2: return CHARSET_ISO_8859_2;
354                   case 15: return CHARSET_ISO_8859_15;
355                   default: return CHARSET_USASCII;
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'
376#endif
377}
378
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
385/* values <= 127 already dealt with */
386static int
387add_unicode(int charset, unsigned char *p, int value)
388{
389#ifdef DEBUG
390   fprintf(stderr, "add_unicode(%d, %p, %d)\n", charset, p, value);
391#endif
392   if (value == 0) return 0;
393   switch (charset) {
394   case CHARSET_USASCII:
395      if (value < 0x80) {
396         *p = value;
397         return 1;
398      }
399      break;
400   case CHARSET_ISO_8859_1:
401      if (value < 0x100) {
402         *p = value;
403         return 1;
404      }
405      break;
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;
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 */
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
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;
505#if (OS==RISCOS)
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; */
511#if 0
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; */
516#endif
517      }
518      if (value < 0x100) {
519         *p = value;
520         return 1;
521      }
522      break;
523#elif (OS==WIN32)
524   case CHARSET_WINCP1250:
525      /* MS Windows rough equivalent to ISO-8859-2 */
526      if (value >= 0x80) {
527         int v = 0;
528         switch (value) {
529            case 0xa0: case 0xa4: case 0xa6: case 0xa7: case 0xa8: case 0xa9:
530            case 0xab: case 0xac: case 0xad: case 0xae: case 0xb0: case 0xb1:
531            case 0xb4: case 0xb5: case 0xb6: case 0xb7: case 0xb8: case 0xbb:
532            case 0xc1: case 0xc2: case 0xc4: case 0xc7: case 0xc9: case 0xcb:
533            case 0xcd: case 0xce: case 0xd3: case 0xd4: case 0xd6: case 0xd7:
534            case 0xda: case 0xdc: case 0xdd: case 0xdf: case 0xe1: case 0xe2:
535            case 0xe4: case 0xe7: case 0xe9: case 0xeb: case 0xed: case 0xee:
536            case 0xf3: case 0xf4: case 0xf6: case 0xf7: case 0xfa: case 0xfc:
537            case 0xfd:
538               v = value; break;
539            case 0x20ac: v = '\x80'; break;
540            case 0x201a: v = '\x82'; break;
541            case 0x201e: v = '\x84'; break;
542            case 0x2026: v = '\x85'; break;
543            case 0x2020: v = '\x86'; break;
544            case 0x2021: v = '\x87'; break;
545            case 0x2030: v = '\x89'; break;
546            case 0x0160: v = '\x8a'; break;
547            case 0x2039: v = '\x8b'; break;
548            case 0x015a: v = '\x8c'; break;
549            case 0x0164: v = '\x8d'; break;
550            case 0x017d: v = '\x8e'; break;
551            case 0x0179: v = '\x8f'; break;
552            case 0x2018: v = '\x91'; break;
553            case 0x2019: v = '\x92'; break;
554            case 0x201c: v = '\x93'; break;
555            case 0x201d: v = '\x94'; break;
556            case 0x2022: v = '\x95'; break;
557            case 0x2013: v = '\x96'; break;
558            case 0x2014: v = '\x97'; break;
559            case 0x2122: v = '\x99'; break;
560            case 0x0161: v = '\x9a'; break;
561            case 0x203a: v = '\x9b'; break;
562            case 0x015b: v = '\x9c'; break;
563            case 0x0165: v = '\x9d'; break;
564            case 0x017e: v = '\x9e'; break;
565            case 0x017a: v = '\x9f'; break;
566            case 0x02c7: v = '\xa1'; break;
567            case 0x02d8: v = '\xa2'; break;
568            case 0x0141: v = '\xa3'; break;
569            case 0x0104: v = '\xa5'; break;
570            case 0x015e: v = '\xaa'; break;
571            case 0x017b: v = '\xaf'; break;
572            case 0x02db: v = '\xb2'; break;
573            case 0x0142: v = '\xb3'; break;
574            case 0x0105: v = '\xb9'; break;
575            case 0x015f: v = '\xba'; break;
576            case 0x013d: v = '\xbc'; break;
577            case 0x02dd: v = '\xbd'; break;
578            case 0x013e: v = '\xbe'; break;
579            case 0x017c: v = '\xbf'; break;
580            case 0x0154: v = '\xc0'; break;
581            case 0x0102: v = '\xc3'; break;
582            case 0x0139: v = '\xc5'; break;
583            case 0x0106: v = '\xc6'; break;
584            case 0x010c: v = '\xc8'; break;
585            case 0x0118: v = '\xca'; break;
586            case 0x011a: v = '\xcc'; break;
587            case 0x010e: v = '\xcf'; break;
588            case 0x0110: v = '\xd0'; break;
589            case 0x0143: v = '\xd1'; break;
590            case 0x0147: v = '\xd2'; break;
591            case 0x0150: v = '\xd5'; break;
592            case 0x0158: v = '\xd8'; break;
593            case 0x016e: v = '\xd9'; break;
594            case 0x0170: v = '\xdb'; break;
595            case 0x0162: v = '\xde'; break;
596            case 0x0155: v = '\xe0'; break;
597            case 0x0103: v = '\xe3'; break;
598            case 0x013a: v = '\xe5'; break;
599            case 0x0107: v = '\xe6'; break;
600            case 0x010d: v = '\xe8'; break;
601            case 0x0119: v = '\xea'; break;
602            case 0x011b: v = '\xec'; break;
603            case 0x010f: v = '\xef'; break;
604            case 0x0111: v = '\xf0'; break;
605            case 0x0144: v = '\xf1'; break;
606            case 0x0148: v = '\xf2'; break;
607            case 0x0151: v = '\xf5'; break;
608            case 0x0159: v = '\xf8'; break;
609            case 0x016f: v = '\xf9'; break;
610            case 0x0171: v = '\xfb'; break;
611            case 0x0163: v = '\xfe'; break;
612            case 0x02d9: v = '\xff'; break;
613         }
614         if (v = 0) break;
615         value = v;
616      }
617      *p = value;
618      return 1;
619   case CHARSET_WINCP1252:
620      /* MS Windows extensions to ISO-8859-1 */
621      switch (value) {
622       case 0x152: value = 0x8c; break; /* &OElig; */
623       case 0x153: value = 0x9c; break; /* &oelig; */
624#if 0
625      /* there are a few other obscure ones we don't currently need */
626#endif
627      }
628      if (value < 0x100) {
629         *p = value;
630         return 1;
631      }
632      break;
633#endif
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) {
651         int ch = (int)uni2dostab[value - 160];
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
690#if (OS==MSDOS || OS==WIN32)
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      }
710#if 0
711      if (value == 305) { /* LATIN SMALL LETTER DOTLESS I */
712         *p = 213;
713         return 1;
714      }
715      if (value == 402) { /* LATIN SMALL LETTER F WITH HOOK */
716         *p = 159;
717         return 1;
718      }
719#endif
720      break;
721   }
722#endif
723   }
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;
749    case 199 /* Ç */: case 268: /* &Ccaron; */
750      *p = 'C'; return 1;
751    case 270: /* &Dcaron; */
752      *p = 'D'; return 1;
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;
759    case 315: /* &Lacute; */
760      *p = 'L'; return 1;
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;
767    case 352: /* &Scaron; */
768      *p = 'S'; return 1;
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;
775    case 381: /* &Zcaron; */
776      *p = 'Z'; return 1;
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;
785    case 231 /* ç */: case 269 /* &ccaron; */:
786      *p = 'c'; return 1;
787    case 271: /* &dcaron; */
788      *p = 'd'; return 1;
789    case 232 /* è */: case 233 /* é */: case 234 /* ê */: case 235 /* ë */:
790    case 283 /* &ecaron; */:
791      *p = 'e'; return 1;
792    case 236 /* ì */: case 237 /* í */: case 238 /* î */: case 239 /* ï */:
793      *p = 'i'; return 1;
794    case 316 /* &lacute; */:
795      *p = 'l'; return 1;
796    case 241 /* ñ */: case 328 /* &ncaron; */:
797      *p = 'n'; return 1;
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;
804    case 240 /* ð */: case 254 /* þ */:
805      *p = 't'; p[1] = 'h'; return 2;
806    case 242 /* ò */: case 243 /* ó */: case 244 /* ô */: case 245 /* õ */:
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 /* û */:
811    case 367 /* &uring; */:
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;
817    case 382: /* &zcaron; */
818      *p = 'z'; return 1;
819   }
820#ifdef DEBUG
821   fprintf(stderr, "failed to transliterate\n");
822#endif
823   return 0;
824}
825
826#if (OS==UNIX) && defined(DATADIR) && defined(PACKAGE)
827/* Under Unix, we compile in the configured path */
828static const char *pth_cfg_files = DATADIR "/" PACKAGE;
829#else
830/* On other platforms, we fall back on looking in the current directory */
831static const char *pth_cfg_files = "";
832#endif
833
834static int num_msgs = 0;
835static char **msg_array = NULL;
836
837const char *msg_lang = NULL;
838const char *msg_lang2 = NULL;
839
840static char **
841parse_msgs(int n, unsigned char *p, int charset_code) {
842   int i;
843
844   char **msgs = osmalloc(n * sizeof(char *));
845
846   for (i = 0; i < n; i++) {
847      unsigned char *to = p;
848      int ch;
849      msgs[i] = (char *)p;
850
851      /* If we want UTF8 anyway, we just need to find the start of each
852       * message */
853      if (charset_code == CHARSET_UTF8) {
854         p += strlen((char *)p) + 1;
855         continue;
856      }
857
858      while ((ch = *p++) != 0) {
859         /* A byte in the range 0x80-0xbf or 0xf0-0xff isn't valid in
860          * this state, (0xf0-0xfd mean values > 0xffff) so treat as
861          * literal and try to resync so we cope better when fed
862          * non-utf-8 data.  Similarly we abandon a multibyte sequence
863          * if we hit an invalid character. */
864         if (ch >= 0xc0 && ch < 0xf0) {
865            int ch1 = *p;
866            if ((ch1 & 0xc0) != 0x80) goto resync;
867
868            if (ch < 0xe0) {
869               /* 2 byte sequence */
870               ch = ((ch & 0x1f) << 6) | (ch1 & 0x3f);
871               p++;
872            } else {
873               /* 3 byte sequence */
874               int ch2 = p[1];
875               if ((ch2 & 0xc0) != 0x80) goto resync;
876               ch = ((ch & 0x1f) << 12) | ((ch1 & 0x3f) << 6) | (ch2 & 0x3f);
877               p += 2;
878            }
879         }
880
881         resync:
882
883         if (ch < 127) {
884            *to++ = (char)ch;
885         } else {
886            /* We assume an N byte UTF-8 code never transliterates to more
887             * than N characters (so we can't transliterate © to (C) or
888             * ® to (R) for example) */
889            to += add_unicode(charset_code, to, ch);
890         }
891      }
892      *to++ = '\0';
893   }
894   return msgs;
895}
896
897/* This is the name of the default language, which can be set like so:
898 * ./configure --enable-defaultlang=fr
899 */
900#ifdef DEFAULTLANG
901/* No point extracting these errors as they won't get used if file opens */
902# include "../lib/defaultlang.h"
903#else
904#define N_DONTEXTRACTMSGS 5
905static unsigned char dontextractmsgs[] =
906   "Can't open message file `%s' using path `%s'\0"/*1000*/
907   "Problem with message file `%s'\0"/*1001*/
908   "I don't understand this message file version\0"/*1002*/
909   "Message file truncated?\0"/*1003*/
910   "Out of memory (couldn't find %lu bytes).\0"/*1004*/;
911#endif
912
913static char **dontextract = NULL;
914
915static void
916parse_msg_file(int charset_code)
917{
918   FILE *fh;
919   unsigned char header[20];
920   int i;
921   unsigned len;
922   unsigned char *p;
923   char *fnm, *s;
924   int n;
925
926#ifdef DEBUG
927   fprintf(stderr, "parse_msg_file(%d)\n", charset_code);
928#endif
929
930   /* sort out messages we need to print if we can't open the message file */
931   dontextract = parse_msgs(N_DONTEXTRACTMSGS, dontextractmsgs, charset_code);
932
933   fnm = osstrdup(msg_lang);
934   /* trim off charset from stuff like "de_DE.iso8859_1" */
935   s = strchr(fnm, '.');
936   if (s) *s = '\0';
937
938   fh = fopenWithPthAndExt(pth_cfg_files, fnm, EXT_SVX_MSG, "rb", NULL);
939
940   if (!fh) {
941      /* e.g. if 'en_GB' is unknown, see if we know 'en' */
942      if (strlen(fnm) > 3 && fnm[2] == '_') {
943         fnm[2] = '\0';
944         fh = fopenWithPthAndExt(pth_cfg_files, fnm, EXT_SVX_MSG, "rb", NULL);
945         if (!fh) fnm[2] = '_'; /* for error reporting */
946      }
947   }
948
949   if (!fh) {
950      fatalerror(/*Can't open message file `%s' using path `%s'*/1000,
951                 fnm, pth_cfg_files);
952   }
953
954   if (fread(header, 1, 20, fh) < 20 ||
955       memcmp(header, "Svx\nMsg\r\n\xfe\xff", 12) != 0) {
956      fatalerror(/*Problem with message file `%s'*/1001, fnm);
957   }
958
959   if (header[12] != 0)
960      fatalerror(/*I don't understand this message file version*/1002);
961
962   n = (header[14] << 8) | header[15];
963
964   len = 0;
965   for (i = 16; i < 20; i++) len = (len << 8) | header[i];
966
967   p = osmalloc(len);
968   if (fread(p, 1, len, fh) < len)
969      fatalerror(/*Message file truncated?*/1003);
970
971   fclose(fh);
972
973#ifdef DEBUG
974   fprintf(stderr, "fnm = `%s', n = %d, len = %d\n", fnm, n, len);
975#endif
976   osfree(fnm);
977
978   msg_array = parse_msgs(n, p, charset_code);
979   num_msgs = n;
980}
981
982const char *
983msg_cfgpth(void)
984{
985   return pth_cfg_files;
986}
987
988const char *
989msg_appname(void)
990{
991   return appname_copy;
992}
993
994void
995msg_init(char * const *argv)
996{
997   char *p;
998   ASSERT(argv);
999
1000#ifdef HAVE_SIGNAL
1001   init_signals();
1002#endif
1003   /* Point to argv[0] itself so we report a more helpful error if the
1004    * code to work out the clean appname generates a signal */
1005   appname_copy = argv[0];
1006#if (OS == UNIX)
1007   /* use name as-is on Unix - programs run from path get name as supplied */
1008   appname_copy = osstrdup(argv[0]);
1009#else
1010   /* use the lower-cased leafname on other platforms */
1011   appname_copy = p = leaf_from_fnm(argv[0]);
1012   while (*p) {
1013      *p = tolower(*p);
1014      p++;
1015   }
1016#endif
1017
1018   /* shortcut --version so you can check the version number when the correct
1019    * message file can't be found... */
1020   if (argv[1] && strcmp(argv[1], "--version") == 0) {
1021      cmdline_version();
1022      exit(0);
1023   }
1024
1025   if (argv[0]) {
1026#if (OS==UNIX) && defined(DATADIR) && defined(PACKAGE)
1027      char *pth = path_from_fnm(argv[0]);
1028      if (pth[0]) {
1029         /* If we're run with an explicit path, check if "../lib" from
1030          * the program's path is a directory, and if so look there for
1031          * support files - this allows us to test binaries in the build
1032          * tree easily. */
1033         /* May also be useful on MacOS X where the programs may be
1034          * installed anywhere... */
1035         char *p = use_path(pth, "../lib");
1036         if (fDirectory(p)) {
1037            pth_cfg_files = p;
1038         } else {
1039            osfree(p);
1040         }
1041      }
1042      osfree(pth);
1043#else
1044      /* Get the path to the support files from argv[0] */
1045      pth_cfg_files = path_from_fnm(argv[0]);
1046#endif
1047   }
1048
1049   msg_lang = getenv("SURVEXLANG");
1050#ifdef DEBUG
1051   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang, msg_lang?msg_lang:"(null)");
1052#endif
1053
1054   if (!msg_lang || !*msg_lang) {
1055      msg_lang = getenv("LANG");
1056      if (!msg_lang || !*msg_lang) {
1057#if (OS==WIN32)
1058         LCID locid;
1059#elif (OS==RISCOS)
1060         territory_t t;
1061#endif
1062#ifdef DEFAULTLANG
1063         msg_lang = STRING(DEFAULTLANG);
1064#else
1065         msg_lang = "en";
1066#endif
1067#if (OS==WIN32)
1068         locid = GetUserDefaultLCID();
1069         if (locid) {
1070            WORD langid = LANGIDFROMLCID(locid);
1071            switch (PRIMARYLANGID(langid)) {
1072/* older mingw compilers don't seem to supply this value */
1073#ifndef LANG_CATALAN
1074# define LANG_CATALAN 0x03
1075#endif
1076             case LANG_CATALAN:
1077               msg_lang = "ca";
1078               break;
1079             case LANG_ENGLISH:
1080               if (SUBLANGID(langid) == SUBLANG_ENGLISH_US)
1081                  msg_lang = "en_US";
1082               else
1083                  msg_lang = "en";
1084               break;
1085             case LANG_FRENCH:
1086               msg_lang = "fr";
1087               break;
1088             case LANG_GERMAN:
1089               switch (SUBLANGID(langid)) {
1090                case SUBLANG_GERMAN_SWISS:
1091                  msg_lang = "de_CH";
1092                  break;
1093                case SUBLANG_GERMAN:
1094                  msg_lang = "de_DE";
1095                  break;
1096                default:
1097                  msg_lang = "de";
1098               }
1099               break;
1100             case LANG_ITALIAN:
1101               msg_lang = "it";
1102               break;
1103             case LANG_PORTUGUESE:
1104               if (SUBLANGID(langid) == SUBLANG_PORTUGUESE_BRAZILIAN)
1105                  msg_lang = "pt_BR";
1106               else
1107                  msg_lang = "pt";
1108               break;
1109             case LANG_SLOVAK:
1110               msg_lang = "sk";
1111               break;
1112             case LANG_SPANISH:
1113               msg_lang = "es";
1114               break;
1115            }
1116         }
1117#elif (OS==RISCOS)
1118         if (!xterritory_number(&t)) switch (t) {
1119          case 1: /* UK */
1120          case 2: /* Master */
1121          case 3: /* Compact */
1122          case 17: /* Canada1 */
1123          case 19: /* Canada */
1124          case 22: /* Ireland */
1125            msg_lang = "en";
1126            break;
1127          case 4: /* Italy */
1128            msg_lang = "it";
1129            break;
1130          case 5: /* Spain (or ca) */
1131          case 27: /* Mexico */
1132          case 28: /* LatinAm (or pt_BR) */
1133            msg_lang = "es";
1134            break;
1135          case 6: /* France */
1136          case 18: /* Canada2 */
1137            msg_lang = "fr";
1138            break;
1139          case 7: /* Germany */
1140            msg_lang = "de_DE";
1141            break;
1142          case 8: /* Portugal */
1143            msg_lang = "pt";
1144            break;
1145          case 48: /* USA */
1146            msg_lang = "en_US";
1147            break;
1148#if 0
1149          case 9: /* Esperanto */
1150          case 10: /* Greece */
1151          case 11: /* Sweden */
1152          case 12: /* Finland */
1153          case 13: /* Unused */
1154          case 14: /* Denmark */
1155          case 15: /* Norway */
1156          case 16: /* Iceland */
1157          case 20: /* Turkey */
1158          case 21: /* Arabic */
1159          case 23: /* Hong Kong */
1160          case 24: /* Russia */
1161          case 25: /* Russia2 */
1162          case 26: /* Israel */
1163#endif
1164         }
1165#elif (OS==MSDOS)
1166           {
1167              int country_code;
1168# ifdef __DJGPP__
1169              __dpmi_regs r;
1170              r.x.ax = 0x6501;
1171              r.x.bx = 0xffff;
1172              r.x.dx = 0xffff;
1173              /* Use DJGPP's transfer buffer (which is at least 2K) */
1174              r.x.es = __tb >> 4;
1175              r.x.di = __tb & 0x0f;
1176              r.x.cx = 2048;
1177              /* bit 1 is the carry flag */
1178              if (__dpmi_int(0x21, &r) != -1 && !(r.x.flags & 1)) {
1179                 unsigned short p;
1180                 dosmemget(__tb + 3, 2, &p);
1181                 country_code = p;
1182# else
1183              union REGS r;
1184              r.x.ax = 0x3800; /* get current country info */
1185              r.x.dx = 0;
1186              intdos(&r, &r);
1187              if (!r.x.cflag) {
1188                 country_code = r.x.bx;
1189# endif
1190                 /* List of country codes taken from:
1191                  * http://www.delorie.com/djgpp/doc/rbinter/it/00/14.html */
1192                 /* The mappings here are guesses at best in most cases.
1193                  * In a lot of cases we pick a language because we have
1194                  * a translation in it, rather than because it's the most
1195                  * widely used or understood in that country. */
1196                 /* Improvements welcome */
1197                 switch (country_code) {
1198                     case 1: /* United States */
1199                     case 670: /* Saipan / N. Mariana Island */
1200                     case 671: /* Guam */
1201                     case 680: /* Palau */
1202                     case 684: /* American Samoa */
1203                     case 691: /* Micronesia */
1204                     case 692: /* Marshall Islands */
1205                         msg_lang = "en_US";
1206                         break;
1207                     case 4: /* Canada (English) */
1208                     case 27: /* South Africa */
1209                     case 44: /* United Kingdom */
1210                     case 61: /* International English / Australia */
1211                     case 64: /* New Zealand */
1212                     case 99: /* Asia (English) */
1213                     case 220: /* Gambia */
1214                     case 231: /* Liberia */
1215                     case 232: /* Sierra Leone */
1216                     case 233: /* Ghana */
1217                     case 254: /* Kenya */
1218                     case 256: /* Uganda */
1219                     case 260: /* Zambia */
1220                     case 263: /* Zimbabwe */
1221                     case 264: /* Namibia */
1222                     case 267: /* Botswana */
1223                     case 268: /* Swaziland */
1224                     case 290: /* St. Helena */
1225                     case 297: /* Aruba */
1226                     case 350: /* Gibraltar */
1227                     case 353: /* Ireland */
1228                     case 356: /* Malta */
1229                     case 500: /* Falkland Islands */
1230                     case 501: /* Belize */
1231                     case 592: /* Guyana */
1232                     case 672: /* Norfolk Island (Australia) / Christmas Island/Cocos Islands / Antartica */
1233                     case 673: /* Brunei Darussalam */
1234                     case 674: /* Nauru */
1235                     case 675: /* Papua New Guinea */
1236                     case 676: /* Tonga Islands */
1237                     case 677: /* Solomon Islands */
1238                     case 679: /* Fiji */
1239                     case 682: /* Cook Islands */
1240                     case 683: /* Niue */
1241                     case 685: /* Western Samoa */
1242                     case 686: /* Kiribati */
1243                         /* I believe only some of these are English speaking... */
1244                     case 809: /* Antigua and Barbuda / Anguilla / Bahamas / Barbados / Bermuda
1245                                  British Virgin Islands / Cayman Islands / Dominica
1246                                  Dominican Republic / Grenada / Jamaica / Montserra
1247                                  St. Kitts and Nevis / St. Lucia / St. Vincent and Grenadines
1248                                  Trinidad and Tobago / Turks and Caicos */
1249                         msg_lang = "en";
1250                         break;
1251                     case 2: /* Canadian-French */
1252                     case 32: /* Belgium */ /* maybe */
1253                     case 33: /* France */
1254                     case 213: /* Algeria */
1255                     case 216: /* Tunisia */
1256                     case 221: /* Senegal */
1257                     case 223: /* Mali */
1258                     case 225: /* Ivory Coast */
1259                     case 226: /* Burkina Faso */
1260                     case 227: /* Niger */
1261                     case 228: /* Togo */
1262                     case 229: /* Benin */
1263                     case 230: /* Mauritius */
1264                     case 235: /* Chad */
1265                     case 236: /* Central African Republic */
1266                     case 237: /* Cameroon */
1267                     case 241: /* Gabon */
1268                     case 242: /* Congo */
1269                     case 250: /* Rwhanda */
1270                     case 253: /* Djibouti */
1271                     case 257: /* Burundi */
1272                     case 261: /* Madagascar */
1273                     case 262: /* Reunion Island */
1274                     case 269: /* Comoros */
1275                     case 270: /* Mayotte */
1276                     case 352: /* Luxembourg (or de or ...) */
1277                     case 508: /* St. Pierre and Miquelon */
1278                     case 509: /* Haiti */
1279                     case 590: /* Guadeloupe */
1280                     case 594: /* French Guiana */
1281                     case 596: /* Martinique / French Antilles */
1282                     case 678: /* Vanuatu */
1283                     case 681: /* Wallis & Futuna */
1284                     case 687: /* New Caledonia */
1285                     case 689: /* French Polynesia */
1286                     case 961: /* Lebanon */
1287                         msg_lang = "fr";
1288                         break;
1289                     case 3: /* Latin America */
1290                     case 34: /* Spain */
1291                     case 51: /* Peru */
1292                     case 52: /* Mexico */
1293                     case 53: /* Cuba */
1294                     case 54: /* Argentina */
1295                     case 56: /* Chile */
1296                     case 57: /* Columbia */
1297                     case 58: /* Venezuela */
1298                     case 63: /* Philippines */
1299                     case 240: /* Equatorial Guinea */
1300                     case 502: /* Guatemala */
1301                     case 503: /* El Salvador */
1302                     case 504: /* Honduras */
1303                     case 505: /* Nicraragua */
1304                     case 506: /* Costa Rica */
1305                     case 507: /* Panama */
1306                     case 591: /* Bolivia */
1307                     case 593: /* Ecuador */
1308                     case 595: /* Paraguay */
1309                     case 598: /* Uruguay */
1310                         msg_lang = "es";
1311                         break;
1312                     case 39: /* Italy / San Marino / Vatican City */
1313                         msg_lang = "it";
1314                         break;
1315                     case 41: /* Switzerland / Liechtenstein */ /* or fr or ... */
1316                         msg_lang = "de_CH";
1317                         break;
1318                     case 43: /* Austria (DR DOS 5.0) */
1319                         msg_lang = "de";
1320                         break;
1321                     case 49: /* Germany */
1322                         msg_lang = "de_DE";
1323                         break;
1324                     case 55: /* Brazil (not supported by DR DOS 5.0) */
1325                         msg_lang = "pt_BR";
1326                         break;
1327                     case 238: /* Cape Verde Islands */
1328                     case 244: /* Angola */
1329                     case 245: /* Guinea-Bissau */
1330                     case 259: /* Mozambique */
1331                     case 351: /* Portugal */
1332                         msg_lang = "pt";
1333                         break;
1334                     case 42: /* Czechoslovakia / Tjekia / Slovakia (not supported by DR DOS 5.0) */
1335                     case 421: /* Czech Republic / Tjekia (PC DOS 7+) */
1336                     case 422: /* Slovakia (reported as 421 due to a bug in COUNTRY.SYS) */
1337                         msg_lang = "sk";
1338                         break;
1339#if 0
1340                     case 7: /* Russia */
1341                     case 20: /* Egypt */
1342                     case 30: /* Greece */
1343                     case 31: /* Netherlands */
1344                     case 35: /* Bulgaria??? */
1345                     case 36: /* Hungary (not supported by DR DOS 5.0) */
1346                     case 38: /* Yugoslavia (not supported by DR DOS 5.0) -- obsolete */
1347                     case 40: /* Romania */
1348                     case 45: /* Denmark */
1349                     case 46: /* Sweden */
1350                     case 47: /* Norway */
1351                     case 48: /* Poland (not supported by DR DOS 5.0) */
1352                     case 60: /* Malaysia */
1353                     case 62: /* Indonesia / East Timor */
1354                     case 65: /* Singapore */
1355                     case 66: /* Thailand (or Taiwan??? ) */
1356                     case 81: /* Japan (DR DOS 5.0, MS-DOS 5.0+) */
1357                     case 82: /* South Korea (DR DOS 5.0) */
1358                     case 84: /* Vietnam */
1359                     case 86: /* China (MS-DOS 5.0+) */
1360                     case 88: /* Taiwan (MS-DOS 5.0+) */
1361                     case 90: /* Turkey (MS-DOS 5.0+) */
1362                     case 91: /* India */
1363                     case 92: /* Pakistan */
1364                     case 93: /* Afghanistan */
1365                     case 94: /* Sri Lanka */
1366                     case 98: /* Iran */
1367                     case 102: /* ??? (Hebrew MS-DOS 5.0) */
1368                     case 112: /* Belarus */
1369                     case 200: /* Thailand (PC DOS 6.1+) (reported as 01due to a bug in PC DOS COUNTRY.SYS) */
1370                     case 212: /* Morocco */
1371                     case 218: /* Libya */
1372                     case 222: /* Maruitania */
1373                     case 224: /* African Guinea */
1374                     case 234: /* Nigeria */
1375                     case 239: /* Sao Tome and Principe */
1376                     case 243: /* Zaire */
1377                     case 246: /* Diego Garcia */
1378                     case 247: /* Ascension Isle */
1379                     case 248: /* Seychelles */
1380                     case 249: /* Sudan */
1381                     case 251: /* Ethiopia */
1382                     case 252: /* Somalia */
1383                     case 255: /* Tanzania */
1384                     case 265: /* Malawi */
1385                     case 266: /* Lesotho */
1386                     case 298: /* Faroe Islands */
1387                     case 299: /* Greenland */
1388                     case 354: /* Iceland */
1389                     case 355: /* Albania */
1390                     case 357: /* Cyprus */
1391                     case 358: /* Finland */
1392                     case 359: /* Bulgaria */
1393                     case 370: /* Lithuania (reported as 372 due to a bug in MS-DOS COUNTRY.SYS) */
1394                     case 371: /* Latvia (reported as 372 due to a bug in MS-DOS COUNTRY.SYS) */
1395                     case 372: /* Estonia */
1396                     case 373: /* Moldova */
1397                     case 375: /* ??? (MS-DOS 7.10 / Windows98) */
1398                     case 380: /* Ukraine */
1399                     case 381: /* Serbia / Montenegro */
1400                     case 384: /* Croatia */
1401                     case 385: /* Croatia (PC DOS 7+) */
1402                     case 386: /* Slovenia */
1403                     case 387: /* Bosnia-Herzegovina (Latin) */
1404                     case 388: /* Bosnia-Herzegovina (Cyrillic) (PC DOS 7+) (reported as 381 due to a bug in PC DOS COUNTRY.SYS) */
1405                     case 389: /* FYR Macedonia */
1406                     case 597: /* Suriname (nl) */
1407                     case 599: /* Netherland Antilles (nl) */
1408                     case 666: /* Russia??? (PTS-DOS 6.51 KEYB) */
1409                     case 667: /* Poland??? (PTS-DOS 6.51 KEYB) */
1410                     case 668: /* Poland??? (Slavic??? ) (PTS-DOS 6.51 KEYB) */
1411                     case 688: /* Tuvalu */
1412                     case 690: /* Tokealu */
1413                     case 711: /* ??? (currency = EA$, code pages 437,737,850,852,855,857) */
1414                     case 785: /* Arabic (Middle East/Saudi Arabia/etc.) */
1415                     case 804: /* Ukraine */
1416                     case 850: /* North Korea */
1417                     case 852: /* Hong Kong */
1418                     case 853: /* Macao */
1419                     case 855: /* Cambodia */
1420                     case 856: /* Laos */
1421                     case 880: /* Bangladesh */
1422                     case 886: /* Taiwan (MS-DOS 6.22+) */
1423                     case 960: /* Maldives */
1424                     case 962: /* Jordan */
1425                     case 963: /* Syria / Syrian Arab Republic */
1426                     case 964: /* Iraq */
1427                     case 965: /* Kuwait */
1428                     case 966: /* Saudi Arabia */
1429                     case 967: /* Yemen */
1430                     case 968: /* Oman */
1431                     case 969: /* Yemen??? (Arabic MS-DOS 5.0) */
1432                     case 971: /* United Arab Emirates */
1433                     case 972: /* Israel (Hebrew) (DR DOS 5.0,MS-DOS 5.0+) */
1434                     case 973: /* Bahrain */
1435                     case 974: /* Qatar */
1436                     case 975: /* Bhutan */
1437                     case 976: /* Mongolia */
1438                     case 977: /* Nepal */
1439                     case 995: /* Myanmar (Burma) */
1440#endif
1441                 }
1442              }
1443           }
1444#endif
1445      }
1446   }
1447#ifdef DEBUG
1448   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang, msg_lang?msg_lang:"(null)");
1449#endif
1450
1451   /* On Mandrake LANG defaults to C */
1452   if (strcmp(msg_lang, "C") == 0) msg_lang = "en";
1453
1454   msg_lang = osstrdup(msg_lang);
1455
1456   /* Convert en-us to en_US, etc */
1457   p = strchr(msg_lang, '-');
1458   if (p) {
1459      *p++ = '_';
1460      while (*p) {
1461         *p = toupper(*p);
1462         p++;
1463      }
1464   }
1465
1466   p = strchr(msg_lang, '_');
1467   if (p) {
1468      *p = '\0';
1469      msg_lang2 = osstrdup(msg_lang);
1470      *p = '_';
1471   }
1472
1473#ifdef LC_MESSAGES
1474   /* try to setlocale() appropriately too */
1475   if (!setlocale(LC_MESSAGES, msg_lang)) {
1476      if (msg_lang2) setlocale(LC_MESSAGES, msg_lang2);
1477   }
1478#endif
1479
1480   select_charset(default_charset());
1481}
1482
1483/* Message may be overwritten by next call
1484 * (but not in current implementation) */
1485const char *
1486msg(int en)
1487{
1488   /* NB can't use ASSERT here! */
1489   static char badbuf[256];
1490   if (en >= 1000 && en < 1000 + N_DONTEXTRACTMSGS)
1491      return dontextract[en - 1000];
1492   if (!msg_array) {
1493      if (en != 1)  {
1494         sprintf(badbuf, "Message %d requested before msg_array initialised\n", en);
1495         return badbuf;
1496      }
1497      /* this should be the only other message which can be requested before
1498       * the message file is opened and read... */
1499      if (!dontextract) return "Out of memory (couldn't find %lu bytes).";
1500      return dontextract[(/*Out of memory (couldn't find %lu bytes).*/1004)
1501                         - 1000];
1502   }
1503
1504   if (en < 0 || en >= num_msgs) {
1505      sprintf(badbuf, "Message %d out of range\n", en);
1506      return badbuf;
1507   }
1508
1509   if (en == 0) {
1510      const char *p = msg_array[0];
1511      if (!*p) p = "(C)";
1512      return p;
1513   }
1514
1515   return msg_array[en];
1516}
1517
1518/* returns persistent copy of message */
1519const char *
1520msgPerm(int en)
1521{
1522   return msg(en);
1523}
1524
1525void
1526v_report(int severity, const char *fnm, int line, int en, va_list ap)
1527{
1528#ifdef AVEN
1529   aven_v_report(severity, fnm, line, en, ap);
1530#else
1531   if (fnm) {
1532      fputs(fnm, STDERR);
1533      if (line) fprintf(STDERR, ":%d", line);
1534   } else {
1535      fputs(appname_copy, STDERR);
1536   }
1537   fputs(": ", STDERR);
1538
1539   if (severity == 0) {
1540      fputs(msg(/*warning*/4), STDERR);
1541      fputs(": ", STDERR);
1542   }
1543
1544   vfprintf(STDERR, msg(en), ap);
1545   fputnl(STDERR);
1546#endif
1547
1548   switch (severity) {
1549    case 0:
1550      msg_warnings++;
1551      break;
1552    case 1:
1553      msg_errors++;
1554      if (msg_errors == 50)
1555         fatalerror_in_file(fnm, 0, /*Too many errors - giving up*/19);
1556      break;
1557    case 2:
1558      exit(EXIT_FAILURE);
1559   }
1560}
1561
1562void
1563warning(int en, ...)
1564{
1565   va_list ap;
1566   va_start(ap, en);
1567   v_report(0, NULL, 0, en, ap);
1568   va_end(ap);
1569}
1570
1571void
1572error(int en, ...)
1573{
1574   va_list ap;
1575   va_start(ap, en);
1576   v_report(1, NULL, 0, en, ap);
1577   va_end(ap);
1578}
1579
1580void
1581fatalerror(int en, ...)
1582{
1583   va_list ap;
1584   va_start(ap, en);
1585   v_report(2, NULL, 0, en, ap);
1586   va_end(ap);
1587}
1588
1589void
1590warning_in_file(const char *fnm, int line, int en, ...)
1591{
1592   va_list ap;
1593   va_start(ap, en);
1594   v_report(0, fnm, line, en, ap);
1595   va_end(ap);
1596}
1597
1598void
1599error_in_file(const char *fnm, int line, int en, ...)
1600{
1601   va_list ap;
1602   va_start(ap, en);
1603   v_report(1, fnm, line, en, ap);
1604   va_end(ap);
1605}
1606
1607void
1608fatalerror_in_file(const char *fnm, int line, int en, ...)
1609{
1610   va_list ap;
1611   va_start(ap, en);
1612   v_report(2, fnm, line, en, ap);
1613   va_end(ap);
1614}
1615
1616/* Code to support switching character set at runtime (e.g. for a printer
1617 * driver to support different character sets on screen and on the printer)
1618 */
1619typedef struct charset_li {
1620   struct charset_li *next;
1621   int code;
1622   char **msg_array;
1623} charset_li;
1624
1625static charset_li *charset_head = NULL;
1626
1627static int charset = CHARSET_BAD;
1628
1629int
1630select_charset(int charset_code)
1631{
1632   int old_charset = charset;
1633   charset_li *p;
1634
1635#ifdef DEBUG
1636   fprintf(stderr, "select_charset(%d), old charset = %d\n", charset_code,
1637           charset);
1638#endif
1639
1640   charset = charset_code;
1641
1642   /* check if we've already parsed messages for new charset */
1643   for (p = charset_head; p; p = p->next) {
1644#ifdef DEBUG
1645      printf("%p: code %d msg_array %p\n", p, p->code, p->msg_array);
1646#endif
1647      if (p->code == charset) {
1648         msg_array = p->msg_array;
1649         return old_charset;
1650      }
1651   }
1652
1653   /* nope, got to reparse message file */
1654   parse_msg_file(charset_code);
1655
1656   /* add to list */
1657   p = osnew(charset_li);
1658   p->code = charset;
1659   p->msg_array = msg_array;
1660   p->next = charset_head;
1661   charset_head = p;
1662
1663   return old_charset;
1664}
Note: See TracBrowser for help on using the repository browser.