source: git/src/message.c @ dc639a8

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

Fixes to get a clean compile.

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

  • Property mode set to 100644
File size: 22.7 KB
RevLine 
[db75e18]1/* > message.c
2 * Fairly general purpose message and error routines
[704ad2b]3 * Copyright (C) 1993-2001 Olly Betts
[846746e]4 *
[89231c4]5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
[846746e]9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
[89231c4]12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
[846746e]14 *
[89231c4]15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
[60f7018]18 */
19
[55de792]20/*#define DEBUG 1*/
21
[db75e18]22#ifdef HAVE_CONFIG_H
23# include <config.h>
24#endif
[60f7018]25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <ctype.h>
30#include <limits.h>
31#include <errno.h>
[f764581]32#include <locale.h>
[60f7018]33
34#include "whichos.h"
[4432f2e]35#include "filename.h"
36#include "message.h"
[60f7018]37#include "osdepend.h"
38#include "filelist.h"
39#include "debug.h"
40
[a4140e9]41#ifdef AVEN
42#include "aven.h"
43#endif
44
[60f7018]45#ifdef HAVE_SIGNAL
46# ifdef HAVE_SETJMP
47#  include <setjmp.h>
48static jmp_buf jmpbufSignal;
49#  include <signal.h>
50# else
51#  undef HAVE_SIGNAL
52# endif
53#endif
54
[6754d07]55#if (OS==WIN32)
56#include <windows.h>
57#endif
58
[2163157]59#if (OS==RISCOS)
60#include "oslib/wimpreadsy.h"
61#endif
62
[647407d]63/* This is the name of the default language.  Add -DDEFAULTLANG to CFLAGS
64 * e.g. with `CFLAGS="-DDEFAULTLANG=fr" ./configure'
[60f7018]65 */
66#ifndef DEFAULTLANG
[d5bd3a7]67# define DEFAULTLANG en
[60f7018]68#endif
69
70/* For funcs which want to be immune from messing around with different
71 * calling conventions */
72#ifndef CDECL
[2ca296b]73# define CDECL
[60f7018]74#endif
75
[25ab06b]76int msg_warnings = 0; /* keep track of how many warnings we've given */
77int msg_errors = 0;   /* and how many (non-fatal) errors */
[60f7018]78
[a4140e9]79/* in case osmalloc() fails before appname_copy is set up */
80static const char *appname_copy = "anonymous program";
[60f7018]81
82/* error code for failed osmalloc and osrealloc calls */
[db75e18]83static void
84outofmem(OSSIZE_T size)
85{
[bd1913f]86   fatalerror(/*Out of memory (couldn't find %lu bytes).*/1,
87              (unsigned long)size);
[60f7018]88}
89
[a420b49]90#ifdef TOMBSTONES
91#define TOMBSTONE_SIZE 16
[bd1913f]92static const char tombstone[TOMBSTONE_SIZE] = "012345\xfftombstone";
[a420b49]93#endif
94
[60f7018]95/* malloc with error catching if it fails. Also allows us to write special
96 * versions easily eg for DOS EMS or MS Windows.
97 */
[bd1913f]98void FAR *
[db75e18]99osmalloc(OSSIZE_T size)
100{
[60f7018]101   void FAR *p;
[a420b49]102#ifdef TOMBSTONES
103   size += TOMBSTONE_SIZE * 2;
104   p = malloc(size);
105#else
[db75e18]106   p = xosmalloc(size);
[a420b49]107#endif
[2ca296b]108   if (p == NULL) outofmem(size);
[a420b49]109#ifdef TOMBSTONES
[bd1913f]110   printf("osmalloc truep=%p truesize=%d\n", p, size);
[a420b49]111   memcpy(p, tombstone, TOMBSTONE_SIZE);
112   memcpy(p + size - TOMBSTONE_SIZE, tombstone, TOMBSTONE_SIZE);
113   *(size_t *)p = size;
114   p += TOMBSTONE_SIZE;
115#endif
[60f7018]116   return p;
117}
118
119/* realloc with error catching if it fails. */
[bd1913f]120void FAR *
[db75e18]121osrealloc(void *p, OSSIZE_T size)
122{
[a420b49]123   /* some pre-ANSI realloc implementations don't cope with a NULL pointer */
124   if (p == NULL) {
125      p = xosmalloc(size);
126   } else {
127#ifdef TOMBSTONES
128      int true_size;
129      size += TOMBSTONE_SIZE * 2;
130      p -= TOMBSTONE_SIZE;
131      true_size = *(size_t *)p;
[bd1913f]132      printf("osrealloc (in truep=%p truesize=%d)\n", p, true_size);
[a420b49]133      if (memcmp(p + sizeof(size_t), tombstone + sizeof(size_t),
134                 TOMBSTONE_SIZE - sizeof(size_t)) != 0) {
135         printf("start tombstone for block %p, size %d corrupted!",
[cb3d1e2]136                p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]137      }
138      if (memcmp(p + true_size - TOMBSTONE_SIZE, tombstone,
139                 TOMBSTONE_SIZE) != 0) {
140         printf("end tombstone for block %p, size %d corrupted!",
[cb3d1e2]141                p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]142      }
143      p = realloc(p, size);
144      if (p == NULL) outofmem(size);
[bd1913f]145      printf("osrealloc truep=%p truesize=%d\n", p, size);
[a420b49]146      memcpy(p, tombstone, TOMBSTONE_SIZE);
147      memcpy(p + size - TOMBSTONE_SIZE, tombstone, TOMBSTONE_SIZE);
148      *(size_t *)p = size;
149      p += TOMBSTONE_SIZE;
150#else
151      p = xosrealloc(p, size);
152#endif
153   }
[2ca296b]154   if (p == NULL) outofmem(size);
[60f7018]155   return p;
156}
157
[b2c945f]158char FAR *
[db75e18]159osstrdup(const char *str)
160{
[60f7018]161   char *p;
[db75e18]162   OSSIZE_T len;
163   len = strlen(str) + 1;
[0a3c5fa]164   p = osmalloc(len);
[db75e18]165   memcpy(p, str, len);
[60f7018]166   return p;
167}
168
[a420b49]169/* osfree is usually just a macro in osalloc.h */
170#ifdef TOMBSTONES
[bd1913f]171void
[a420b49]172osfree(void *p)
173{
174   int true_size;
175   if (!p) return;
176   p -= TOMBSTONE_SIZE;
177   true_size = *(size_t *)p;
[bd1913f]178   printf("osfree truep=%p truesize=%d\n", p, true_size);
[a420b49]179   if (memcmp(p + sizeof(size_t), tombstone + sizeof(size_t),
180              TOMBSTONE_SIZE - sizeof(size_t)) != 0) {
181      printf("start tombstone for block %p, size %d corrupted!",
[cb3d1e2]182             p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]183   }
184   if (memcmp(p + true_size - TOMBSTONE_SIZE, tombstone,
185              TOMBSTONE_SIZE) != 0) {
186      printf("end tombstone for block %p, size %d corrupted!",
[cb3d1e2]187             p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]188   }
189   free(p);
190}
191#endif
[60f7018]192
193#ifdef HAVE_SIGNAL
194
195static int sigReceived;
196
197/* for systems not using autoconf, assume the signal handler returns void
198 * unless specified elsewhere */
199#ifndef RETSIGTYPE
[2ca296b]200# define RETSIGTYPE void
[60f7018]201#endif
202
[bd1913f]203static CDECL RETSIGTYPE FAR
204report_sig(int sig)
205{
[db75e18]206   sigReceived = sig;
[2ca296b]207   longjmp(jmpbufSignal, 1);
[60f7018]208}
209
[db75e18]210static void
211init_signals(void)
212{
[60f7018]213   int en;
214   if (!setjmp(jmpbufSignal)) {
[0a3c5fa]215#if 1 /* disable these to get a core dump */
[db75e18]216      signal(SIGABRT, report_sig); /* abnormal termination eg abort() */
217      signal(SIGFPE,  report_sig); /* arithmetic error eg /0 or overflow */
218      signal(SIGILL,  report_sig); /* illegal function image eg illegal instruction */
219      signal(SIGSEGV, report_sig); /* illegal storage access eg access outside memory limits */
220#endif
[60f7018]221# ifdef SIGSTAK /* only on RISC OS AFAIK */
[db75e18]222      signal(SIGSTAK, report_sig); /* stack overflow */
[60f7018]223# endif
224      return;
225   }
[db75e18]226
[60f7018]227   switch (sigReceived) {
[bd1913f]228      case SIGABRT: en = /*Abnormal termination*/90; break;
229      case SIGFPE:  en = /*Arithmetic error*/91; break;
230      case SIGILL:  en = /*Illegal instruction*/92; break;
231      case SIGSEGV: en = /*Bad memory access*/94; break;
[60f7018]232# ifdef SIGSTAK
[bd1913f]233      case SIGSTAK: en = /*Stack overflow*/96; break;
[60f7018]234# endif
[bd1913f]235      default:      en = /*Unknown signal received*/97; break;
[60f7018]236   }
[db75e18]237   fputsnl(msg(en), STDERR);
[ea816ec]238
[c0a9908]239   /* Any of the signals we catch indicates a bug */
240   fatalerror(/*Bug in program detected! Please report this to the authors*/11);
[db75e18]241
[60f7018]242   exit(EXIT_FAILURE);
243}
244#endif
245
[bd1913f]246static int
247default_charset(void)
248{
[8769f9f]249#if (OS==RISCOS)
[ea816ec]250   /* RISCOS 3.1 and above CHARSET_RISCOS31 (ISO_8859_1 + extras in 128-159)
251    * RISCOS < 3.1 is ISO_8859_1 */
[2163157]252   int version;
[ea816ec]253   if (xwimpreadsysinfo_version(&version) != NULL) {
254      /* RISC OS 2 or some error (don't care which) */
255      return CHARSET_ISO_8859_1;
256   }
257
258   /* oddly wimp_VERSION_RO3 is RISC OS 3.1 */
259   if (version < wimp_VERSION_RO3) return CHARSET_ISO_8859_1;
[2163157]260
[2ca296b]261   return CHARSET_RISCOS31;
[60f7018]262#elif (OS==MSDOS)
263   return CHARSET_DOSCP850;
[a4140e9]264#elif (OS==WIN32)
[d5bd3a7]265# ifdef AVEN
[dc639a8]266   return CHARSET_WINCP1252;
[d5bd3a7]267# else
268   switch (GetConsoleOutputCP()) {
[dc639a8]269    case 1252: return CHARSET_WINCP1252;
270    case 850: return CHARSET_DOSCP850;
[d5bd3a7]271   }
272   return CHARSET_USASCII;
273# endif
[a4140e9]274#elif (OS==UNIX)
275#if defined(XCAVEROT) || defined(AVEN)
[8769f9f]276   return CHARSET_ISO_8859_1;
[a4140e9]277#else
278   char *p = strchr(msg_lang, '.');
279   if (p) {
280      char *chset = ++p;
281      size_t name_len;
282
283      while (*p != '\0' && *p != '@') p++;
284
285      name_len = p - chset;
286
287      if (name_len) {
288         int only_digit = 1;
289         size_t cnt;
290       
291         for (cnt = 0; cnt < name_len; ++cnt)
292            if (isalpha(chset[cnt])) {
293               only_digit = 0;
294               break;
295            }
296
297         if (only_digit) goto iso;
298         
299         switch (tolower(chset[0])) {
300          case 'i':
301            if (tolower(chset[1]) == 's' && tolower(chset[2]) == 'o') {
302               chset += 3;
303               iso:
304               if (strncmp(chset, "8859", 4) == 0) {
305                  chset += 4;
306                  while (chset < p && *chset && !isdigit(*chset)) chset++;
307                  switch (atoi(chset)) {
308                   case 1: return CHARSET_ISO_8859_1;
309                   default: return CHARSET_USASCII;               
310                  }
311               }
312            }
313            break;
314          case 'u':
315            if (tolower(chset[1]) == 't' && tolower(chset[2]) == 'f') {
316               chset += 3;
317               while (chset < p && *chset && !isdigit(*chset)) chset++;
318               switch (atoi(chset)) {
319                case 8: return CHARSET_UTF8;
320                default: return CHARSET_USASCII;
321               }
322            }
323         }
324      }
325   }
326   return CHARSET_USASCII;
327#endif
328#else
329# error Do not know operating system 'OS'
[60f7018]330#endif
331}
332
[dc639a8]333#if (OS==MSDOS || OS==WIN32)
[db75e18]334static int
335xlate_dos_cp850(int unicode)
336{
[48e4121]337   switch (unicode) {
[d41b1353]338#include "uni2dos.h"
[48e4121]339   }
340   return 0;
341}
342#endif
343
[a4140e9]344/* It seems that Swedish and maybe some other scandanavian languages don't
345 * transliterate &auml; to ae - but it seems there may be conflicting views
346 * on this...
347 */
348#define umlaut_to_e() 1
349
[db75e18]350static int
[55de792]351add_unicode(int charset, unsigned char *p, int value)
[db75e18]352{
[55de792]353#ifdef DEBUG
354   fprintf(stderr, "add_unicode(%d, %p, %d)\n", charset, p, value);
355#endif
[4432f2e]356   if (value == 0) return 0;
[48e4121]357   switch (charset) {
[db75e18]358   case CHARSET_USASCII:
[6a4871e]359      if (value < 0x80) {
[48e4121]360         *p = value;
361         return 1;
362      }
363      break;
[db75e18]364   case CHARSET_ISO_8859_1:
[6a4871e]365      if (value < 0x100) {
[48e4121]366         *p = value;
367         return 1;
368      }
[ea816ec]369      break;
[48e4121]370#if (OS==RISCOS)
[ea816ec]371   case CHARSET_RISCOS31:
372      /* RISC OS 3.1 (and later) extensions to ISO-8859-1 */
373      switch (value) {
374       case 0x152: value = 0x9a; break; /* &OElig; */
375       case 0x153: value = 0x9b; break; /* &oelig; */
376       case 0x174: value = 0x81; break; /* &Wcirc; */
377       case 0x175: value = 0x82; break; /* &wcirc; */
378       case 0x176: value = 0x85; break; /* &Ycirc; */
379       case 0x177: value = 0x86; break; /* &ycirc; */
380      }
381      if (value < 0x100) {
382         *p = value;
383         return 1;
384      }
[48e4121]385      break;
[a4140e9]386#elif (OS==WIN32)
387   case CHARSET_WINCP1252:
388      /* MS Windows extensions to ISO-8859-1 */
389      /* there are a few other obscure ones we don't currently need */
390      switch (value) {
391       case 0x152: value = 0x8c; break; /* &OElig; */
392       case 0x153: value = 0x9c; break; /* &oelig; */
393      }
394      if (value < 0x100) {
395         *p = value;
396         return 1;
397      }
398      break;     
[dc639a8]399#elif (OS==MSDOS || OS==WIN32)
[db75e18]400   case CHARSET_DOSCP850:
[48e4121]401      value = xlate_dos_cp850(value);
402      if (value) {
403         *p = value;
404         return 1;
405      }
406      break;
407#endif
[4432f2e]408   }
[a4140e9]409   /* Transliterate characters we can't represent */
410#ifdef DEBUG
411   fprintf(stderr, "transliterate `%c' 0x%x\n", value, value);
412#endif
413   switch (value) {
414    case 160:
415      *p = ' '; return 1;
416    case 161 /* ¡ */:
417      *p = '!'; return 1;
418    case 171 /* « */:
419      p[1] = *p = '<'; return 2;
420    case 187 /* » */:
421      p[1] = *p = '>'; return 2;
422    case 191 /* ¿ */:
423      *p = '?'; return 1;
424    case 192 /* À */: case 193 /* Á */: case 194 /* Â */: case 195 /* Ã */:
425      *p = 'A'; return 1;
426    case 197 /* Å */:
427      p[1] = *p = 'A'; return 2;
428    case 196 /* Ä */: /* &Auml; */
429      *p = 'A';
430      if (!umlaut_to_e()) return 1;
431      p[1] = 'E'; return 2;
432    case 198 /* Æ */:
433      *p = 'A'; p[1] = 'E'; return 2;
434    case 199 /* Ç */:
435      *p = 'C'; return 1;
436    case 200 /* È */: case 201 /* É */: case 202 /* Ê */: case 203 /* Ë */:
437      *p = 'E'; return 1;
438    case 204 /* Ì */: case 205 /* Í */: case 206 /* Î */: case 207 /* Ï */:
439      *p = 'I'; return 1;
440    case 208 /* Ð */: case 222 /* Þ */:
441      *p = 'T'; p[1] = 'H'; return 2;
442    case 209 /* Ñ */:
443      *p = 'N'; return 1;
444    case 210 /* Ò */: case 211 /* Ó */: case 212 /* Ô */: case 213 /* Õ */:
445      *p = 'O'; return 1;
446    case 214 /* Ö */: /* &Ouml; */ case 0x152: /* &OElig; */
447      *p = 'O'; p[1] = 'E'; return 2;
448    case 217 /* Ù */: case 218 /* Ú */: case 219 /* Û */:
449      *p = 'U'; return 1;
450    case 220 /* Ü */: /* &Uuml; */
451      *p = 'U'; p[1] = 'E'; return 2;
452    case 221 /* Ý */:
453      *p = 'Y'; return 1;
454    case 223 /* ß */:
455      p[1] = *p = 's'; return 2;
456    case 224 /* à */: case 225 /* á */: case 226 /* â */: case 227 /* ã */:
457      *p = 'a'; return 1;
458    case 228 /* ä */: /* &auml; */ case 230 /* æ */:
459      *p = 'a'; p[1] = 'e'; return 2;
460    case 229 /* å */:
461      p[1] = *p = 'a'; return 2;
462    case 231 /* ç */:
463      *p = 'c'; return 1;
464    case 232 /* è */: case 233 /* é */: case 234 /* ê */: case 235 /* ë */:
465      *p = 'e'; return 1;
466    case 236 /* ì */: case 237 /* í */: case 238 /* î */: case 239 /* ï */:
467      *p = 'i'; return 1;
468    case 241 /* ñ */:
469      *p = 'n'; return 1;
470    case 240 /* ð */: case 254 /* þ */:
471      *p = 't'; p[1] = 'h'; return 2;
472    case 242 /* ò */: case 243 /* ó */: case 244 /* ô */: case 245 /* õ */:
473      *p = 'o'; return 1;
474    case 246 /* ö */: /* &ouml; */ case 0x153: /* &oelig; */
475      *p = 'o'; p[1] = 'e'; return 2;
476    case 249 /* ù */: case 250 /* ú */: case 251 /* û */:
477      *p = 'u'; return 1;
478    case 252 /* ü */: /* &uuml; */
479      *p = 'u'; p[1] = 'e'; return 2;
480    case 253 /* ý */: case 255 /* ÿ */:
481      *p = 'y'; return 1;
482   }
483#ifdef DEBUG
484   fprintf(stderr, "failed to transliterate\n");
485#endif
[f1a5201]486   return 0;
[4432f2e]487}
488
[f2a6ce4]489/* fall back on looking in the current directory */
490static const char *pth_cfg_files = "";
491
[db75e18]492static int num_msgs = 0;
[55de792]493static char **msg_array = NULL;
[db75e18]494
[b83f907]495const char *msg_lang = NULL;
[c0a9908]496const char *msg_lang2 = NULL;
[b83f907]497
[d5bd3a7]498static char **
499parse_msgs(int n, unsigned char *p, int charset_code) {
500   int i;
501
502   char **msgs = osmalloc(n * sizeof(char *));
503
504   for (i = 0; i < n; i++) {
505      unsigned char *to = p;
506      int ch;
507      msgs[i] = (char *)p;
508
509      /* If we want UTF8 anyway, we just need to find the start of each
510       * message */
511      if (charset_code == CHARSET_UTF8) {
512         p += strlen((char *)p) + 1;
513         continue;
514      }
515
516      while ((ch = *p++) != 0) {
517         /* A byte in the range 0x80-0xbf or 0xf0-0xff isn't valid in
518          * this state, (0xf0-0xfd mean values > 0xffff) so treat as
519          * literal and try to resync so we cope better when fed
520          * non-utf-8 data.  Similarly we abandon a multibyte sequence
521          * if we hit an invalid character. */
522         if (ch >= 0xc0 && ch < 0xf0) {
523            int ch1 = *p;
524            if ((ch1 & 0xc0) != 0x80) goto resync;
525
526            if (ch < 0xe0) {
527               /* 2 byte sequence */
528               ch = ((ch & 0x1f) << 6) | (ch1 & 0x3f);
529               p++;
530            } else {
531               /* 3 byte sequence */
532               int ch2 = p[1];
533               if ((ch2 & 0xc0) != 0x80) goto resync;
534               ch = ((ch & 0x1f) << 12) | ((ch1 & 0x3f) << 6) | (ch2 & 0x3f);
535               p += 2;
536            }
537         }
538
539         resync:
540
541         if (ch < 127) {
542            *to++ = (char)ch;
543         } else {
544            /* We assume an N byte UTF-8 code never transliterates to more
545             * than N characters (so we can't transliterate © to (C) or
546             * ® to (R) for example) */
547            to += add_unicode(charset_code, to, ch);
548         }
549      }
550      *to++ = '\0';
551   }
552   return msgs;
553}
554
555/* No point extracting these errors as they won't get used if file opens */
556#define HDR(D) "../lib/"STRING(D)".h"
557#include HDR(DEFAULTLANG)
558
559static char **dontextract = NULL;
560
[db75e18]561static void
562parse_msg_file(int charset_code)
563{
564   FILE *fh;
565   unsigned char header[20];
[d5bd3a7]566   int i;   
[db75e18]567   unsigned len;
[55de792]568   unsigned char *p;
[b164c18]569   char *fnm, *s;
[d5bd3a7]570   int n;
[cb3d1e2]571
[55de792]572#ifdef DEBUG
573   fprintf(stderr, "parse_msg_file(%d)\n", charset_code);
574#endif
[db75e18]575
[d5bd3a7]576   /* sort out messages we need to print if we can't open the message file */
577   dontextract = parse_msgs(N_DONTEXTRACTMSGS, dontextractmsgs, charset_code);
578
[0a3c5fa]579   fnm = osstrdup(msg_lang);
[b164c18]580   /* trim off charset from stuff like "de_DE.iso8859_1" */
581   s = strchr(fnm, '.');
582   if (s) *s = '\0';
[a2f9d5c]583
[b164c18]584   fh = fopenWithPthAndExt(pth_cfg_files, fnm, EXT_SVX_MSG, "rb", NULL);
[db75e18]585
586   if (!fh) {
587      /* e.g. if 'en-COCKNEY' is unknown, see if we know 'en' */
[b164c18]588      if (strlen(fnm) > 3 && fnm[2] == '-') {
589         fnm[2] = '\0';
590         fh = fopenWithPthAndExt(pth_cfg_files, fnm, EXT_SVX_MSG, "rb", NULL);
591         if (!fh) fnm[2] = '-'; /* for error reporting */
[db75e18]592      }
[48e4121]593   }
[db75e18]594
595   if (!fh) {
[b07f165]596      fatalerror(/*Can't open message file `%s' using path `%s'*/1000,
597                 fnm, pth_cfg_files);
[4432f2e]598   }
[db75e18]599
600   if (fread(header, 1, 20, fh) < 20 ||
601       memcmp(header, "Svx\nMsg\r\n\xfe\xff", 12) != 0) {
[b07f165]602      fatalerror(/*Problem with message file `%s'*/1001, fnm);
[db75e18]603   }
604
[b07f165]605   if (header[12] != 0)
606      fatalerror(/*I don't understand this message file version*/1002);
[db75e18]607
[d5bd3a7]608   n = (header[14] << 8) | header[15];
[db75e18]609
610   len = 0;
611   for (i = 16; i < 20; i++) len = (len << 8) | header[i];
612
[0a3c5fa]613   p = osmalloc(len);
[b07f165]614   if (fread(p, 1, len, fh) < len)
615      fatalerror(/*Message file truncated?*/1003);
[2163157]616
[a420b49]617   fclose(fh);
[db75e18]618
[55de792]619#ifdef DEBUG
[d5bd3a7]620   fprintf(stderr, "fnm = `%s', n = %d, len = %d\n", fnm, n, len);
[55de792]621#endif
[b164c18]622   osfree(fnm);
[55de792]623
[d5bd3a7]624   msg_array = parse_msgs(n, p, charset_code);
625   num_msgs = n;
[4432f2e]626}
627
[f2a6ce4]628const char *
629msg_cfgpth(void)
630{
631   return pth_cfg_files;
632}
633
634void
635msg_init(const char *argv0)
[db75e18]636{
637   char *p;
638
639#ifdef HAVE_SIGNAL
640   init_signals();
641#endif
[0a3c5fa]642   /* Point to argv0 itself so we report a more helpful error if the code to work
643    * out the clean appname generates a signal */
[a4140e9]644   appname_copy = argv0;
[0a3c5fa]645#if (OS == UNIX)
646   /* use name as-is on Unix - programs run from path get name as supplied */
[a4140e9]647   appname_copy = osstrdup(argv0);
[0a3c5fa]648#else
649   /* use the lower-cased leafname on other platforms */
[a4140e9]650   appname_copy = p = leaf_from_fnm(argv0);
[4bfc8a7]651   while (*p) {
652      *p = tolower(*p);
653      p++;
654   }
[0a3c5fa]655#endif
[db75e18]656
657   /* Look for env. var. "SURVEXHOME" or the like */
658   p = getenv("SURVEXHOME");
659   if (p && *p) {
[0a3c5fa]660      pth_cfg_files = osstrdup(p);
[18f4759]661#if (OS==UNIX) && defined(DATADIR) && defined(PACKAGE)
[a420b49]662   } else {
663      /* under Unix, we compile in the configured path */
[18f4759]664      pth_cfg_files = DATADIR "/" PACKAGE;
[a420b49]665#else
[db75e18]666   } else if (argv0) {
667      /* else try the path on argv[0] */
[f2a6ce4]668      pth_cfg_files = path_from_fnm(argv0);
[a420b49]669#endif
[db75e18]670   }
671
[b164c18]672   msg_lang = getenv("SURVEXLANG");
673#ifdef DEBUG
[74044b7]674   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang, msg_lang?msg_lang:"(null)");
[b164c18]675#endif
676
677   if (!msg_lang || !*msg_lang) {
678      msg_lang = getenv("LANG");
[74044b7]679      if (!msg_lang || !*msg_lang) {
680#if (OS==WIN32)
681         LCID locid;
682#endif
[d5bd3a7]683         msg_lang = STRING(DEFAULTLANG);
[74044b7]684#if (OS==WIN32)
685         locid = GetUserDefaultLCID();
686         if (locid) {
687            WORD langid = LANGIDFROMLCID(locid);
688            switch (PRIMARYLANGID(langid)) {
689             case LANG_CATALAN:
690               msg_lang = "ca";
691               break;
692             case LANG_ENGLISH:
693               if (SUBLANGID(langid) == SUBLANG_ENGLISH_US)
694                  msg_lang = "en_US";
695               else
696                  msg_lang = "en";
697               break;
698             case LANG_FRENCH:
699               msg_lang = "fr";
700               break;
701             case LANG_GERMAN:
702               switch (SUBLANGID(langid)) {
703                case SUBLANG_GERMAN_SWISS:
704                  msg_lang = "de_CH";
705                  break;
706                case SUBLANG_GERMAN:
707                  msg_lang = "de_DE";
708                  break;
709                default:
710                  msg_lang = "de";
711               }
712               break;
713             case LANG_ITALIAN:
714               msg_lang = "it";
715               break;
716             case LANG_PORTUGUESE:
717               if (SUBLANGID(langid) == SUBLANG_PORTUGUESE_BRAZILIAN)
718                  msg_lang = "pt_BR";
719               else
720                  msg_lang = "pt";
721               break;
722             case LANG_SPANISH:
723               msg_lang = "es";
724               break;
725            }
726         }
727#endif
728      }
[b164c18]729   }
730#ifdef DEBUG
731   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang, msg_lang?msg_lang:"(null)");
732#endif
733
734   /* On Mandrake LANG defaults to C */
735   if (strcmp(msg_lang, "C") == 0) msg_lang = "en";
736
[0a3c5fa]737   msg_lang = osstrdup(msg_lang);
[b164c18]738
739   /* Convert en-us to en_US, etc */
740   p = strchr(msg_lang, '-');
741   if (p) {
742      *p++ = '_';
743      while (*p) {
744         *p = toupper(*p);
745         p++;
746      }
747   }
748
749   p = strchr(msg_lang, '_');
750   if (p) {
751      *p = '\0';
[0a3c5fa]752      msg_lang2 = osstrdup(msg_lang);
[b164c18]753      *p = '_';
754   }
755
756#ifdef LC_MESSAGES
757   /* try to setlocale() appropriately too */
758   if (!setlocale(LC_MESSAGES, msg_lang)) {
759      if (msg_lang2) setlocale(LC_MESSAGES, msg_lang2);
760   }
761#endif
762
[db75e18]763   select_charset(default_charset());
764}
765
[d5bd3a7]766/* Message may be overwritten by next call
[bd1913f]767 * (but not in current implementation) */
768const char *
[db75e18]769msg(int en)
770{
[eee67ab]771   /* NB can't use ASSERT here! */
772   static char badbuf[256];
[d5bd3a7]773   if (en >= 1000 && en < 1000 + N_DONTEXTRACTMSGS)
[b07f165]774      return dontextract[en - 1000];
[55de792]775   if (!msg_array) {
[eee67ab]776      if (en != 1)  {
777         sprintf(badbuf, "Message %d requested before msg_array initialised\n", en);
778         return badbuf;
779      }
[d5bd3a7]780      /* this should be the only other message which can be requested before
[a420b49]781       * the message file is opened and read... */
[d5bd3a7]782      if (!dontextract) return "Out of memory (couldn't find %lu bytes).";
783      return dontextract[4];
[db75e18]784   }
785
[eee67ab]786   if (en < 0 || en >= num_msgs) {
787      sprintf(badbuf, "Message %d out of range\n", en);
788      return badbuf;
789   }
[db75e18]790
[55de792]791   return msg_array[en];
[db75e18]792}
793
794/* returns persistent copy of message */
[bd1913f]795const char *
[db75e18]796msgPerm(int en)
797{
798   return msg(en);
799}
800
801void
802v_report(int severity, const char *fnm, int line, int en, va_list ap)
803{
[1f316f3]804#ifdef AVEN
[2e18955]805   aven_v_report(severity, fnm, line, en, ap);
[2163157]806#else
[db75e18]807   if (fnm) {
808      fputs(fnm, STDERR);
809      if (line) fprintf(STDERR, ":%d", line);
810   } else {
[a4140e9]811      fputs(appname_copy, STDERR);
[cb3d1e2]812   }
[db75e18]813   fputs(": ", STDERR);
814
815   if (severity == 0) {
816      fputs(msg(/*warning*/4), STDERR);
817      fputs(": ", STDERR);
818   }
819
820   vfprintf(STDERR, msg(en), ap);
821   fputnl(STDERR);
[1f316f3]822#endif
[cb3d1e2]823
[db75e18]824   switch (severity) {
825    case 0:
[25ab06b]826      msg_warnings++;
[db75e18]827      break;
828    case 1:
[25ab06b]829      msg_errors++;
830      if (msg_errors == 50)
[db75e18]831         fatalerror_in_file(fnm, 0, /*Too many errors - giving up*/19);
832      break;
833    case 2:
834      exit(EXIT_FAILURE);
835   }
836}
837
838void
839warning(int en, ...)
840{
841   va_list ap;
842   va_start(ap, en);
843   v_report(0, NULL, 0, en, ap);
844   va_end(ap);
845}
846
847void
848error(int en, ...)
849{
850   va_list ap;
851   va_start(ap, en);
852   v_report(1, NULL, 0, en, ap);
853   va_end(ap);
854}
855
856void
857fatalerror(int en, ...)
858{
859   va_list ap;
860   va_start(ap, en);
861   v_report(2, NULL, 0, en, ap);
862   va_end(ap);
863}
864
865void
866warning_in_file(const char *fnm, int line, int en, ...)
867{
868   va_list ap;
869   va_start(ap, en);
870   v_report(0, fnm, line, en, ap);
871   va_end(ap);
872}
873
874void
875error_in_file(const char *fnm, int line, int en, ...)
876{
877   va_list ap;
878   va_start(ap, en);
879   v_report(1, fnm, line, en, ap);
880   va_end(ap);
881}
882
883void
884fatalerror_in_file(const char *fnm, int line, int en, ...)
885{
886   va_list ap;
887   va_start(ap, en);
888   v_report(2, fnm, line, en, ap);
889   va_end(ap);
890}
891
892/* Code to support switching character set at runtime (e.g. for a printer
893 * driver to support different character sets on screen and on the printer)
894 */
895typedef struct charset_li {
896   struct charset_li *next;
897   int code;
[55de792]898   char **msg_array;
[db75e18]899} charset_li;
900
901static charset_li *charset_head = NULL;
902
903static int charset = CHARSET_BAD;
904
905int
906select_charset(int charset_code)
907{
908   int old_charset = charset;
909   charset_li *p;
910
[55de792]911#ifdef DEBUG
[bd1913f]912   fprintf(stderr, "select_charset(%d), old charset = %d\n", charset_code,
913           charset);
[55de792]914#endif
[cb3d1e2]915
[db75e18]916   charset = charset_code;
917
918   /* check if we've already parsed messages for new charset */
919   for (p = charset_head; p; p = p->next) {
[55de792]920#ifdef DEBUG
921      printf("%p: code %d msg_array %p\n", p, p->code, p->msg_array);
922#endif
[db75e18]923      if (p->code == charset) {
[55de792]924         msg_array = p->msg_array;
[db75e18]925         return old_charset;
926      }
927   }
928
929   /* nope, got to reparse message file */
930   parse_msg_file(charset_code);
931
932   /* add to list */
933   p = osnew(charset_li);
934   p->code = charset;
[55de792]935   p->msg_array = msg_array;
[db75e18]936   p->next = charset_head;
937   charset_head = p;
938
939   return old_charset;
940}
Note: See TracBrowser for help on using the repository browser.