source: git/src/message.c @ f6fe808

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 f6fe808 was 1e275f0, checked in by Olly Betts <olly@…>, 24 years ago

(RISC OS Version): fixed automatic detection of language.

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

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