source: git/src/message.c @ ce81278

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 ce81278 was 48e4121, checked in by Olly Betts <olly@…>, 27 years ago

Sorted out character entities

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

  • Property mode set to 100644
File size: 33.6 KB
RevLine 
[60f7018]1/* message.c */
2
[a3e49dc]3/* ERRC show diffs to newer version of error.c - most that are left in here aren't relevant */
4
[60f7018]5/* loosely based on Survex's error.c, but uses SGML entities for accented
6 * characters, and is rather more generic */
7
8/* maps: */
9
10/* (perfect hash) entity name to &#nnn; code */
11
12/* (lookup table or switch) &#nnn; code to best rendition in each charset */
13
14
15/* filename.c split off with filename manipulation stuff */
16
17
18/* > error.c
19 * Fairly general purpose error routines and path handling code
20 * Copyright (C) 1993-1997 Olly Betts
21 */
22
23/*
241993.01.25 PC Compatibility OKed
251993.01.27 print newline before error messages
261993.02.17 changed #ifdef RISCOS to #if OS==...
271993.02.19 now look for ErrList in dir main exec was in
28           for PC ERRLIST -> ERRLIST.TXT
291993.02.23 now do exit(EXIT_FAILURE) or exit(EXIT_SUCCESS)
30           added guessed UNIX stuff
311993.03.12 Major recode to make it less crap. Especially:
32           Now copes with *any* undefined message number
33           Error file now has spaces, not underscores
341993.03.16 Merged 'PathCode.c' with this file. Updates for 'PathCode.c' were:
35>> 1993.02.19 written
36>> 1993.02.23 added guess at UNIX code
37>> 1993.02.24 (W) add (int) cast to suppress warning calculating lenpth
38>> 1993.02.25 Don't look for FNM_SEP_DRV if it's not defined
391993.03.18 Added LfFromFnm()
401993.03.19 Corrected bug which caused infinite loop for PC text error file
411993.04.06 slight fettles and copied fn headers to error.c
421993.04.07 Added UsePth()
43           #error Don't ... -> #error Do not ... for GCC's happiness
441993.04.22 added fopenWithPthAndExt()
45           added application name code
461993.04.25 added AMIGA version
471993.05.05 Slightly more elegant hack than Wook's to solve BC++ stderr bug
481993.05.12 (W) added FNTYPE for different DOS memory model proofing (non-ANSI)
491993.05.22 (W) removed stderr hack as it is not that simple???
50               improved 'error file not found' reporting
511993.05.27 removed commented out #define STDERR ...
52           actually improved 'error file not found' et al - personally I do
53            *not* regard caverot telling me 'SURVEX: <error message>' as an
54            improvement. Mind you, I'm fussy.
551993.05.28 added signal catching code
561993.05.29 errno printed when signal received
571993.06.04 moved #define FNM_SEP_XXX to filelist.h
58           added #ifdef SIGSTAK as unix GCC doesn't seem to have it
591993.06.05 removed 'superfluous' &'s in signal fns
60           signal catcher now uses strerror()
611993.06.07 Unix libraries don't have strerror() - so don't use it!
62           FNTYPE -> FAR to aid comprehension
631993.06.10 in report_sig() only print out errno if non-zero
641993.06.12 fixed bug in path&ext code: only added .ext when prepending path
651993.06.16 syserr() -> fatal(); osmalloc() added; char* -> sz
66           osrealloc() added; osfree() comment added
671993.06.28 fixed bug which lost first character of each error message on
68            big-endian machines
69           fixed fopenWithPthAndExt() to osfree() fnmFull
701993.07.19 "common.h" -> "osdepend.h"
711993.07.27 changed "error number %d" to "#%d" in output
721993.08.10 added '\n' before errors reported in report_sig
731993.08.12 added more bomb-proofing
741993.08.13 fettled header
751993.08.16 added fAbsoluteFnm & fAmbiguousFnm; recoded fopenWithPthAndExt
76           RISC OS version of fopenWithPthAndExt copes with "<My$Dir>.File"
77           added AddExt; added pfExtUsed arg to fopenWithPthAndExt
781993.08.19 ./ in DOS is ambiguous, not absolute
791993.09.21 (W)fixed relative paths without preceding .\ for .svc files
80           (W)changed DOS fAbsolute() so 'c:here' is returned as ambiguous
811993.09.22 (W)changed error functions for more general info line
82           (W)added function list
831993.09.23 (IH)DOS uses farmalloc,farrealloc,farfree; osmalloc() takes a long
841993.10.15 (BP)changed erroneous ifdef MSDOS's to if (OS==MSDOS)
851993.10.18 (W)fWarningGiven added
861993.10.23 corrected fFALSE to fFalse
871993.11.03 changed error routines
88           cWarnings rather than fWarningGiven
89           fettled a bit
901993.11.05 OSSIZE_T added
91           fixed problem with pth=="" in fopenWithPthAndExt
92           added msg() and msgPerm()
931993.11.07 merged out of memory code from osmalloc & osrealloc
941993.11.08 added code to deal with quoted messages
951993.11.14 fettled
961993.11.15 added xosmalloc (returns NULL if malloc fails)
971993.11.18 xosrealloc added as macro in error.h
98           added calls to fDirectory
991993.11.19 added TeX style escape sequences for accents; also ``,'' for "
1001993.11.20 minor change to '' and `` code
101           \/O & \/o now used for slashed Os
102           extracted tables to tex.h
1031993.11.26 moved chOpenQuotes & chCloseQuotes to tex.h
1041993.11.28 added NO_TEX to turn it off for now
1051993.11.29 (IH) void * FAR -> void FAR * ; void * FILE -> void FILE *
106           use perror in UNIX version
107           extracted messages from here too! (except for signal ones)
1081993.11.30 corrected Wook's ungroks in function list
109           error now returns (it was wrong, but limp on); use fatal to abort
110           added cErrors
1111993.12.01 added error_summary()
112           most signals tell the user to report them as a bug (autograss?)
113           check version of messages.txt file
1141993.12.08 split off osdepend.c
1151993.12.09 now makes less explicit reference to OS
1161993.12.16 farmalloc use controlled by NO_FLATDOS macro
117           fixed error bootstrap code problem-ette
1181993.12.17 wr changed to send to stderr as it writes error info
1191994.01.05 added missing FAR to fix >128 eqns bug
120           and another
121           bug-fixed in outofmem
1221994.03.13 enabled TeX style characters
123           will deal with `` and '' even if NO_TEX is defined
1241994.03.14 altered fopenWithPthAndExt to give filename actually used
1251994.03.19 signals now reported as `fatal error' since they are
126           all error output to do with signals is now sent to stderr
1271994.03.20 added a putnl() at end of error_summary()
1281994.03.24 error summary to stderr too
1291994.04.27 cWarnings and cErrors now static
1301994.06.03 fixed so SunOS version should cope with DOS error message file
1311994.06.09 added home directory environmental variable
1321994.06.18 fixed Norcroft warning
1331994.06.20 added int argument to warning, error and fatal
1341994.08.31 added fputnl()
1351994.09.13 added fix for caverot signals being invisible under RISC OS
1361994.09.13 removed 'cos it doesn't work
1371994.09.20 fixed signal handler to longjmp back so it's now truely ANSI
138           miscellaneous fettling
1391994.09.21 rearranged signal handler code to minimize stack use
1401994.09.22 should now be able to read multi-language message file
1411994.09.28 xosmalloc is now a macro in error.h
1421994.10.04 no longer pass NULL for szExt to fopenWithPathAndExt
1431994.10.05 DEFAULTLANG and szLangVar added
1441994.10.08 sizeof -> ossizeof
1451994.11.16 errno.h wanted even if we're not signal handling
1461994.11.23 UsePth and AddExt now insert a separator if appropriate
147           fopenWithPthAndExt now uses UsePth and AddExt
1481994.12.03 added FNM_SEP_LEV2
1491994.12.06 stderr -> STDERR; STDERR #defined to stdout
1501994.12.10 fopenWithPthAndExt() copes with NULL for pth or ext
1511995.03.25 added osstrdup
1521995.06.26 fixed bug with UsePth("",leafname)
1531995.10.06 commented out some debug code
1541995.10.11 fixed getline to take a buffer length
1551996.02.10 pszTable entries can now be NULL, as can szSingTab
1561996.02.19 fixed 2 sizeof() to ossizeof()
1571996.03.22 fettled layout
1581996.05.05 added CDECL
1591997.01.19 started code to support multiple charsets at once
1601997.01.22 finished off up charset code (merged in tex.h):
161>1993.11.20 created
162>1993.11.26 moved chOpenQuotes and chCloseQuotes to here too
163>1994.03.13 characters 128-159 translated to \xXX codes to placate compilers
164>1994.03.23 added caveat comment about top-bit-set characters
165>1994.12.03 added -DISO8859_1 to makefile to force iso-8859-1
166>1995.02.14 changed "char foo[]=" to "char *foo="
167>1996.02.10 pszTable is now an array of char *, which can be NULL
168>          szSingTab can also be NULL
[a3e49dc]1691997.06.05 added const
1701998.03.04 more const
1711998.03.21 fixed up to compile cleanly on Linux
[60f7018]172*/
173
174/* Beware: This file contains top-bit-set characters (160-255), so be     */
175/* careful of mailers, ascii ftp, etc                                     */
176
177/* Tables for TeX style accented chars, etc for use with Survex           */
178/* Copyright (C) Olly Betts 1993-1996                                     */
179
180/* NB if (as in TeX) \o and \O mean slashed-o and slashed-O, we can't
181 * have \oe and \OE for linked-oe and linked-OE without cleverer code.
182 * Therefore, I've changed slashed-o and slashed-O to \/o and \/O.
183 */
184
185/*
186Function List
187xosmalloc:       malloc, but indirected so we can eg do DOS XMS malloc
188osmalloc:        ditto, but traps failure and gives fatal error
189xosrealloc:      realloc, but indirected so we can eg do DOS XMS malloc
190osrealloc:       ditto, but traps failure and gives fatal error
191osfree:          free, but indirected so we can eg do DOS XMS malloc
192report_sig:      catches signals and prints explanatory message
193ReadErrorFile:   initialisation function - should be called first (ish)
194warning:         report warning
195error:           report error
196fatal:           report fatal error and exit
197fAbsoluteFnm:    is fnm definitely absolute?
198fAmbiguousFnm:   could fnm be interpreted as both absolute and relative?
199PthFromFnm:      extract path from fnm
200LfFromFnm:       extract leafname from fnm
201UsePth:          concatenate path & leafname
202UseExt:          bung an extension on
203fopenWithPthAndExt:
204                 open file, passing back filename actually used
205safe_fopen:      like fopen, but returns NULL for directories under all OS
206*/
207
208#include <stdio.h>
209#include <stdlib.h>
210#include <string.h>
211#include <ctype.h>
212#include <limits.h>
213#include <errno.h>
214
215#include "whichos.h"
[4432f2e]216#include "filename.h"
217#include "message.h"
[60f7018]218#include "osdepend.h"
219#include "filelist.h"
220#include "debug.h"
221#include "version.h"
222
223#ifdef HAVE_SIGNAL
224# ifdef HAVE_SETJMP
225#  include <setjmp.h>
226static jmp_buf jmpbufSignal;
227#  include <signal.h>
228# else
229#  undef HAVE_SIGNAL
230# endif
231#endif
232
233/* This is the name of the default language -- set like this so folks can
[4432f2e]234 * add (for eg) -DDEFAULTLANG="fr" to UFLG in the makefile
[60f7018]235 */
236#ifndef DEFAULTLANG
[4432f2e]237# define DEFAULTLANG "en"
[60f7018]238#endif
239
240#define STDERR stdout
241
242/* For funcs which want to be immune from messing around with different
243 * calling conventions */
244#ifndef CDECL
245#define CDECL
246#endif
247
248/* These are English versions of messages which might be needed before the
249 * alternative language version has been read from the message file.
250 */
251static const char * ergBootstrap[]={
252   "",
253   "Out of memory (couldn't find %ul bytes).\n",
254   "\nFatal error from %s: ",
255   "\nError from %s: ",
256   "\nWarning from %s: ",
257   "Message file has incorrect format\n", /* was "Error message file ..." */
258   "Negative error numbers are not allowed\n",
259   NULL /* NULL marks end of list */
260};
261
262static const char **erg = ergBootstrap;
263static int enMac = 32; /* Initially, grows automatically */
264static const char *szBadEn = "???";
265
266static int cWarnings = 0; /* keep track of how many warnings we've given */
267static int cErrors = 0;   /* and how many (non-fatal) errors */
268
269extern int error_summary(void) {
270   fprintf(STDERR,msg(16),cWarnings,cErrors);
271   fputnl(STDERR);
272   return ( cErrors ? EXIT_FAILURE : EXIT_SUCCESS );
273}
274
275/* in case osmalloc() fails before szAppNameCopy is set up */
276static const char *szAppNameCopy="anonymous program";
277
278/* error code for failed osmalloc and osrealloc calls */
279static void outofmem(OSSIZE_T size) {
280   fprintf( STDERR, erg[2], szAppNameCopy );
281   fprintf( STDERR, erg[1], (unsigned long)size );
282   exit(EXIT_FAILURE);
283}
284
285/* malloc with error catching if it fails. Also allows us to write special
286 * versions easily eg for DOS EMS or MS Windows.
287 */
288extern void FAR * osmalloc( OSSIZE_T size ) {
289   void FAR *p;
290   p=xosmalloc( size );
291   if (p==NULL)
292      outofmem(size);
293   return p;
294}
295
296/* realloc with error catching if it fails. */
297extern void FAR * osrealloc( void *p, OSSIZE_T size ) {
298   p=xosrealloc(p,size);
299   if (p==NULL)
300      outofmem(size);
301   return p;
302}
303
304extern void FAR * osstrdup( const char *sz ) {
305   char *p;
306   int len;
307   len=strlen(sz)+1;
308   p=osmalloc(len);
309   memmove(p,sz,len);
310   return p;
311}
312
313/* osfree is currently a macro in error.h */
314
315#ifdef HAVE_SIGNAL
316
317static int sigReceived;
318
319/* for systems not using autoconf, assume the signal handler returns void
320 * unless specified elsewhere */
321#ifndef RETSIGTYPE
322#define RETSIGTYPE void
323#endif
324
325static CDECL RETSIGTYPE FAR report_sig( int sig ) {
326   sigReceived=sig;
327   longjmp(jmpbufSignal,1);
328}
329
330static void init_signals( void ) {
331   int en;
332   if (!setjmp(jmpbufSignal)) {
333      signal(SIGABRT,report_sig); /* abnormal termination eg abort() */
334      signal(SIGFPE ,report_sig); /* arithmetic error eg /0 or overflow */
335      signal(SIGILL ,report_sig); /* illegal function image eg illegal instruction */
336      signal(SIGINT ,report_sig); /* interactive attention eg interrupt */
337      signal(SIGSEGV,report_sig); /* illegal storage access eg access outside memory limits */
338      signal(SIGTERM,report_sig); /* termination request sent to program */
339# ifdef SIGSTAK /* only on RISC OS AFAIK */
340      signal(SIGSTAK,report_sig); /* stack overflow */
341# endif
342      return;
343   }
344   fprintf(STDERR,msg(2),szAppNameCopy);
345   switch (sigReceived) {
346    case SIGABRT: en=90; break;
347    case SIGFPE:  en=91; break;
348    case SIGILL:  en=92; break;
349    case SIGINT:  en=93; break;
350    case SIGSEGV: en=94; break;
351    case SIGTERM: en=95; break;
352# ifdef SIGSTAK
353    case SIGSTAK: en=96; break;
354# endif
355    default:      en=97; break;
356   }
357   fputsnl(msg(en),STDERR);
358   if (errno >= 0) {
359# ifdef HAVE_STRERROR
360      fputsnl(strerror(errno),STDERR);
361# elif defined(HAVE_SYS_ERRLIST)
362      if (errno < sys_nerr)
363         fputsnl( STDERR, sys_errlist[errno] );
364# elif defined(HAVE_PERROR)
365      perror(NULL); /* always goes to stderr */
366      /* if (arg!=NULL && *arg!='\0') fputs("<arg>: <err>\n",stderr); */
367      /* else fputs("<err>\n",stderr); */
368# else
369      fprintf( STDERR, "error code %d\n", errno );
370# endif
371   }
372   if (sigReceived!=SIGINT && sigReceived!=SIGTERM)
373      fatal(11,NULL,NULL,0); /* shouldn't get any others => bug */
374   exit(EXIT_FAILURE);
375}
376#endif
377
378/* write string and nl to STDERR */
379extern void wr( const char *sz, int n ) {
380   n=n; /* suppress warning */
381   fputsnl(sz,STDERR);
382}
383
384#define CHARSET_BAD       -1
385#define CHARSET_USASCII    0
386#define CHARSET_ISO_8859_1 1
387#define CHARSET_DOSCP850   2
388#define CHARSET_RISCOS31   3
389static int default_charset( void ) {
390#ifdef ISO8859_1
391   return CHARSET_ISO_8859_1;
392#elif (OS==RISCOS)
393/*
[48e4121]394RISCOS 3.1 and above CHARSET_RISCOS31 !HACK!
[60f7018]395*/
[48e4121]396   return CHARSET_CHARSET_RISCOS31;
[60f7018]397#elif (OS==MSDOS)
398   return CHARSET_DOSCP850;
399#else
400   return CHARSET_ISO_8859_1; /*!HACK!*/
401#endif
402}
403
[4432f2e]404static const char *pthMe = NULL, *lfErrs = NULL;
405static char prefix[32];
[60f7018]406static int prefix_len;
407
[4432f2e]408static char prefix_root[32];
409static int prefix_root_len;
410
[48e4121]411#if (OS==MSDOS)
412static int xlate_dos_cp850(int unicode) {
413   switch (unicode) {
414/*# include "unicode-to-dos-cp-default.tab"*/
415case 160: return 255;
416case 161: return 173;
417case 162: return 189;
418case 163: return 156;
419case 164: return 207;
420case 165: return 190;
421case 167: return 245;
422case 168: return 249;
423case 169: return 184;
424case 170: return 166;
425case 171: return 174;
426case 172: return 170;
427case 173: return 240;
428case 174: return 169;
429#if 0
430case 175: return 223;
431case 175: return 238;
432#endif
433case 176: return 248;
434case 177: return 241;
435case 178: return 253;
436case 179: return 252;
437case 180: return 239;
438case 181: return 230;
439case 182: return 244;
440case 183: return 250;
441case 184: return 247;
442case 185: return 251;
443case 186: return 167;
444case 187: return 175;
445case 188: return 172;
446case 189: return 171;
447case 190: return 243;
448case 191: return 168;
449case 192: return 183;
450case 193: return 181;
451case 194: return 182;
452case 195: return 199;
453case 196: return 142;
454case 197: return 143;
455case 198: return 146;
456case 199: return 128;
457case 200: return 212;
458case 201: return 144;
459case 202: return 210;
460case 203: return 211;
461case 204: return 222;
462case 205: return 214;
463case 206: return 215;
464case 207: return 216;
465case 208: return 209;
466case 209: return 165;
467case 210: return 227;
468case 211: return 224;
469case 212: return 226;
470case 213: return 229;
471case 214: return 153;
472case 215: return 158;
473case 216: return 157;
474case 217: return 235;
475case 218: return 233;
476case 219: return 234;
477case 220: return 154;
478case 221: return 237;
479case 222: return 232;
480case 223: return 225;
481case 224: return 133;
482case 225: return 160;
483case 226: return 131;
484case 227: return 198;
485case 228: return 132;
486case 229: return 134;
487case 230: return 145;
488case 231: return 135;
489case 232: return 138;
490case 233: return 130;
491case 234: return 136;
492case 235: return 137;
493case 236: return 141;
494case 237: return 161;
495case 238: return 140;
496case 239: return 139;
497case 240: return 208;
498case 241: return 164;
499case 242: return 149;
500case 243: return 162;
501case 244: return 147;
502case 245: return 228;
503case 246: return 148;
504case 247: return 246;
505case 248: return 155;
506case 249: return 151;
507case 250: return 163;
508case 251: return 150;
509case 252: return 129;
510case 253: return 236;
511case 254: return 231;
512case 255: return 152;
513   }
514   return 0;
515}
516#endif
517
[4432f2e]518static int add_unicode(int charset, char *p, int value) {
519   if (value == 0) return 0;
[48e4121]520   switch (charset) {
521    case CHARSET_USASCII:
522      if (value < 128) {
523         *p = value;
524         return 1;
525      }
526      break;
527    case CHARSET_ISO_8859_1:
528#if (OS==RISCOS)
529    case CHARSET_RISCOS31: /* RISC OS 3.1 has a few extras in 128-159 */
530#endif
531      if (value < 256) {
532         *p = value;
533         return 1;
534      }
535#if (OS==RISCOS)
536      /* !HACK! handle extras here */
537#endif
538      break;
539#if (OS==MSDOS)
540    case CHARSET_DOSCP850:
541      value = xlate_dos_cp850(value);
542      if (value) {
543         *p = value;
544         return 1;
545      }
546      break;
547#endif
[4432f2e]548   }
[f1a5201]549   return 0;
[4432f2e]550}
551
552static int decode_entity(const char *entity, size_t len) {
[48e4121]553   unsigned long value;   
[4432f2e]554   int i;
[48e4121]555   
556   if (len > 6) return 0;
557   value = entity[0] - '0';
558   if (value >= 'a' - '0') {
559      value += 36 - ('a' - '0');
560   } else if (value >= 'A' - '0') {
561      value += 10 - ('A' - '0');
562   }
563   for (i = 1; i < 6 && i < len; i++) {
564      int c;
565      c = toupper(entity[i]) - '0';
566      if (c >= 'A' - '0') c += 10 - ('A' - '0');
567      value = value * 36 + c;
568   }
[4432f2e]569   switch (value) {
[48e4121]570    case 17477224u: return 198; /* AElig */
571    case 622057730u: return 193; /* Aacute */
572    case 17380344u: return 194; /* Acirc */
573    case 632809418u: return 192; /* Agrave */
574    case 18080044u: return 197; /* Aring */
575    case 654238130u: return 195; /* Atilde */
576    case 506253u: return 196; /* Auml */
577    case 746420205u: return 199; /* Ccedil */
578    case 19205u: return 208; /* ETH */
579    case 863922434u: return 201; /* Eacute */
580    case 24098808u: return 202; /* Ecirc */
581    case 874674122u: return 200; /* Egrave */
582    case 692877u: return 203; /* Euml */
583    case 1105787138u: return 205; /* Iacute */
584    case 30817272u: return 206; /* Icirc */
585    case 1116538826u: return 204; /* Igrave */
586    case 879501u: return 207; /* Iuml */
587    case 1440298418u: return 209; /* Ntilde */
588    case 1468584194u: return 211; /* Oacute */
589    case 40894968u: return 212; /* Ocirc */
590    case 1479335882u: return 210; /* Ograve */
591    case 1499211233u: return 216; /* Oslash */
592    case 1500764594u: return 213; /* Otilde */
593    case 1159437u: return 214; /* Ouml */
594    case 49534115u: return 222; /* THORN */
595    case 1831381250u: return 218; /* Uacute */
596    case 50972664u: return 219; /* Ucirc */
597    case 1842132938u: return 217; /* Ugrave */
598    case 1439373u: return 220; /* Uuml */
599    case 2073245954u: return 221; /* Yacute */
600    case 2194178306u: return 225; /* aacute */
601    case 61050360u: return 226; /* acirc */
602    case 61065986u: return 180; /* acute */
603    case 61147240u: return 230; /* aelig */
604    case 2204929994u: return 224; /* agrave */
605    case 61750060u: return 229; /* aring */
606    case 2226358706u: return 227; /* atilde */
607    case 1719309u: return 228; /* auml */
608    case 2284059123u: return 166; /* brvbar */
609    case 2318540781u: return 231; /* ccedil */
610    case 64496109u: return 184; /* cedil */
611    case 1791929u: return 162; /* cent */
612    case 1804966u: return 169; /* copy */
613    case 2349398399u: return 164; /* curren */
614    case 51064u: return 176; /* deg */
615    case 2389884098u: return 247; /* divide */
616    case 2436043010u: return 233; /* eacute */
617    case 67768824u: return 234; /* ecirc */
618    case 2446794698u: return 232; /* egrave */
619    case 52901u: return 240; /* eth */
620    case 1905933u: return 235; /* euml */
621    case 2524944998u: return 189; /* frac12 */
622    case 2524945000u: return 188; /* frac14 */
623    case 2524945072u: return 190; /* frac34 */
624    case 2677907714u: return 237; /* iacute */
625    case 74487288u: return 238; /* icirc */
626    case 74599509u: return 161; /* iexcl */
627    case 2688659402u: return 236; /* igrave */
628    case 2705600621u: return 191; /* iquest */
629    case 2092557u: return 239; /* iuml */
630    case 79443312u: return 171; /* laquo */
631    case 2252907u: return 175; /* macr */
632    case 81477924u: return 181; /* micro */
633    case 2933233805u: return 183; /* middot */
634    case 2301433u: return 160; /* nbsp */
635    case 64397u: return 172; /* not */
636    case 3012418994u: return 241; /* ntilde */
637    case 3040704770u: return 243; /* oacute */
638    case 84564984u: return 244; /* ocirc */
639    case 3051456458u: return 242; /* ograve */
640    case 2368275u: return 170; /* ordf */
641    case 2368282u: return 186; /* ordm */
642    case 3071331809u: return 248; /* oslash */
643    case 3072885170u: return 245; /* otilde */
644    case 2372493u: return 246; /* ouml */
645    case 2393398u: return 182; /* para */
646    case 3120483695u: return 177; /* plusmn */
647    case 86819881u: return 163; /* pound */
648    case 89521008u: return 187; /* raquo */
649    case 69208u: return 174; /* reg */
650    case 2538029u: return 167; /* sect */
651    case 70630u: return 173; /* shy */
652    case 2559205u: return 185; /* sup1 */
653    case 2559206u: return 178; /* sup2 */
654    case 2559207u: return 179; /* sup3 */
655    case 92360104u: return 223; /* szlig */
656    case 93204131u: return 254; /* thorn */
657    case 93247732u: return 215; /* times */
658    case 3403501826u: return 250; /* uacute */
659    case 94642680u: return 251; /* ucirc */
660    case 3414253514u: return 249; /* ugrave */
661    case 73389u: return 168; /* uml */
662    case 2652429u: return 252; /* uuml */
663    case 3645366530u: return 253; /* yacute */
664    case 78287u: return 165; /* yen */
665    case 2839053u: return 255; /* yuml */
[4432f2e]666   }
667   return 0;
668}
669
[60f7018]670static void parse_msg_file( int charset_code ) {
671  FILE *fh;
[4432f2e]672  char estr[512], line[512];
[60f7018]673  int en;
674  int c;
675  bool fQuoted;
676#ifndef NO_ACCENTS
677  char chOpenQuotes, chCloseQuotes;
678  char *szSingles;
679  char *szSingTab;
680  char *szAccents;
681  char *szLetters;
682  char **pszTable;
683
684  switch (charset_code) {
685     case CHARSET_USASCII: {
686        /* US ASCII */
687        chOpenQuotes = '\"';
688        chCloseQuotes = '\"';
689        szSingles = "";
690        szSingTab = NULL;
691        szAccents = "";
692        szLetters = "";
693        pszTable = NULL;
694        break;
695     }
696     case CHARSET_ISO_8859_1: {
697        /* ISO 8859/1 (Latin 1) */
698        static char *my_pszTable[]={
699         "àèòÀìùÈÌÒÙ",
700         "áéóÁíúÉÍÓÚýÝ",
701         "âêôÂîûÊÎÔÛ",
702         "äëöÄïüËÏÖÜÿ",
703         "ã õà   Õ   ñÑ",
704         NULL,
705         NULL,
706         NULL,
707         NULL,
708         NULL,
709         NULL,
710         "              ç",
711         "               Ç",
712         NULL,
713         "ª º",
714         "åæ",
715         "   Å  Æ",
716         "                  ß",
717         NULL,
718         NULL,
719         "  ø     Ø"
720        };
721        chOpenQuotes = '\"';
722        chCloseQuotes = '\"';
723        szSingles = "";
724        szSingTab = NULL;
725        szAccents = "`'^\"~=.uvHtcCdbaAsOo/";
726        szLetters = "aeoAiuEIOUyYnNcCwWs";
727        pszTable = my_pszTable;
728        break;
729     }
730     case CHARSET_RISCOS31: {
731        /* Archimedes RISC OS 3.1 and above
732         * ISO 8859/1 (Latin 1) + extensions in 128-159 */
733        static char *my_pszTable[]={
734         "àèòÀìùÈÌÒÙ",
735         "áéóÁíúÉÍÓÚýÝ",
736         "âêôÂîûÊÎÔÛ\x86\x85    \x82\x81",
737         "äëöÄïüËÏÖÜÿ",
738         "ã õà   Õ   ñÑ",
739         NULL,
740         NULL,
741         NULL,
742         NULL,
743         NULL,
744         NULL,
745         "              ç",
746         "               Ç",
747         NULL,
748         "ª º",
749         "åæ",
750         "   Å  Æ",
751         "                  ß",
752         "      \x9a",
753         " \x9b",
754         "  ø     Ø"
755        };
756        chOpenQuotes='\x94';
757        chCloseQuotes='\x95';
758        szSingles="";
759        szSingTab=NULL;
760        szAccents="`'^\"~=.uvHtcCdbaAsOo/";
761        szLetters="aeoAiuEIOUyYnNcCwWs";
762        pszTable = my_pszTable;
763        break;
764     }
765     case CHARSET_DOSCP850: {
766        /* MS DOS - Code page 850 */
767        static char *my_pszTable[]={
768         "\x85\x8A\x95·\x8D\x97Ô ãëìí",
769         " \x82¢µ¡£\x90Öàé",
770         "\x83\x88\x93¶\x8C\x96Ò×âê",
771         "\x84\x89\x94\x8E\x8B\x81ÓØ\x99\x9A\x98",
772         "Æ äÇ    å   ¤¥",
773         NULL,
774         NULL,
775         NULL,
776         NULL,
777         NULL,
778         NULL,
779         "              \x87",
780         "               \x80",
781         NULL,
782         "¦ §",
783         "\x86\x91",
784         "   \x8F  \x92",
785         "                  á",
786         NULL,
787         NULL,
788         "  \x9B     \x9D"
789        };
790        chOpenQuotes='\"';
791        chCloseQuotes='\"';
792        szSingles="lLij";
793        szSingTab="  Õ";
794        szAccents="`'^\"~=.uvHtcCdbaAsOo/";
795        szLetters="aeoAiuEIOUyYnNcCwWs";
796        pszTable = my_pszTable;
797        break;
798     }
799#if 0
800/* MS DOS - PC-8 (code page 437?) */
801static char chOpenQuotes='\"', chCloseQuotes='\"';
802static char *szSingles="";
803static char *szSingTab=NULL;
804static char *szAccents="`'^\"~=.uvHtcCdbaAsOo/";
805static char *szLetters="aeoAiuEIOUyYnNcCwWs";
806static char *pszTable[]={
807 "\x85\x8A\x95 \x8D\x97",
808 " \x82¢ ¡£\x90",
809 "\x83\x88\x93 \x8C\x96",
810 "\x84\x89\x94\x8E\x8B\x81  \x99\x9A\x98",
811 "            ¤¥",
812 NULL,
813 NULL,
814 NULL,
815 NULL,
816 NULL,
817 NULL,
818 "              \x87",
819 "               \x80",
820 NULL,
821 "¦ §",
822 "\x86\x91",
823 "   \x8F  \x92",
824 "                  á",
825 NULL,
826 NULL,
827 NULL
828};
829
830#elif 0
831/* MS DOS - PC-8 Denmark/Norway */
832static char chOpenQuotes='\"', chCloseQuotes='\"';
833static char *szSingles="";
834static char *szSingTab=NULL;
835static char *szAccents="`'^\"~=.uvHtcCdbaAsOo/";
836static char *szLetters="aeoAiuEIOUyYnNcCwWs";
837static char *pszTable[]={
838 "\x85\x8A\x95 \x8D\x97",
839 " \x82¢ ¡£\x90     ¬",
840 "\x83\x88\x93 \x8C\x96",
841 "\x84\x89\x94\x8E\x8B\x81  \x99\x9A\x98",
842 "© ¦ª    §   ¤¥",
843 NULL,
844 NULL,
845 NULL,
846 NULL,
847 NULL,
848 NULL,
849 "              \x87",
850 "               \x80",
851 NULL,
852 NULL,
853 "\x86\x91",
854 "   \x8F  \x92",
855 "                  á",
856 NULL,
857 NULL,
858 NULL
859};
860#elif 0
861/* No special chars... */
862# define NO_TEX
863#endif
864default: /*!HACK! do something -- no_tex variable version of NO_TEX ? */
865printf("oops, bad charset...\n");
866(void)0;
867  }
868#endif
869
870#if 0
871printf("opening error file\n");
872printf("(%s %s)\n",pthMe,lfErrs);
873#endif
874  fh=fopenWithPthAndExt( pthMe, lfErrs, "", "rb", NULL );
875#if 0
876printf("opened error file\n");
877#endif
878  if (!fh) {
879    /* no point extracting this error, as it won't get used if file opens */
880    fprintf(STDERR, erg[3], szAppNameCopy );
881    fprintf(STDERR, "Can't open message file '%s' using path '%s'\n",
[a3e49dc]882            lfErrs, pthMe);
[60f7018]883    exit(EXIT_FAILURE);
884  }
885
886  { /* copy bootstrap erg[] which'll get overwritten by file entries */
[a3e49dc]887     const char **ergMalloc;
888     erg = ergBootstrap;
889     ergMalloc = osmalloc( enMac * ossizeof(char*) );
890     /* NULL marks end of list */
891     for ( en = 0 ; erg[en] ; en++ ) ergMalloc[en]=erg[en];
892     for ( ; en < enMac ; en++ ) ergMalloc[en] = szBadEn;
893     erg = ergMalloc;
[60f7018]894  }
895
896  while (!feof( fh )) {
[4432f2e]897    char *p;
898    char *q;
899    int exact;
[60f7018]900    getline( line, ossizeof(line), fh );
[4432f2e]901    if ((exact = (strncmp(line, prefix, prefix_len) == 0)) ||
902        (prefix_root_len && strncmp(line, prefix_root, prefix_root_len) == 0)) {
903      long val;
904      val = strtol( line + (exact?prefix_len:prefix_root_len), &q, 0);
[60f7018]905      if (val < 0 || val > (unsigned long)INT_MAX) {
906        fprintf( STDERR, erg[3], szAppNameCopy );
907        fprintf( STDERR, erg[ (errno==ERANGE) ? 5 : 6 ] );
908        exit(EXIT_FAILURE);
909      }
910      en = (int)val;
911      while (isspace(*q)) q++;
912
913      p = q + strlen(q);
914      while (p > q && isspace(p[-1])) p--;
915
916      fQuoted = (p > q + 1 && *q == '\"' && *(p-1) == '\"');
917      if (fQuoted) {
918         q++;
919         p--;
920      }
921      *p = '\0';
922
923      c = 0;
924      while (*q) {
925         if (*q == '&') {
926            if (*(q+1) == '#') {
[4432f2e]927               if (isdigit(q[2])) {
[60f7018]928                  unsigned long value = strtoul( q+2, &q, 10);
929                  if (*q == ';') q++;
[4432f2e]930                  if (value < 127) {
[f1a5201]931                     estr[c++] = (char)value;
[4432f2e]932                  } else {
933                     c += add_unicode(charset_code, estr+c, value);
934                  }
[60f7018]935                  continue;
936               }
[4432f2e]937            } else if (isalnum(q[1])) { /* or isalpha? !HACK! */
938               /*const*/ char *entity;
[60f7018]939               int entity_len;
[4432f2e]940               int len;
[60f7018]941               entity = q+1;
942               q += 2;
943               while (isalnum(*q)) q++;
944               entity_len = q - entity;
945               if (*q == ';') q++;
[4432f2e]946               len = add_unicode(charset_code, estr+c, decode_entity(entity, entity_len));
947               if (len) {
948                  c += len;
949                  continue;
950               }
[60f7018]951               q = entity - 1;
952            }
953         }
954         if (*q < 32 || *q >= 127) {
[4432f2e]955            fprintf(STDERR, "Warning: literal character '%c' (value %d) "
956                    "in message %d\n", *q, (int)*q, en);
[60f7018]957         }
958         estr[c++] = *q++;
959      }
960      estr[c] = '\0';
961
962      if (en >= enMac) {
963         int enTmp;
964         enTmp = enMac;
965         enMac = enMac<<1;
966         erg = osrealloc( erg, enMac * ossizeof(char*) );
967         while (enTmp < enMac) erg[enTmp++] = szBadEn;
968      }
[a3e49dc]969      erg[en] = osstrdup(estr);
[60f7018]970/*printf("Error number %d: %s\n",en,erg[en]);*/
971    }
972  }
973  fclose(fh);
974}
975
976extern const char * FAR ReadErrorFile( const char *szAppName, const char *szEnvVar,
977                                       const char *szLangVar, const char *argv0,
978                                       const char *lfErrFile ) {
[4432f2e]979   int  c;
980   char *szTmp;
[60f7018]981
[4432f2e]982   lfErrs = osstrdup(lfErrFile);
[60f7018]983#ifdef HAVE_SIGNAL
[4432f2e]984   init_signals();
[60f7018]985#endif
[4432f2e]986   /* This code *should* be completely bomb-proof even if strcpy
987    * generates a signal
988    */
989   szAppNameCopy = szAppName; /* ... in case the osstrdup() fails */
990   szAppNameCopy = osstrdup(szAppName);
991
992   /* Look for env. var. "SURVEXHOME" or the like */
993   if (szEnvVar && *szEnvVar && (szTmp=getenv(szEnvVar))!=NULL && *szTmp) {
994      pthMe = osstrdup(szTmp);
995   } else if (argv0) {
996      /* else try the path on argv[0] */
997      pthMe = PthFromFnm(argv0);
998   } else {
999      /* otherwise, forget it - go for the current directory */
1000      pthMe = "";
1001   }
[f1a5201]1002
[4432f2e]1003   /* Look for env. var. "SURVEXLANG" or the like */
1004   if ((szTmp=getenv(szLangVar))==0 || !*szTmp) {
1005      szTmp = DEFAULTLANG;
1006   }
1007   for (c = 0 ; c < 4 && szTmp[c] ; c++) prefix[c] = tolower(szTmp[c]);
1008   prefix[c] = '\0';
1009   if (c == 4) {
1010      if (strcmp(prefix, "engi") == 0) {
1011         strcpy(prefix, "en");
1012      } else if (strcmp(prefix, "engu") == 0) {
[f1a5201]1013         strcpy(prefix, "en-us");
[4432f2e]1014      } else if (strcmp(prefix, "fren") == 0) {
[f1a5201]1015         strcpy(prefix, "fr");
[4432f2e]1016      } else if (strcmp(prefix, "germ") == 0) {
[f1a5201]1017         strcpy(prefix, "de");
[4432f2e]1018      } else if (strcmp(prefix, "ital") == 0) {
[f1a5201]1019         strcpy(prefix, "it");
[4432f2e]1020      } else if (strcmp(prefix, "span") == 0) {
[f1a5201]1021         strcpy(prefix, "es");
[4432f2e]1022      } else if (strcmp(prefix, "cata") == 0) {
[f1a5201]1023         strcpy(prefix, "ca");
[4432f2e]1024      } else if (strcmp(prefix, "port") == 0) {
[f1a5201]1025         strcpy(prefix, "pt");
[4432f2e]1026      } else {
1027         while (szTmp[c] && c < sizeof(prefix)) {
1028            prefix[c] = tolower(szTmp[c]);
1029            c++;
1030         }
1031         prefix[c] = '\0';
1032      }
1033   }
1034   strcat(prefix, ":");
1035   prefix_len = strlen(prefix);
[f1a5201]1036
[4432f2e]1037   /* If the language is something like "en-us", fallback to "en" if we don't
1038    * have an entry for en-us */
1039   szTmp = strchr(prefix, '-');
1040   if (szTmp) {
1041      c = szTmp - prefix;
1042      memcpy(prefix_root, prefix, c);
1043      prefix_root[c++] = ':';
1044      prefix_root[c] = '\0';
1045      prefix_root_len = strlen(prefix_root);
1046   } else {
1047      prefix_root_len = 0;
1048   }
[60f7018]1049
1050  select_charset(default_charset());
1051
1052  if (erg[0]==szBadEn) {
1053    fprintf(STDERR, erg[3], szAppName );
1054    /* no point extracting this message */
1055    fprintf(STDERR, "No messages in language '%s'\n",prefix);
1056    exit(EXIT_FAILURE);
1057  }
1058  if (strcmp(MESSAGE_VERSION_MIN,erg[0])>0 || strcmp(VERSION,erg[0])<0)
1059    /* a little tacky, but'll work */
1060    fatal(191,wr,MESSAGE_VERSION_MIN" - "VERSION,0);
1061
1062  return pthMe;
1063}
1064
1065extern const char *msg( int en ) /* message may be overwritten by next call */ {
1066  return ( (en<0||en>=enMac) ? szBadEn : erg[en] );
1067}
1068
1069extern const char *msgPerm( int en ) /* returns persistent copy of message */ {
1070  return ( (en<0||en>=enMac) ? szBadEn : erg[en] );
1071}
1072
[4432f2e]1073static void FAR errdisp( int en, void (*fn)( const char *, int ), const char *arg, int n,
[60f7018]1074                         int type ) {
[4432f2e]1075   fputnl( STDERR );
1076   fputnl( STDERR );
1077   fprintf( STDERR, erg[type], szAppNameCopy );
1078   fputs( msg(en), STDERR);
1079   fputnl( STDERR );
1080   if (fn) (fn)(arg, n);
1081/*   if (fn) (fn)( (arg ? arg : "(null)"), n);*/
[60f7018]1082}
1083
1084extern void FAR warning( int en, void (*fn)( const char *, int ), const char *szArg, int n ) {
[4432f2e]1085   cWarnings++;
1086   errdisp( en, fn, szArg, n, 4 );
[60f7018]1087}
1088
1089extern void FAR error( int en, void (*fn)( const char *, int ), const char *szArg, int n ) {
[4432f2e]1090   cErrors++;
1091   errdisp( en, fn, szArg, n, 3 );
1092   /* non-fatal errors now return... */
[60f7018]1093}
1094
1095extern void FAR fatal( int en, void (*fn)( const char *, int ), const char *szArg, int n ) {
[4432f2e]1096   errdisp( en, fn, szArg, n, 2 );
1097   exit(EXIT_FAILURE);
[60f7018]1098}
1099
1100#if 1
1101/* Code to support switching character set at runtime (e.g. for a printer
1102 * driver to support different character sets on screen and on the printer)
1103 */
1104typedef struct charset_li {
1105   struct charset_li *next;
1106   int code;
[a3e49dc]1107   const char **erg;
[60f7018]1108} charset_li;
1109
1110static charset_li *charset_head = NULL;
1111
1112static int charset = CHARSET_BAD;
1113
1114int select_charset( int charset_code ) {
1115   int old_charset = charset;
1116   charset_li *p;
1117
[a3e49dc]1118/*   printf( "select_charset(%d), old charset = %d\n", charset_code, charset ); */
[60f7018]1119
1120   charset = charset_code;
1121
1122   /* check if we've already parsed messages for new charset */
1123   for( p = charset_head ; p ; p = p->next ) {
[a3e49dc]1124/*      printf("%p: code %d erg %p\n",p,p->code,p->erg); */
[60f7018]1125      if (p->code == charset) {
1126         erg = p->erg;
1127         goto found;
1128      }
1129   }
1130
1131   /* nope, got to reparse message file */
[a3e49dc]1132   parse_msg_file( charset_code );
[60f7018]1133
1134   /* add to list */
1135   p = osnew(charset_li);
1136/*   p = osmalloc(256); */
1137   p->code = charset;
1138   p->erg = erg;
1139   p->next = charset_head;
1140   charset_head = p;
1141
1142   found:
1143   return old_charset;
1144}
1145#endif
Note: See TracBrowser for help on using the repository browser.