source: git/src/message.c @ 350b2a6

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 350b2a6 was 647407d, checked in by Olly Betts <olly@…>, 25 years ago

Lots of fixes from CUCC 2000 Expo:

  • cavern: *fix with error values (one for same all round, two for horizontal and vertical, three for x, y, z)
  • Fixed RISC OS not treating "foo." as a directory
  • Improved behaviour when sgmltools not installed
  • cavern: Merged patches for generating .3dx files for chasm
  • Miscellaneous code tidying
  • Moved unresolvable issues from BUGS to ZOMBIES
  • cavern: Fixed articulation code bug (handling of some cases of components with multiple fixed points); added regression test
  • cavern: "*begin" / "*end foo" now gives more explicit error
  • cavern: More work on gross error detection
  • xcaverot: you can now set environmental variables XCAVEROT_FONTNAME, XCAVEROT_INDICATOR_RADIUS
  • extend: now starts from highest station with only one leg. If no such station exists then revert to the previous behaviour of starting from the highest station (but complain if we have no legs at all).
  • cavern: line numbers now correct for .svx files with Mac style lineends
  • cavern: improved error reporting in several cases
  • caverot: on RISC OS now fall back to using 2 or even just one screen bank if we can't find a mode where we can create 3 banks [FIXME: need to test this works]
  • cavern: added data styles "TOPOFIL" (like tape/compass/clino but with a counter instead of the tape), "CARTESIAN" (dx, dy, dz), and "NOSURVEY" (for unsurveyed connections between surveys)
  • cavern: can now suppress "unused fixed point" error on a station by station basis by using: "*fix <station> reference <coords>"
  • cavern: new command "*require <version>" to allow survey data to specify the minimum survex version required to process it
  • print*: now search multiple print.ini files so you can override settings in the shipped file rather than having to modify it. Search order is: ~/.survex/print.ini (unix only), $SURVEXHOME/myprint.ini, $SURVEXHOME/print.ini
  • Changed xcaverot rotation/zoom to be the same way round as caverot
  • diffpos, extend, xcaverot, caverot: Now use cmdline library to parse command line arguments and so support --help, --version, etc.
  • hto2svx, svx2hto, and survex wrapper now all support --help and --version
  • `configure --disable-aven' now disables building of aven
  • caverot: on RISC OS fall back to using 2 or just 1 screen bank if there's not enough video memory allocated for 3.
  • Documentation brought more up to date.
  • If a station is only referenced once, and that reference is in a *equate and with an explicit prefix (e.g. "*equate 1 possibletypo.6"), a warning is issued.
  • configure now autoprobes compiler for 16 and 32 bit types so osdepend.h no longer needs to list them for each platform.
  • Removed pointless check for floating point support - it was only implemented for RISC OS and without FP the program falls over during initialisation and never gets to the check.
  • Rearranged caverot sources to make use of cvrotimg from other programs cleaner.
  • Minor enhancements to cmdline library.
  • Strings read by get_token now reported with original case in error messages.
  • Handle LANG=C (Mandrake Linux) and LANG=en_US (RedHat? 6.1).

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

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