source: git/src/message.c @ f9c9612

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

Renamed message files to be de_CH.msg rather than de-ch.msg to make
working with other i18n code easier.

aven: more translations, enabled i18n of wxWindows.

No longer trap SIGINT or SIGTERM - there's not much point really.

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

  • Property mode set to 100644
File size: 17.5 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
41#ifdef HAVE_SIGNAL
42# ifdef HAVE_SETJMP
43#  include <setjmp.h>
44static jmp_buf jmpbufSignal;
45#  include <signal.h>
46# else
47#  undef HAVE_SIGNAL
48# endif
49#endif
50
[647407d]51/* This is the name of the default language.  Add -DDEFAULTLANG to CFLAGS
52 * e.g. with `CFLAGS="-DDEFAULTLANG=fr" ./configure'
[60f7018]53 */
54#ifndef DEFAULTLANG
[4432f2e]55# define DEFAULTLANG "en"
[60f7018]56#endif
57
58/* For funcs which want to be immune from messing around with different
59 * calling conventions */
60#ifndef CDECL
[2ca296b]61# define CDECL
[60f7018]62#endif
63
[25ab06b]64int msg_warnings = 0; /* keep track of how many warnings we've given */
65int msg_errors = 0;   /* and how many (non-fatal) errors */
[60f7018]66
67/* in case osmalloc() fails before szAppNameCopy is set up */
[bd1913f]68static const char *szAppNameCopy = "anonymous program";
[60f7018]69
70/* error code for failed osmalloc and osrealloc calls */
[db75e18]71static void
72outofmem(OSSIZE_T size)
73{
[bd1913f]74   fatalerror(/*Out of memory (couldn't find %lu bytes).*/1,
75              (unsigned long)size);
[60f7018]76}
77
[a420b49]78#ifdef TOMBSTONES
79#define TOMBSTONE_SIZE 16
[bd1913f]80static const char tombstone[TOMBSTONE_SIZE] = "012345\xfftombstone";
[a420b49]81#endif
82
[60f7018]83/* malloc with error catching if it fails. Also allows us to write special
84 * versions easily eg for DOS EMS or MS Windows.
85 */
[bd1913f]86void FAR *
[db75e18]87osmalloc(OSSIZE_T size)
88{
[60f7018]89   void FAR *p;
[a420b49]90#ifdef TOMBSTONES
91   size += TOMBSTONE_SIZE * 2;
92   p = malloc(size);
93#else
[db75e18]94   p = xosmalloc(size);
[a420b49]95#endif
[2ca296b]96   if (p == NULL) outofmem(size);
[a420b49]97#ifdef TOMBSTONES
[bd1913f]98   printf("osmalloc truep=%p truesize=%d\n", p, size);
[a420b49]99   memcpy(p, tombstone, TOMBSTONE_SIZE);
100   memcpy(p + size - TOMBSTONE_SIZE, tombstone, TOMBSTONE_SIZE);
101   *(size_t *)p = size;
102   p += TOMBSTONE_SIZE;
103#endif
[60f7018]104   return p;
105}
106
107/* realloc with error catching if it fails. */
[bd1913f]108void FAR *
[db75e18]109osrealloc(void *p, OSSIZE_T size)
110{
[a420b49]111   /* some pre-ANSI realloc implementations don't cope with a NULL pointer */
112   if (p == NULL) {
113      p = xosmalloc(size);
114   } else {
115#ifdef TOMBSTONES
116      int true_size;
117      size += TOMBSTONE_SIZE * 2;
118      p -= TOMBSTONE_SIZE;
119      true_size = *(size_t *)p;
[bd1913f]120      printf("osrealloc (in truep=%p truesize=%d)\n", p, true_size);
[a420b49]121      if (memcmp(p + sizeof(size_t), tombstone + sizeof(size_t),
122                 TOMBSTONE_SIZE - sizeof(size_t)) != 0) {
123         printf("start tombstone for block %p, size %d corrupted!",
[cb3d1e2]124                p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]125      }
126      if (memcmp(p + true_size - TOMBSTONE_SIZE, tombstone,
127                 TOMBSTONE_SIZE) != 0) {
128         printf("end tombstone for block %p, size %d corrupted!",
[cb3d1e2]129                p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]130      }
131      p = realloc(p, size);
132      if (p == NULL) outofmem(size);
[bd1913f]133      printf("osrealloc truep=%p truesize=%d\n", p, size);
[a420b49]134      memcpy(p, tombstone, TOMBSTONE_SIZE);
135      memcpy(p + size - TOMBSTONE_SIZE, tombstone, TOMBSTONE_SIZE);
136      *(size_t *)p = size;
137      p += TOMBSTONE_SIZE;
138#else
139      p = xosrealloc(p, size);
140#endif
141   }
[2ca296b]142   if (p == NULL) outofmem(size);
[60f7018]143   return p;
144}
145
[bd1913f]146void FAR *
[db75e18]147osstrdup(const char *str)
148{
[60f7018]149   char *p;
[db75e18]150   OSSIZE_T len;
151   len = strlen(str) + 1;
[2ca296b]152   p = osmalloc(len);
[db75e18]153   memcpy(p, str, len);
[60f7018]154   return p;
155}
156
[a420b49]157/* osfree is usually just a macro in osalloc.h */
158#ifdef TOMBSTONES
[bd1913f]159void
[a420b49]160osfree(void *p)
161{
162   int true_size;
163   if (!p) return;
164   p -= TOMBSTONE_SIZE;
165   true_size = *(size_t *)p;
[bd1913f]166   printf("osfree truep=%p truesize=%d\n", p, true_size);
[a420b49]167   if (memcmp(p + sizeof(size_t), tombstone + sizeof(size_t),
168              TOMBSTONE_SIZE - sizeof(size_t)) != 0) {
169      printf("start tombstone for block %p, size %d corrupted!",
[cb3d1e2]170             p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]171   }
172   if (memcmp(p + true_size - TOMBSTONE_SIZE, tombstone,
173              TOMBSTONE_SIZE) != 0) {
174      printf("end tombstone for block %p, size %d corrupted!",
[cb3d1e2]175             p + TOMBSTONE_SIZE, true_size - TOMBSTONE_SIZE * 2);
[a420b49]176   }
177   free(p);
178}
179#endif
[60f7018]180
181#ifdef HAVE_SIGNAL
182
183static int sigReceived;
184
185/* for systems not using autoconf, assume the signal handler returns void
186 * unless specified elsewhere */
187#ifndef RETSIGTYPE
[2ca296b]188# define RETSIGTYPE void
[60f7018]189#endif
190
[bd1913f]191static CDECL RETSIGTYPE FAR
192report_sig(int sig)
193{
[db75e18]194   sigReceived = sig;
[2ca296b]195   longjmp(jmpbufSignal, 1);
[60f7018]196}
197
[db75e18]198static void
199init_signals(void)
200{
[60f7018]201   int en;
202   if (!setjmp(jmpbufSignal)) {
[647407d]203#if 1 /* disable these to get a core dump */
[db75e18]204      signal(SIGABRT, report_sig); /* abnormal termination eg abort() */
205      signal(SIGFPE,  report_sig); /* arithmetic error eg /0 or overflow */
206      signal(SIGILL,  report_sig); /* illegal function image eg illegal instruction */
207      signal(SIGSEGV, report_sig); /* illegal storage access eg access outside memory limits */
208#endif
[60f7018]209# ifdef SIGSTAK /* only on RISC OS AFAIK */
[db75e18]210      signal(SIGSTAK, report_sig); /* stack overflow */
[60f7018]211# endif
212      return;
213   }
[db75e18]214
[60f7018]215   switch (sigReceived) {
[bd1913f]216      case SIGABRT: en = /*Abnormal termination*/90; break;
217      case SIGFPE:  en = /*Arithmetic error*/91; break;
218      case SIGILL:  en = /*Illegal instruction*/92; break;
219      case SIGSEGV: en = /*Bad memory access*/94; break;
[60f7018]220# ifdef SIGSTAK
[bd1913f]221      case SIGSTAK: en = /*Stack overflow*/96; break;
[60f7018]222# endif
[bd1913f]223      default:      en = /*Unknown signal received*/97; break;
[60f7018]224   }
[db75e18]225   fputsnl(msg(en), STDERR);
[647407d]226#if 0
227   /* Not useful to display errno - it's just left from the last library
228    * call which failed... */
[60f7018]229   if (errno >= 0) {
230# ifdef HAVE_STRERROR
[db75e18]231      fputsnl(strerror(errno), STDERR);
[60f7018]232# elif defined(HAVE_SYS_ERRLIST)
[db75e18]233      if (errno < sys_nerr) fputsnl(STDERR, sys_errlist[errno]);
[60f7018]234# elif defined(HAVE_PERROR)
235      perror(NULL); /* always goes to stderr */
236      /* if (arg!=NULL && *arg!='\0') fputs("<arg>: <err>\n",stderr); */
237      /* else fputs("<err>\n",stderr); */
238# else
[db75e18]239      fprintf(STDERR, "error code %d\n", errno);
[60f7018]240# endif
241   }
[647407d]242#endif
[c0a9908]243   /* Any of the signals we catch indicates a bug */
244   fatalerror(/*Bug in program detected! Please report this to the authors*/11);
[db75e18]245
[60f7018]246   exit(EXIT_FAILURE);
247}
248#endif
249
[bd1913f]250static int
251default_charset(void)
252{
[60f7018]253#ifdef ISO8859_1
254   return CHARSET_ISO_8859_1;
255#elif (OS==RISCOS)
[2ca296b]256/* RISCOS 3.1 and above CHARSET_RISCOS31 (ISO_8859_1 + extras in 128-159)
[647407d]257 * FIXME: RISCOS < 3.1 is ISO_8859_1 */
[2ca296b]258   return CHARSET_RISCOS31;
[60f7018]259#elif (OS==MSDOS)
260   return CHARSET_DOSCP850;
261#else
[647407d]262   return CHARSET_ISO_8859_1; /* FIXME: Look at env var CHARSET ? */
[60f7018]263#endif
264}
265
[48e4121]266#if (OS==MSDOS)
[db75e18]267static int
268xlate_dos_cp850(int unicode)
269{
[48e4121]270   switch (unicode) {
[d41b1353]271#include "uni2dos.h"
[48e4121]272   }
273   return 0;
274}
275#endif
276
[db75e18]277static int
[55de792]278add_unicode(int charset, unsigned char *p, int value)
[db75e18]279{
[55de792]280#ifdef DEBUG
281   fprintf(stderr, "add_unicode(%d, %p, %d)\n", charset, p, value);
282#endif
[4432f2e]283   if (value == 0) return 0;
[48e4121]284   switch (charset) {
[db75e18]285   case CHARSET_USASCII:
[6a4871e]286      if (value < 0x80) {
[48e4121]287         *p = value;
288         return 1;
289      }
290      break;
[db75e18]291   case CHARSET_ISO_8859_1:
[48e4121]292#if (OS==RISCOS)
[db75e18]293   case CHARSET_RISCOS31: /* RISC OS 3.1 has a few extras in 128-159 */
[48e4121]294#endif
[6a4871e]295      if (value < 0x100) {
[48e4121]296         *p = value;
297         return 1;
298      }
299#if (OS==RISCOS)
[db75e18]300      /* FIXME: if OS version >= 3.1 handle extras here */
301      /* RISC OS 3.1 (and later) extensions to ISO-8859-1:
302       * \^y = \x86
303       * \^Y = \x85
304       * \^w = \x82
305       * \^W = \x81
306       * \oe = \x9b
307       * \OE = \x9a
308       */
[48e4121]309#endif
310      break;
311#if (OS==MSDOS)
[db75e18]312   case CHARSET_DOSCP850:
[48e4121]313      value = xlate_dos_cp850(value);
314      if (value) {
315         *p = value;
316         return 1;
317      }
318      break;
319#endif
[4432f2e]320   }
[f1a5201]321   return 0;
[4432f2e]322}
323
[f2a6ce4]324/* fall back on looking in the current directory */
325static const char *pth_cfg_files = "";
326
[db75e18]327static int num_msgs = 0;
[55de792]328static char **msg_array = NULL;
[db75e18]329
[b83f907]330const char *msg_lang = NULL;
[c0a9908]331const char *msg_lang2 = NULL;
[b83f907]332
[db75e18]333static void
334parse_msg_file(int charset_code)
335{
336   FILE *fh;
337   unsigned char header[20];
[4432f2e]338   int i;
[db75e18]339   unsigned len;
[55de792]340   unsigned char *p;
[cb3d1e2]341
[55de792]342#ifdef DEBUG
343   fprintf(stderr, "parse_msg_file(%d)\n", charset_code);
344#endif
[db75e18]345
[a2f9d5c]346   msg_lang = getenv("SURVEXLANG");
[55de792]347#ifdef DEBUG
348   fprintf(stderr, "lang = %p (= \"%s\")\n", lang, lang?lang:"(null)");
349#endif
[cb3d1e2]350
[a2f9d5c]351   if (!msg_lang || !*msg_lang) {
352      msg_lang = getenv("LANG");
353      if (!msg_lang || !*msg_lang) msg_lang = DEFAULTLANG;
[32232b2]354   }
[55de792]355#ifdef DEBUG
[a2f9d5c]356   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang, msg_lang?msg_lang:"(null)");
[55de792]357#endif
[db75e18]358
359#if 1
360   /* backward compatibility - FIXME deprecate? */
[a2f9d5c]361   if (strcasecmp(msg_lang, "engi") == 0) {
362      msg_lang = "en";
363   } else if (strcasecmp(msg_lang, "engu") == 0) {
[c0a9908]364      msg_lang = "en_US";
[a2f9d5c]365   } else if (strcasecmp(msg_lang, "fren") == 0) {
366      msg_lang = "fr";
367   } else if (strcasecmp(msg_lang, "germ") == 0) {
368      msg_lang = "de";
369   } else if (strcasecmp(msg_lang, "ital") == 0) {
370      msg_lang = "it";
371   } else if (strcasecmp(msg_lang, "span") == 0) {
372      msg_lang = "es";
373   } else if (strcasecmp(msg_lang, "cata") == 0) {
374      msg_lang = "ca";
375   } else if (strcasecmp(msg_lang, "port") == 0) {
376      msg_lang = "pt";
[48e4121]377   }
[db75e18]378#endif
[55de792]379#ifdef DEBUG
[bd1913f]380   fprintf(stderr, "msg_lang = %p (= \"%s\")\n", msg_lang,
381           msg_lang ? msg_lang : "(null)");
[55de792]382#endif
[db75e18]383
[647407d]384   /* On Mandrake LANG defaults to C */
[a2f9d5c]385   if (strcmp(msg_lang, "C") == 0) msg_lang = "en";
386
[c0a9908]387   /* Convert en-us to en_US, etc */
388   if (strchr(msg_lang, '-')) {
[a2f9d5c]389      char *lang = osstrdup(msg_lang);
[c0a9908]390      char *dash = strchr(lang, '-');
391      *dash++ = '_';
392      while (*dash) {
393         *dash = toupper(*dash);
394         dash++;
[b4ab19e]395      }
[a2f9d5c]396      msg_lang = lang;
[6d54808]397   }
398
[c0a9908]399   if (strchr(msg_lang, '_')) {
400      char *under;
401      msg_lang2 = osstrdup(msg_lang);
402      under = strchr(msg_lang2, '_');
403      *under = '\0';
404   }
405
[c2aedee]406#ifdef LC_MESSAGES
[f764581]407   /* try to setlocale() appropriately too */
[c0a9908]408   if (!setlocale(LC_MESSAGES, msg_lang)) {
409      if (msg_lang2) setlocale(LC_MESSAGES, msg_lang2);
[b3756e0]410   }
[c2aedee]411#endif
[b3756e0]412   
[a2f9d5c]413   fh = fopenWithPthAndExt(pth_cfg_files, msg_lang, EXT_SVX_MSG, "rb", NULL);
[db75e18]414
415   if (!fh) {
416      /* e.g. if 'en-COCKNEY' is unknown, see if we know 'en' */
[a2f9d5c]417      if (strlen(msg_lang) > 3 && msg_lang[2] == '-') {
[db75e18]418         char lang_generic[3];
[a2f9d5c]419         lang_generic[0] = msg_lang[0];
420         lang_generic[1] = msg_lang[1];
[db75e18]421         lang_generic[2] = '\0';
[f2a6ce4]422         fh = fopenWithPthAndExt(pth_cfg_files, lang_generic, EXT_SVX_MSG,
423                                 "rb", NULL);
[a2f9d5c]424         if (fh) msg_lang = osstrdup(lang_generic);
[db75e18]425      }
[48e4121]426   }
[db75e18]427
428   if (!fh) {
[bd1913f]429      /* no point extracting this error as it won't get used if file opens */
[759fb47]430      fprintf(STDERR, "Can't open message file `%s' using path `%s'\n",
[a2f9d5c]431              msg_lang, pth_cfg_files);
[db75e18]432      exit(EXIT_FAILURE);
[4432f2e]433   }
[db75e18]434
435   if (fread(header, 1, 20, fh) < 20 ||
436       memcmp(header, "Svx\nMsg\r\n\xfe\xff", 12) != 0) {
[bd1913f]437      /* no point extracting this error as it won't get used if file opens */
[759fb47]438      fprintf(STDERR, "Problem with message file `%s'\n", msg_lang);
[db75e18]439      exit(EXIT_FAILURE);
440   }
441
442   if (header[12] != 0) {
[bd1913f]443      /* no point extracting this error as it won't get used if file opens */
[db75e18]444      fprintf(STDERR, "I don't understand this message file version\n");
445      exit(EXIT_FAILURE);
446   }
447
448   num_msgs = (header[14] << 8) | header[15];
449
450   len = 0;
451   for (i = 16; i < 20; i++) len = (len << 8) | header[i];
452
[55de792]453   p = osmalloc(len);
454   if (fread(p, 1, len, fh) < len) {
[bd1913f]455      /* no point extracting this error - translation will never be used */
[db75e18]456      fprintf(STDERR, "Message file truncated?\n");
457      exit(EXIT_FAILURE);
458   }
[a420b49]459   fclose(fh);
[db75e18]460
[55de792]461#ifdef DEBUG
[759fb47]462   fprintf(stderr, "msg_lang = `%s', num_msgs = %d, len = %d\n", msg_lang,
[bd1913f]463           num_msgs, len);
[55de792]464#endif
465
466   msg_array = osmalloc(sizeof(char *) * num_msgs);
467
[db75e18]468   for (i = 0; i < num_msgs; i++) {
[55de792]469      unsigned char *to = p;
[db75e18]470      int ch;
[55de792]471      msg_array[i] = (char *)p;
[6a4871e]472
473      /* If we want UTF8 anyway, we just need to find the start of each
474       * message */
475      if (charset_code == CHARSET_UTF8) {
[49090c02]476         p += strlen((char *)p) + 1;
[6a4871e]477         continue;
[cb3d1e2]478      }
[6a4871e]479
[db75e18]480      while ((ch = *p++) != 0) {
481         /* A byte in the range 0x80-0xbf or 0xf0-0xff isn't valid in
482          * this state, (0xf0-0xfd mean values > 0xffff) so treat as
483          * literal and try to resync so we cope better when fed
484          * non-utf-8 data.  Similarly we abandon a multibyte sequence
485          * if we hit an invalid character. */
486         if (ch >= 0xc0 && ch < 0xf0) {
487            int ch1 = *p;
488            if ((ch1 & 0xc0) != 0x80) goto resync;
[cb3d1e2]489
[db75e18]490            if (ch < 0xe0) {
491               /* 2 byte sequence */
492               ch = ((ch & 0x1f) << 6) | (ch1 & 0x3f);
493               p++;
494            } else {
495               /* 3 byte sequence */
496               int ch2 = p[1];
497               if ((ch2 & 0xc0) != 0x80) goto resync;
498               ch = ((ch & 0x1f) << 12) | ((ch1 & 0x3f) << 6) | (ch2 & 0x3f);
499               p += 2;
500            }
501         }
[cb3d1e2]502
[db75e18]503         resync:
[cb3d1e2]504
[db75e18]505         if (ch < 127) {
506            *to++ = (char)ch;
507         } else {
[bd1913f]508            /* FIXME: this rather assumes a 2 byte UTF-8 code never
[db75e18]509             * transliterates to more than 2 characters */
510            to += add_unicode(charset_code, to, ch);
511         }
512      }
513      *to++ = '\0';
514   }
[4432f2e]515}
516
[f2a6ce4]517const char *
518msg_cfgpth(void)
519{
520   return pth_cfg_files;
521}
522
523void
524msg_init(const char *argv0)
[db75e18]525{
526   char *p;
527
528#ifdef HAVE_SIGNAL
529   init_signals();
530#endif
531   /* This code *should* be completely bomb-proof even if strcpy
532    * generates a signal
533    */
534   szAppNameCopy = argv0; /* FIXME... */
535   szAppNameCopy = osstrdup(argv0);
536
537   /* Look for env. var. "SURVEXHOME" or the like */
538   p = getenv("SURVEXHOME");
539   if (p && *p) {
[f2a6ce4]540      pth_cfg_files = osstrdup(p);
[18f4759]541#if (OS==UNIX) && defined(DATADIR) && defined(PACKAGE)
[a420b49]542   } else {
543      /* under Unix, we compile in the configured path */
[18f4759]544      pth_cfg_files = DATADIR "/" PACKAGE;
[a420b49]545#else
[db75e18]546   } else if (argv0) {
547      /* else try the path on argv[0] */
[f2a6ce4]548      pth_cfg_files = path_from_fnm(argv0);
[a420b49]549#endif
[db75e18]550   }
551
552   select_charset(default_charset());
553}
554
[bd1913f]555/* message may be overwritten by next call
556 * (but not in current implementation) */
557const char *
[db75e18]558msg(int en)
559{
[eee67ab]560   /* NB can't use ASSERT here! */
561   static char badbuf[256];
[55de792]562   if (!msg_array) {
[eee67ab]563      if (en != 1)  {
564         sprintf(badbuf, "Message %d requested before msg_array initialised\n", en);
565         return badbuf;
566      }
[a420b49]567      /* this should be the only message which can be requested before
568       * the message file is opened and read... */
569      return "Out of memory (couldn't find %ul bytes).\n";
[db75e18]570   }
571
[eee67ab]572   if (en < 0 || en >= num_msgs) {
573      sprintf(badbuf, "Message %d out of range\n", en);
574      return badbuf;
575   }
[db75e18]576
[55de792]577   return msg_array[en];
[db75e18]578}
579
580/* returns persistent copy of message */
[bd1913f]581const char *
[db75e18]582msgPerm(int en)
583{
584   return msg(en);
585}
586
587void
588v_report(int severity, const char *fnm, int line, int en, va_list ap)
589{
590   if (fnm) {
591      fputs(fnm, STDERR);
592      if (line) fprintf(STDERR, ":%d", line);
593   } else {
594      fputs(szAppNameCopy, STDERR);
[cb3d1e2]595   }
[db75e18]596   fputs(": ", STDERR);
597
598   if (severity == 0) {
599      fputs(msg(/*warning*/4), STDERR);
600      fputs(": ", STDERR);
601   }
602
603   vfprintf(STDERR, msg(en), ap);
604   fputnl(STDERR);
[cb3d1e2]605
[647407d]606   /* FIXME: allow "warnings are errors" and/or "errors are fatal" */
[db75e18]607   switch (severity) {
608    case 0:
[25ab06b]609      msg_warnings++;
[db75e18]610      break;
611    case 1:
[25ab06b]612      msg_errors++;
613      if (msg_errors == 50)
[db75e18]614         fatalerror_in_file(fnm, 0, /*Too many errors - giving up*/19);
615      break;
616    case 2:
617      exit(EXIT_FAILURE);
618   }
619}
620
621void
622warning(int en, ...)
623{
624   va_list ap;
625   va_start(ap, en);
626   v_report(0, NULL, 0, en, ap);
627   va_end(ap);
628}
629
630void
631error(int en, ...)
632{
633   va_list ap;
634   va_start(ap, en);
635   v_report(1, NULL, 0, en, ap);
636   va_end(ap);
637}
638
639void
640fatalerror(int en, ...)
641{
642   va_list ap;
643   va_start(ap, en);
644   v_report(2, NULL, 0, en, ap);
645   va_end(ap);
646}
647
648void
649warning_in_file(const char *fnm, int line, int en, ...)
650{
651   va_list ap;
652   va_start(ap, en);
653   v_report(0, fnm, line, en, ap);
654   va_end(ap);
655}
656
657void
658error_in_file(const char *fnm, int line, int en, ...)
659{
660   va_list ap;
661   va_start(ap, en);
662   v_report(1, fnm, line, en, ap);
663   va_end(ap);
664}
665
666void
667fatalerror_in_file(const char *fnm, int line, int en, ...)
668{
669   va_list ap;
670   va_start(ap, en);
671   v_report(2, fnm, line, en, ap);
672   va_end(ap);
673}
674
675/* Code to support switching character set at runtime (e.g. for a printer
676 * driver to support different character sets on screen and on the printer)
677 */
678typedef struct charset_li {
679   struct charset_li *next;
680   int code;
[55de792]681   char **msg_array;
[db75e18]682} charset_li;
683
684static charset_li *charset_head = NULL;
685
686static int charset = CHARSET_BAD;
687
688int
689select_charset(int charset_code)
690{
691   int old_charset = charset;
692   charset_li *p;
693
[55de792]694#ifdef DEBUG
[bd1913f]695   fprintf(stderr, "select_charset(%d), old charset = %d\n", charset_code,
696           charset);
[55de792]697#endif
[cb3d1e2]698
[db75e18]699   charset = charset_code;
700
701   /* check if we've already parsed messages for new charset */
702   for (p = charset_head; p; p = p->next) {
[55de792]703#ifdef DEBUG
704      printf("%p: code %d msg_array %p\n", p, p->code, p->msg_array);
705#endif
[db75e18]706      if (p->code == charset) {
[55de792]707         msg_array = p->msg_array;
[db75e18]708         return old_charset;
709      }
710   }
711
712   /* nope, got to reparse message file */
713   parse_msg_file(charset_code);
714
715   /* add to list */
716   p = osnew(charset_li);
717   p->code = charset;
[55de792]718   p->msg_array = msg_array;
[db75e18]719   p->next = charset_head;
720   charset_head = p;
721
722   return old_charset;
723}
Note: See TracBrowser for help on using the repository browser.