source: git/src/message.c @ c1cf79d

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

Fixes for clean compilation on RISC OS.

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

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