source: git/src/message.c @ c0635e7

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

Improved gcc-specific DEFAULTLANG code - still needs work.

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

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