source: git/src/message.c @ 2001db9

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

Vastly improved msg.pl script for extracting messages from source code.
Compared its output to message file and fixed up discrepancies.

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

  • Property mode set to 100644
File size: 39.3 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   }
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     
829   /* MacOSX version can be installed anywhere, so use argv[0] */
830#if (OS==UNIX) && defined(DATADIR) && defined(PACKAGE) && !defined(__APPLE__)
831   } else {
832      /* under Unix, we compile in the configured path */
833      pth_cfg_files = DATADIR "/" PACKAGE;
834#else
835   } else if (argv[0]) {
836      /* else try the path on argv[0] */
837      pth_cfg_files = path_from_fnm(argv[0]);
838#endif
839   }
840
841   msg_lang = getenv("SURVEXLANG");
842#ifdef DEBUG
843   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang, msg_lang?msg_lang:"(null)");
844#endif
845
846   if (!msg_lang || !*msg_lang) {
847      msg_lang = getenv("LANG");
848      if (!msg_lang || !*msg_lang) {
849#if (OS==WIN32)
850         LCID locid;
851#elif (OS==RISCOS)
852         territory_t t;
853#endif
854#ifdef DEFAULTLANG
855         msg_lang = STRING(DEFAULTLANG);
856#else
857         msg_lang = "en";
858#endif
859#if (OS==WIN32)
860         locid = GetUserDefaultLCID();
861         if (locid) {
862            WORD langid = LANGIDFROMLCID(locid);
863            switch (PRIMARYLANGID(langid)) {
864/* older mingw compilers don't seem to supply this value */
865#ifndef LANG_CATALAN
866# define LANG_CATALAN 0x03
867#endif
868             case LANG_CATALAN:
869               msg_lang = "ca";
870               break;
871             case LANG_ENGLISH:
872               if (SUBLANGID(langid) == SUBLANG_ENGLISH_US)
873                  msg_lang = "en_US";
874               else
875                  msg_lang = "en";
876               break;
877             case LANG_FRENCH:
878               msg_lang = "fr";
879               break;
880             case LANG_GERMAN:
881               switch (SUBLANGID(langid)) {
882                case SUBLANG_GERMAN_SWISS:
883                  msg_lang = "de_CH";
884                  break;
885                case SUBLANG_GERMAN:
886                  msg_lang = "de_DE";
887                  break;
888                default:
889                  msg_lang = "de";
890               }
891               break;
892             case LANG_ITALIAN:
893               msg_lang = "it";
894               break;
895             case LANG_PORTUGUESE:
896               if (SUBLANGID(langid) == SUBLANG_PORTUGUESE_BRAZILIAN)
897                  msg_lang = "pt_BR";
898               else
899                  msg_lang = "pt";
900               break;
901             case LANG_SPANISH:
902               msg_lang = "es";
903               break;
904            }
905         }
906#elif (OS==RISCOS)
907         if (!xterritory_number(&t)) switch (t) {
908          case 1: /* UK */
909          case 2: /* Master */
910          case 3: /* Compact */
911          case 17: /* Canada1 */
912          case 19: /* Canada */
913          case 22: /* Ireland */
914            msg_lang = "en";
915            break;
916          case 4: /* Italy */
917            msg_lang = "it";
918            break;
919          case 5: /* Spain (or ca) */
920          case 27: /* Mexico */
921          case 28: /* LatinAm (or pt_BR) */
922            msg_lang = "es";
923            break;
924          case 6: /* France */
925          case 18: /* Canada2 */
926            msg_lang = "fr";
927            break;
928          case 7: /* Germany */
929            msg_lang = "de_DE";
930            break;
931          case 8: /* Portugal */
932            msg_lang = "pt";
933            break;
934          case 48: /* USA */
935            msg_lang = "en_US";
936            break;
937#if 0
938          case 9: /* Esperanto */
939          case 10: /* Greece */
940          case 11: /* Sweden */
941          case 12: /* Finland */
942          case 13: /* Unused */
943          case 14: /* Denmark */
944          case 15: /* Norway */
945          case 16: /* Iceland */
946          case 20: /* Turkey */
947          case 21: /* Arabic */
948          case 23: /* Hong Kong */
949          case 24: /* Russia */
950          case 25: /* Russia2 */
951          case 26: /* Israel */
952#endif
953         }
954#elif (OS==MSDOS)
955           {
956              int country_code;
957# ifdef __DJGPP__
958              __dpmi_regs r;
959              r.x.ax = 0x6501;
960              r.x.bx = 0xffff;
961              r.x.dx = 0xffff;
962              /* Use DJGPP's transfer buffer (which is at least 2K) */
963              r.x.es = __tb >> 4;
964              r.x.di = __tb & 0x0f;
965              r.x.cx = 2048;
966              /* bit 1 is the carry flag */
967              if (__dpmi_int(0x21, &r) != -1 && !(r.x.flags & 1)) {
968                 unsigned short p;
969                 dosmemget(__tb + 3, 2, &p);
970                 country_code = p;
971# else
972              union REGS r;
973              r.x.ax = 0x3800; /* get current country info */
974              r.x.dx = 0;
975              intdos(&r, &r);
976              if (!r.x.cflag) {
977                 country_code = r.x.bx;
978# endif
979                 /* List of country codes taken from:
980                  * http://www.delorie.com/djgpp/doc/rbinter/it/00/14.html */
981                 /* The mappings here are guesses at best in most cases.
982                  * In a lot of cases we pick a language because we have
983                  * a translation in it, rather than because it's the most
984                  * widely used or understood in that country. */
985                 /* Improvements welcome */
986                 switch (country_code) {
987                     case 1: /* United States */
988                     case 670: /* Saipan / N. Mariana Island */
989                     case 671: /* Guam */
990                     case 680: /* Palau */
991                     case 684: /* American Samoa */
992                     case 691: /* Micronesia */
993                     case 692: /* Marshall Islands */
994                         msg_lang = "en_US";
995                         break;
996                     case 4: /* Canada (English) */
997                     case 27: /* South Africa */
998                     case 44: /* United Kingdom */
999                     case 61: /* International English / Australia */
1000                     case 64: /* New Zealand */
1001                     case 99: /* Asia (English) */
1002                     case 220: /* Gambia */
1003                     case 231: /* Liberia */
1004                     case 232: /* Sierra Leone */
1005                     case 233: /* Ghana */
1006                     case 254: /* Kenya */
1007                     case 256: /* Uganda */
1008                     case 260: /* Zambia */
1009                     case 263: /* Zimbabwe */
1010                     case 264: /* Namibia */
1011                     case 267: /* Botswana */
1012                     case 268: /* Swaziland */
1013                     case 290: /* St. Helena */
1014                     case 297: /* Aruba */
1015                     case 350: /* Gibraltar */
1016                     case 353: /* Ireland */
1017                     case 356: /* Malta */
1018                     case 500: /* Falkland Islands */
1019                     case 501: /* Belize */
1020                     case 592: /* Guyana */
1021                     case 672: /* Norfolk Island (Australia) / Christmas Island/Cocos Islands / Antartica */
1022                     case 673: /* Brunei Darussalam */
1023                     case 674: /* Nauru */
1024                     case 675: /* Papua New Guinea */
1025                     case 676: /* Tonga Islands */
1026                     case 677: /* Solomon Islands */
1027                     case 679: /* Fiji */
1028                     case 682: /* Cook Islands */
1029                     case 683: /* Niue */
1030                     case 685: /* Western Samoa */
1031                     case 686: /* Kiribati */
1032                         /* I believe only some of these are English speaking... */
1033                     case 809: /* Antigua and Barbuda / Anguilla / Bahamas / Barbados / Bermuda
1034                                  British Virgin Islands / Cayman Islands / Dominica
1035                                  Dominican Republic / Grenada / Jamaica / Montserra
1036                                  St. Kitts and Nevis / St. Lucia / St. Vincent and Grenadines
1037                                  Trinidad and Tobago / Turks and Caicos */
1038                         msg_lang = "en";
1039                         break;
1040                     case 2: /* Canadian-French */
1041                     case 32: /* Belgium */ /* maybe */
1042                     case 33: /* France */
1043                     case 213: /* Algeria */
1044                     case 216: /* Tunisia */
1045                     case 221: /* Senegal */
1046                     case 223: /* Mali */
1047                     case 225: /* Ivory Coast */
1048                     case 226: /* Burkina Faso */
1049                     case 227: /* Niger */
1050                     case 228: /* Togo */
1051                     case 229: /* Benin */
1052                     case 230: /* Mauritius */
1053                     case 235: /* Chad */
1054                     case 236: /* Central African Republic */
1055                     case 237: /* Cameroon */
1056                     case 241: /* Gabon */
1057                     case 242: /* Congo */
1058                     case 250: /* Rwhanda */
1059                     case 253: /* Djibouti */
1060                     case 257: /* Burundi */
1061                     case 261: /* Madagascar */
1062                     case 262: /* Reunion Island */
1063                     case 269: /* Comoros */
1064                     case 270: /* Mayotte */
1065                     case 352: /* Luxembourg (or de or ...) */
1066                     case 508: /* St. Pierre and Miquelon */
1067                     case 509: /* Haiti */
1068                     case 590: /* Guadeloupe */
1069                     case 594: /* French Guiana */
1070                     case 596: /* Martinique / French Antilles */
1071                     case 678: /* Vanuatu */
1072                     case 681: /* Wallis & Futuna */
1073                     case 687: /* New Caledonia */
1074                     case 689: /* French Polynesia */
1075                     case 961: /* Lebanon */
1076                         msg_lang = "fr";
1077                         break;
1078                     case 3: /* Latin America */
1079                     case 34: /* Spain */
1080                     case 51: /* Peru */
1081                     case 52: /* Mexico */
1082                     case 53: /* Cuba */
1083                     case 54: /* Argentina */
1084                     case 56: /* Chile */
1085                     case 57: /* Columbia */
1086                     case 58: /* Venezuela */
1087                     case 63: /* Philippines */
1088                     case 240: /* Equatorial Guinea */
1089                     case 502: /* Guatemala */
1090                     case 503: /* El Salvador */
1091                     case 504: /* Honduras */
1092                     case 505: /* Nicraragua */
1093                     case 506: /* Costa Rica */
1094                     case 507: /* Panama */
1095                     case 591: /* Bolivia */
1096                     case 593: /* Ecuador */
1097                     case 595: /* Paraguay */
1098                     case 598: /* Uruguay */
1099                         msg_lang = "es";
1100                         break;
1101                     case 39: /* Italy / San Marino / Vatican City */
1102                         msg_lang = "it";
1103                         break;
1104                     case 41: /* Switzerland / Liechtenstein */ /* or fr or ... */
1105                         msg_lang = "de_CH";
1106                         break;
1107                     case 43: /* Austria (DR DOS 5.0) */
1108                         msg_lang = "de";
1109                         break;
1110                     case 49: /* Germany */
1111                         msg_lang = "de_DE";
1112                         break;
1113                     case 55: /* Brazil (not supported by DR DOS 5.0) */
1114                         msg_lang = "pt_BR";
1115                         break;
1116                     case 238: /* Cape Verde Islands */
1117                     case 244: /* Angola */
1118                     case 245: /* Guinea-Bissau */
1119                     case 259: /* Mozambique */
1120                     case 351: /* Portugal */
1121                         msg_lang = "pt";
1122                         break;
1123#if 0
1124                     case 7: /* Russia */
1125                     case 20: /* Egypt */
1126                     case 30: /* Greece */
1127                     case 31: /* Netherlands */
1128                     case 35: /* Bulgaria??? */
1129                     case 36: /* Hungary (not supported by DR DOS 5.0) */
1130                     case 38: /* Yugoslavia (not supported by DR DOS 5.0) -- obsolete */
1131                     case 40: /* Romania */
1132                     case 42: /* Czechoslovakia / Tjekia / Slovakia (not supported by DR DOS 5.0) */
1133                     case 45: /* Denmark */
1134                     case 46: /* Sweden */
1135                     case 47: /* Norway */
1136                     case 48: /* Poland (not supported by DR DOS 5.0) */
1137                     case 60: /* Malaysia */
1138                     case 62: /* Indonesia / East Timor */
1139                     case 65: /* Singapore */
1140                     case 66: /* Thailand (or Taiwan??? ) */
1141                     case 81: /* Japan (DR DOS 5.0, MS-DOS 5.0+) */
1142                     case 82: /* South Korea (DR DOS 5.0) */
1143                     case 84: /* Vietnam */
1144                     case 86: /* China (MS-DOS 5.0+) */
1145                     case 88: /* Taiwan (MS-DOS 5.0+) */
1146                     case 90: /* Turkey (MS-DOS 5.0+) */
1147                     case 91: /* India */
1148                     case 92: /* Pakistan */
1149                     case 93: /* Afghanistan */
1150                     case 94: /* Sri Lanka */
1151                     case 98: /* Iran */
1152                     case 102: /* ??? (Hebrew MS-DOS 5.0) */
1153                     case 112: /* Belarus */
1154                     case 200: /* Thailand (PC DOS 6.1+) (reported as 01due to a bug in PC DOS COUNTRY.SYS) */
1155                     case 212: /* Morocco */
1156                     case 218: /* Libya */
1157                     case 222: /* Maruitania */
1158                     case 224: /* African Guinea */
1159                     case 234: /* Nigeria */
1160                     case 239: /* Sao Tome and Principe */
1161                     case 243: /* Zaire */
1162                     case 246: /* Diego Garcia */
1163                     case 247: /* Ascension Isle */
1164                     case 248: /* Seychelles */
1165                     case 249: /* Sudan */
1166                     case 251: /* Ethiopia */
1167                     case 252: /* Somalia */
1168                     case 255: /* Tanzania */
1169                     case 265: /* Malawi */
1170                     case 266: /* Lesotho */
1171                     case 298: /* Faroe Islands */
1172                     case 299: /* Greenland */
1173                     case 354: /* Iceland */
1174                     case 355: /* Albania */
1175                     case 357: /* Cyprus */
1176                     case 358: /* Finland */
1177                     case 359: /* Bulgaria */
1178                     case 370: /* Lithuania (reported as 372 due to a bug in MS-DOS COUNTRY.SYS) */
1179                     case 371: /* Latvia (reported as 372 due to a bug in MS-DOS COUNTRY.SYS) */
1180                     case 372: /* Estonia */
1181                     case 373: /* Moldova */
1182                     case 375: /* ??? (MS-DOS 7.10 / Windows98) */
1183                     case 380: /* Ukraine */
1184                     case 381: /* Serbia / Montenegro */
1185                     case 384: /* Croatia */
1186                     case 385: /* Croatia (PC DOS 7+) */
1187                     case 386: /* Slovenia */
1188                     case 387: /* Bosnia-Herzegovina (Latin) */
1189                     case 388: /* Bosnia-Herzegovina (Cyrillic) (PC DOS 7+) (reported as 381 due to a bug in PC DOS COUNTRY.SYS) */
1190                     case 389: /* FYR Macedonia */
1191                     case 421: /* Czech Republic / Tjekia (PC DOS 7+) */
1192                     case 422: /* Slovakia (reported as 421 due to a bug in COUNTRY.SYS) */
1193                     case 597: /* Suriname (nl) */
1194                     case 599: /* Netherland Antilles (nl) */
1195                     case 666: /* Russia??? (PTS-DOS 6.51 KEYB) */
1196                     case 667: /* Poland??? (PTS-DOS 6.51 KEYB) */
1197                     case 668: /* Poland??? (Slavic??? ) (PTS-DOS 6.51 KEYB) */
1198                     case 688: /* Tuvalu */
1199                     case 690: /* Tokealu */
1200                     case 711: /* ??? (currency = EA$, code pages 437,737,850,852,855,857) */
1201                     case 785: /* Arabic (Middle East/Saudi Arabia/etc.) */
1202                     case 804: /* Ukraine */
1203                     case 850: /* North Korea */
1204                     case 852: /* Hong Kong */
1205                     case 853: /* Macao */
1206                     case 855: /* Cambodia */
1207                     case 856: /* Laos */
1208                     case 880: /* Bangladesh */
1209                     case 886: /* Taiwan (MS-DOS 6.22+) */
1210                     case 960: /* Maldives */
1211                     case 962: /* Jordan */
1212                     case 963: /* Syria / Syrian Arab Republic */
1213                     case 964: /* Iraq */
1214                     case 965: /* Kuwait */
1215                     case 966: /* Saudi Arabia */
1216                     case 967: /* Yemen */
1217                     case 968: /* Oman */
1218                     case 969: /* Yemen??? (Arabic MS-DOS 5.0) */
1219                     case 971: /* United Arab Emirates */
1220                     case 972: /* Israel (Hebrew) (DR DOS 5.0,MS-DOS 5.0+) */
1221                     case 973: /* Bahrain */
1222                     case 974: /* Qatar */
1223                     case 975: /* Bhutan */
1224                     case 976: /* Mongolia */
1225                     case 977: /* Nepal */
1226                     case 995: /* Myanmar (Burma) */
1227#endif
1228                 }
1229              }
1230           }
1231#endif
1232      }
1233   }
1234#ifdef DEBUG
1235   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang, msg_lang?msg_lang:"(null)");
1236#endif
1237
1238   /* On Mandrake LANG defaults to C */
1239   if (strcmp(msg_lang, "C") == 0) msg_lang = "en";
1240
1241   msg_lang = osstrdup(msg_lang);
1242
1243   /* Convert en-us to en_US, etc */
1244   p = strchr(msg_lang, '-');
1245   if (p) {
1246      *p++ = '_';
1247      while (*p) {
1248         *p = toupper(*p);
1249         p++;
1250      }
1251   }
1252
1253   p = strchr(msg_lang, '_');
1254   if (p) {
1255      *p = '\0';
1256      msg_lang2 = osstrdup(msg_lang);
1257      *p = '_';
1258   }
1259
1260#ifdef LC_MESSAGES
1261   /* try to setlocale() appropriately too */
1262   if (!setlocale(LC_MESSAGES, msg_lang)) {
1263      if (msg_lang2) setlocale(LC_MESSAGES, msg_lang2);
1264   }
1265#endif
1266
1267   select_charset(default_charset());
1268}
1269
1270/* Message may be overwritten by next call
1271 * (but not in current implementation) */
1272const char *
1273msg(int en)
1274{
1275   /* NB can't use ASSERT here! */
1276   static char badbuf[256];
1277   if (en >= 1000 && en < 1000 + N_DONTEXTRACTMSGS)
1278      return dontextract[en - 1000];
1279   if (!msg_array) {
1280      if (en != 1)  {
1281         sprintf(badbuf, "Message %d requested before msg_array initialised\n", en);
1282         return badbuf;
1283      }
1284      /* this should be the only other message which can be requested before
1285       * the message file is opened and read... */
1286      if (!dontextract) return "Out of memory (couldn't find %lu bytes).";
1287      return dontextract[(/*Out of memory (couldn't find %lu bytes).*/1004)
1288                         - 1000];
1289   }
1290
1291   if (en < 0 || en >= num_msgs) {
1292      sprintf(badbuf, "Message %d out of range\n", en);
1293      return badbuf;
1294   }
1295
1296   if (en == 0) {
1297      const char *p = msg_array[0];
1298      if (!*p) p = "(C)";
1299      return p;
1300   }
1301
1302   return msg_array[en];
1303}
1304
1305/* returns persistent copy of message */
1306const char *
1307msgPerm(int en)
1308{
1309   return msg(en);
1310}
1311
1312void
1313v_report(int severity, const char *fnm, int line, int en, va_list ap)
1314{
1315#ifdef AVEN
1316   aven_v_report(severity, fnm, line, en, ap);
1317#else
1318   if (fnm) {
1319      fputs(fnm, STDERR);
1320      if (line) fprintf(STDERR, ":%d", line);
1321   } else {
1322      fputs(appname_copy, STDERR);
1323   }
1324   fputs(": ", STDERR);
1325
1326   if (severity == 0) {
1327      fputs(msg(/*warning*/4), STDERR);
1328      fputs(": ", STDERR);
1329   }
1330
1331   vfprintf(STDERR, msg(en), ap);
1332   fputnl(STDERR);
1333#endif
1334
1335   switch (severity) {
1336    case 0:
1337      msg_warnings++;
1338      break;
1339    case 1:
1340      msg_errors++;
1341      if (msg_errors == 50)
1342         fatalerror_in_file(fnm, 0, /*Too many errors - giving up*/19);
1343      break;
1344    case 2:
1345      exit(EXIT_FAILURE);
1346   }
1347}
1348
1349void
1350warning(int en, ...)
1351{
1352   va_list ap;
1353   va_start(ap, en);
1354   v_report(0, NULL, 0, en, ap);
1355   va_end(ap);
1356}
1357
1358void
1359error(int en, ...)
1360{
1361   va_list ap;
1362   va_start(ap, en);
1363   v_report(1, NULL, 0, en, ap);
1364   va_end(ap);
1365}
1366
1367void
1368fatalerror(int en, ...)
1369{
1370   va_list ap;
1371   va_start(ap, en);
1372   v_report(2, NULL, 0, en, ap);
1373   va_end(ap);
1374}
1375
1376void
1377warning_in_file(const char *fnm, int line, int en, ...)
1378{
1379   va_list ap;
1380   va_start(ap, en);
1381   v_report(0, fnm, line, en, ap);
1382   va_end(ap);
1383}
1384
1385void
1386error_in_file(const char *fnm, int line, int en, ...)
1387{
1388   va_list ap;
1389   va_start(ap, en);
1390   v_report(1, fnm, line, en, ap);
1391   va_end(ap);
1392}
1393
1394void
1395fatalerror_in_file(const char *fnm, int line, int en, ...)
1396{
1397   va_list ap;
1398   va_start(ap, en);
1399   v_report(2, fnm, line, en, ap);
1400   va_end(ap);
1401}
1402
1403/* Code to support switching character set at runtime (e.g. for a printer
1404 * driver to support different character sets on screen and on the printer)
1405 */
1406typedef struct charset_li {
1407   struct charset_li *next;
1408   int code;
1409   char **msg_array;
1410} charset_li;
1411
1412static charset_li *charset_head = NULL;
1413
1414static int charset = CHARSET_BAD;
1415
1416int
1417select_charset(int charset_code)
1418{
1419   int old_charset = charset;
1420   charset_li *p;
1421
1422#ifdef DEBUG
1423   fprintf(stderr, "select_charset(%d), old charset = %d\n", charset_code,
1424           charset);
1425#endif
1426
1427   charset = charset_code;
1428
1429   /* check if we've already parsed messages for new charset */
1430   for (p = charset_head; p; p = p->next) {
1431#ifdef DEBUG
1432      printf("%p: code %d msg_array %p\n", p, p->code, p->msg_array);
1433#endif
1434      if (p->code == charset) {
1435         msg_array = p->msg_array;
1436         return old_charset;
1437      }
1438   }
1439
1440   /* nope, got to reparse message file */
1441   parse_msg_file(charset_code);
1442
1443   /* add to list */
1444   p = osnew(charset_li);
1445   p->code = charset;
1446   p->msg_array = msg_array;
1447   p->next = charset_head;
1448   charset_head = p;
1449
1450   return old_charset;
1451}
Note: See TracBrowser for help on using the repository browser.