source: git/src/message.c @ 54177c2

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 54177c2 was 4ad82e9, checked in by Olly Betts <olly@…>, 24 years ago

Added code to read current codepage under Borland C.

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

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