1 /*
2    Copyright (c) 1991-1999 Thomas T. Wetmore IV
3    "The MIT license"
4    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7 */
8 /*===========================================================
9  * translat.c -- LifeLines character mapping functions
10  * Copyright(c) 1994 by T.T. Wetmore IV; all rights reserved
11  *=========================================================*/
12 
13 #include <errno.h>
14 #include "llstdlib.h"
15 #include "btree.h"
16 #include "translat.h"
17 #include "xlat.h"
18 #include "codesets.h"
19 #include "gedcom.h"
20 #include "zstr.h"
21 #include "icvt.h"
22 #include "lloptions.h"
23 #include "gedcomi.h"
24 #include "arch.h"
25 
26 
27 /*********************************************
28  * global/exported variables
29  *********************************************/
30 
31 STRING illegal_char = 0;
32 
33 /*********************************************
34  * external/imported variables
35  *********************************************/
36 
37 extern BTREE BTR;
38 
39 /*********************************************
40  * local types
41  *********************************************/
42 
43 /* legacy (embedded) translation table */
44 struct legacytt_s {
45 	TRANTABLE tt;
46 	BOOLEAN first; /* comes at start of translation ? */
47 };
48 /* a predefined conversion, such as editor-to-internal */
49 struct conversion_s {
50 	INT trnum;
51 	CNSTRING key;
52 	CNSTRING name;
53 	INT zon_src;
54 	INT zon_dest;
55 	STRING * src_codeset;
56 	STRING * dest_codeset;
57 	XLAT xlat;
58 };
59 /* a predefined codeset, such as editor */
60 struct zone_s {
61 	INT znum;
62 	CNSTRING name;
63 };
64 
65 /*********************************************
66  * local enums & defines
67  *********************************************/
68 
69 enum { ZON_X, ZON_INT, ZON_GUI, ZON_EDI, ZON_RPT, ZON_GED, NUM_ZONES };
70 
71 /*********************************************
72  * local function prototypes
73  *********************************************/
74 
75 /* alphabetical */
76 static void clear_legacy_tt(INT trnum);
77 static void clear_predefined_list(void);
78 static struct conversion_s * getconvert(INT trnum);
79 static BOOLEAN is_legacy_first(INT trnum);
80 static void local_init(void);
81 
82 
83 /*********************************************
84  * local variables
85  *********************************************/
86 
87 struct zone_s zones[] = {
88 	{ ZON_X, "Invalid zone" }
89 	, { ZON_INT, "Internal codeset" }
90 	, { ZON_GUI, "Display codeset" }
91 	, { ZON_EDI, "Editor codeset" }
92 	, { ZON_RPT, "Report codeset" }
93 	, { ZON_GED, "GEDCOM codeset" }
94 };
95 
96 /* These must be in enumeration order up to NUM_TT_MAPS */
97 static struct conversion_s conversions[] = {
98 	/* TRANSLATORS: Character set conversion from external editor to database internal */
99 	{ MEDIN, "MEDIN", N_("Editor to Internal"), ZON_EDI, ZON_INT, &editor_codeset_in, &int_codeset, 0 }
100 	/* TRANSLATORS: Character set conversion from database internal to external editor */
101 	, { MINED, "MINED", N_("Internal to Editor"), ZON_INT, ZON_EDI, &int_codeset, &editor_codeset_out, 0 }
102 	, { MGDIN, "MGDIN", N_("GEDCOM to Internal"), ZON_GED, ZON_INT, &gedcom_codeset_in, &int_codeset, 0 }
103 	, { MINGD, "MINGD", N_("Internal to GEDCOM"), ZON_INT, ZON_GED, &int_codeset, &gedcom_codeset_out, 0 }
104 	, { MDSIN, "MDSIN", N_("Display to Internal"), ZON_GUI, ZON_INT, &gui_codeset_in, &int_codeset, 0 }
105 	, { MINDS, "MINDS", N_("Internal to Display"), ZON_INT, ZON_GUI, &int_codeset, &gui_codeset_out, 0 }
106 	, { MRPIN, "MRPIN", N_("Report to Internal"), ZON_RPT, ZON_INT, &report_codeset_in, &int_codeset, 0 }
107 	, { MINRP, "MINRP", N_("Internal to Report"), ZON_INT, ZON_RPT, &int_codeset, &report_codeset_out, 0 }
108 	/* These are all special-purpose translation tables, and maybe shouldn't even be here ? */
109 	, { MSORT, "MSORT", "Custom Sort", ZON_X, ZON_X, 0, 0, 0 }
110 	, { MCHAR, "MCHAR", "Custom Charset", ZON_X, ZON_X, 0, 0, 0 }
111 	, { MLCAS, "MLCAS", "Custom Lowercase", ZON_X, ZON_X, 0, 0, 0 }
112 	, { MUCAS, "MUCAS", "Custom Uppercase", ZON_X, ZON_X, 0, 0, 0 }
113 	, { MPREF, "MPREF", "Custom Prefix", ZON_X, ZON_X, 0, 0, 0 }
114 };
115 static CNSTRING conversions_keys[] = {
116 	/* TRANSLATORS: key for "Editor to Internal" on translation table menu
117 	Omit everything up to and including final | */
118 	N_("menu|trantable|e")
119 	/* TRANSLATORS: key for "Internal to Editor" on translation table menu
120 	Omit everything up to and including final | */
121 	, N_("menu|trantable|m")
122 	/* TRANSLATORS: key for "GEDCOM to Internal" on translation table menu
123 	Omit everything up to and including final | */
124 	, N_("menu|trantable|i")
125 	/* TRANSLATORS: key for "Internal to GEDCOM" on translation table menu
126 	Omit everything up to and including final | */
127 	, N_("menu|trantable|x")
128 	/* TRANSLATORS: key for "Display to Internal" on translation table menu
129 	Omit everything up to and including final | */
130 	, N_("menu|trantable|g")
131 	/* TRANSLATORS: key for "Internal to Display" on translation table menu
132 	Omit everything up to and including final | */
133 	, N_("menu|trantable|d")
134 	/* TRANSLATORS: key for "Report to Internal" on translation table menu
135 	Omit everything up to and including final | */
136 	, N_("menu|trantable|p")
137 	/* TRANSLATORS: key for "Internal to Report" on translation table menu
138 	Omit everything up to and including final | */
139 	, N_("menu|trantable|r")
140 };
141 /* currently loaded legacy (embedded) translation tables */
142 static struct legacytt_s legacytts[NUM_TT_MAPS]; /* initialized once by transl_init() */
143 static BOOLEAN inited=FALSE;
144 
145 
146 /*********************************************
147  * local & exported function definitions
148  * body of module
149  *********************************************/
150 
151 /*===================================================
152  * translate_catn -- Translate & concatenate string
153  *
154  * tt:    translation table to use
155  * pdest: address of destination (will be advanced)
156  * src:   source string
157  * len:   address of space left in destination (will be decremented)
158  *=================================================*/
159 void
translate_catn(XLAT ttm,STRING * pdest,CNSTRING src,INT * len)160 translate_catn (XLAT ttm, STRING * pdest, CNSTRING src, INT * len)
161 {
162 	INT added;
163 	if (*len > 1)
164 		translate_string(ttm, src, *pdest, *len);
165 	else
166 		(*pdest)[0] = 0; /* to be safe */
167 	added = strlen(*pdest);
168 	*len -= added;
169 	*pdest += added;
170 }
171 /*===================================================
172  * translate_string_to_zstring -- Translate string via TRANTABLE
173  *  xlat: [IN]  translation to apply
174  *  in:   [IN]  string to translate
175  * Created: 2001/07/19 (Perry Rapp)
176  * Copied from translate_string, except this version
177  * uses dynamic buffer, so it can expand if necessary
178  *=================================================*/
179 ZSTR
translate_string_to_zstring(XLAT xlat,CNSTRING in)180 translate_string_to_zstring (XLAT xlat, CNSTRING in)
181 {
182 	ZSTR zstr = zs_news(in);
183 	transl_xlat(xlat, zstr);
184 	return zstr;
185 }
186 /*===================================================
187  * translate_string -- Translate string via XLAT
188  *  ttm:     [IN]  tranmapping
189  *  in:      [IN]  in string
190  *  out:     [OUT] string
191  *  maxlen:  [OUT] max len of out string
192  * Output string is limited to max length via use of
193  * add_char & add_string.
194  *=================================================*/
195 void
translate_string(XLAT ttm,CNSTRING in,STRING out,INT maxlen)196 translate_string (XLAT ttm, CNSTRING in, STRING out, INT maxlen)
197 {
198 	ZSTR zstr=0;
199 	if (!in || !in[0]) {
200 		out[0] = 0;
201 		return;
202 	}
203 	zstr = translate_string_to_zstring(ttm, in);
204 	llstrsets(out, maxlen, uu8, zs_str(zstr));
205 	zs_free(&zstr);
206 }
207 /*==========================================================
208  * translate_write -- Translate and output lines in a buffer
209  *  tt:   [in] translation table (may be NULL)
210  *  in:   [in] input string to write
211  *  lenp: [in,out] #characters left in buffer (set to 0 if a full write)
212  *  ofp:  [in] output file
213  *  last: [in] flag to write final line if no trailing \n
214  * Loops thru & prints out lines until end of string
215  *  (or until last line if not terminated with \n)
216  * *lenp will be set to zero unless there is a final line
217  * not terminated by \n and caller didn't ask to write it anyway
218  * NB: If no translation table, entire string is always written
219  *========================================================*/
220 BOOLEAN
translate_write(XLAT ttm,STRING in,INT * lenp,FILE * ofp,BOOLEAN last)221 translate_write(XLAT ttm, STRING in, INT *lenp, FILE *ofp, BOOLEAN last)
222 {
223 	char intmp[MAXLINELEN+2]="";
224 	char out[MAXLINELEN+2]="";
225 	char *tp=0;
226 	STRING bp = in;
227 	int i=0,j=0;
228 
229 	if(ttm == NULL) {
230 	    ASSERT(fwrite(in, *lenp, 1, ofp) == 1);
231 	    *lenp = 0;
232 	    return TRUE;
233 	}
234 
235 	/* loop through lines one by one */
236 	for(i = 0; i < *lenp; ) {
237 		/* copy in to intmp, up to first \n or our buffer size-1 */
238 		tp = intmp;
239 		for(j = 0; (j <= MAXLINELEN) && (i < *lenp) && (*bp != '\n'); j++) {
240 			i++;
241 			*tp++ = *bp++;
242 		}
243 		*tp = '\0';
244 		if(i < *lenp) {
245 			/* partial, either a single line or a single buffer full */
246 			if(*bp == '\n') {
247 				/* single line, include the \n */
248 				/* it is important that we limited size earlier so we
249 				have room here to add one more character */
250 				*tp++ = *bp++;
251 				*tp = '\0';
252 				i++;
253 			}
254 		}
255 		else if(!last) {
256 			/* the last line is not complete, return it in buffer  */
257 			strcpy(in, intmp);
258 			*lenp = strlen(in);
259 			return(TRUE);
260 		}
261 		/* translate & write out current line */
262 		/* TODO (2002-11-28): modify to use dynamic string */
263 		translate_string(ttm, intmp, out, MAXLINELEN+2);
264 		if (ofp && strlen(out)) {
265 			int outbytes = fwrite(out, 1, strlen(out), ofp);
266 			if (!outbytes || ferror(ofp)) {
267 				crashlog("outbytes=%d, errno=%d, outstr=%s"
268 					, outbytes, errno, out);
269 				FATAL();
270 			}
271 		}
272 	}
273 	*lenp = 0;
274 	return(TRUE);
275 }
276 /*==========================================================
277  * get_xlat_to_int -- Get translation to internal codeset
278  *  returns NULL if fails
279  * Created: 2002/11/28 (Perry Rapp)
280  *========================================================*/
281 XLAT
transl_get_xlat_to_int(CNSTRING codeset)282 transl_get_xlat_to_int (CNSTRING codeset)
283 {
284 	BOOLEAN adhoc = TRUE;
285 	return xl_get_xlat(codeset, int_codeset, adhoc);
286 }
287 /*==========================================================
288  * transl_get_xlat -- Get arbitrary translator
289  *  returns NULL if fails
290  * Created: 2002/11/30 (Perry Rapp)
291  *========================================================*/
292 XLAT
transl_get_xlat(CNSTRING src,CNSTRING dest)293 transl_get_xlat (CNSTRING src, CNSTRING dest)
294 {
295 	BOOLEAN adhoc = TRUE;
296 	return xl_get_xlat(src, dest, adhoc);
297 }
298 /*==========================================================
299  * transl_load_all_tts -- Load internal list of available translation
300  *  tables (based on *.tt files in TTPATH)
301  * Created: 2002/11/28 (Perry Rapp)
302  *========================================================*/
303 void
transl_load_all_tts(void)304 transl_load_all_tts (void)
305 {
306 	CNSTRING ttpath = getlloptstr("TTPATH", ".");
307 	if (!inited) local_init();
308 	xl_load_all_dyntts(ttpath);
309 }
310 /*==========================================================
311  * transl_xlat -- Perform a translation on a string
312  * Created: 2002/11/28 (Perry Rapp)
313  *========================================================*/
314 void
transl_xlat(XLAT xlat,ZSTR zstr)315 transl_xlat (XLAT xlat, ZSTR zstr)
316 {
317 	INT index = xl_get_uparam(xlat)-1;
318 	struct legacytt_s * legtt = (index>=0 ? &legacytts[index] : NULL);
319 	if (legtt && legtt->tt && legtt->first) {
320 		custom_translatez(zstr, legtt->tt);
321 	}
322 
323 	xl_do_xlat(xlat, zstr);
324 
325 	if (legtt && legtt->tt && !legtt->first) {
326 		custom_translatez(zstr, legtt->tt);
327 	}
328 }
329 /*==========================================================
330  * transl_init -- One-time initialization of this module
331  * Created: 2002/12/13 (Perry Rapp)
332  *========================================================*/
333 static void
local_init(void)334 local_init (void)
335 {
336 	INT i;
337 
338 	ASSERT(NUM_TT_MAPS == ARRSIZE(conversions));
339 	ASSERT(NUM_ZONES == ARRSIZE(zones));
340 
341 	for (i=0; i<NUM_TT_MAPS; ++i)
342 		legacytts[i].tt = 0;
343 	inited=TRUE;
344 }
345 /*==========================================================
346  * transl_load_xlats -- Load translations for all regular codesets
347  *  (internal, GUI, ...)
348  * returns FALSE if needed conversions not available
349  * Created: 2002/11/28 (Perry Rapp)
350  *========================================================*/
351 void
transl_load_xlats(void)352 transl_load_xlats (void)
353 {
354 	INT i;
355 
356 	if (!inited) local_init();
357 
358 	clear_predefined_list();
359 
360 	for (i=0; i<NUM_TT_MAPS; ++i) {
361 		struct conversion_s * conv = getconvert(i);
362 		STRING src, dest;
363 		BOOLEAN adhoc = FALSE;
364 		ASSERT(conv->trnum == i);
365 		if (conv->src_codeset && int_codeset) {
366 			ASSERT(conv->dest_codeset);
367 			src = *conv->src_codeset;
368 			dest = *conv->dest_codeset;
369 			conv->xlat = xl_get_xlat(src, dest, adhoc);
370 		} else {
371 			/* even if codesets are unspecified, have to have a placeholder
372 			in which to store any legacy translation tables */
373 			conv->xlat = xl_get_null_xlat();
374 		}
375 		/* 2003-09-09, Perry
376 		I just added this today quickly today to get legacy translations
377 		working; this is kind of confusing and ought to be cleaned
378 		up */
379 		xl_set_uparam(conv->xlat, 0);
380 		if (BTR) {
381 			TRANTABLE tt=0;
382 			if (init_map_from_rec(conv->key, i, &tt) && tt) {
383 				transl_set_legacy_tt(i, tt);
384 			}
385 			xl_set_uparam(conv->xlat, i+1);
386 		}
387 	}
388 }
389 /*==========================================================
390  * is_legacy_first -- Should this legacy come before rest of translation ?
391  * This is to make legacy tts run in internal codeset
392  * Created: 2002/12/13 (Perry Rapp)
393  *========================================================*/
394 static BOOLEAN
is_legacy_first(INT trnum)395 is_legacy_first (INT trnum)
396 {
397 	return (getconvert(trnum)->src_codeset == &int_codeset);
398 }
399 /*==========================================================
400  * clear_predefined_list -- Free cached regular conversions
401  * Created: 2002/11/28 (Perry Rapp)
402  *========================================================*/
403 static void
clear_predefined_list(void)404 clear_predefined_list (void)
405 {
406 	INT i;
407 	for (i=0; i<NUM_TT_MAPS; ++i) {
408 		getconvert(i)->xlat = 0; /* pointer into xlat.c cache, so we don't free it */
409 		clear_legacy_tt(i);
410 	}
411 }
412 /*==========================================================
413  * transl_get_predefined_xlat -- Fetch a predefined translation
414  *  eg, MEDIN (editor-to-internal)
415  * Created: 2002/11/28 (Perry Rapp)
416  *========================================================*/
417 XLAT
transl_get_predefined_xlat(INT trnum)418 transl_get_predefined_xlat (INT trnum)
419 {
420 	return getconvert(trnum)->xlat;
421 }
422 /*==========================================================
423  * transl_get_predefined_name -- Fetch name of a predefined translation
424  *  eg, transl_get_predefined_name(MEDIN) == "editor-to-internal"
425  * Created: 2002/12/13 (Perry Rapp)
426  *========================================================*/
427 ZSTR
transl_get_predefined_name(INT trnum)428 transl_get_predefined_name (INT trnum)
429 {
430 	return zs_news(_(getconvert(trnum)->name));
431 }
432 /*==========================================================
433  * sgettext -- Version of gettext that strips out menu leaders
434  * (menu leaders are everything up to last |)
435  *========================================================*/
436 static const char *
sgettext(const char * msgid)437 sgettext (const char *msgid)
438 {
439 	char *msgval = _(msgid);
440 	if (msgval == msgid)
441 		msgval = strrchr (msgid, '|') + 1;
442 	return msgval;
443 }
444 /*==========================================================
445  * transl_get_predefined_menukey -- Menu key for predefined translation
446  * (localized)
447  *========================================================*/
448 ZSTR
transl_get_predefined_menukey(INT trnum)449 transl_get_predefined_menukey (INT trnum)
450 {
451 	ASSERT(trnum>=0);
452 	ASSERT(trnum<ARRSIZE(conversions_keys));
453 	return zs_news(sgettext(conversions_keys[trnum]));
454 }
455 /*==========================================================
456  * transl_get_description -- Fetch description of a translation
457  *  eg, "3 steps with iconv(UTF-8, CP1252)"
458  * Created: 2002/12/13 (Perry Rapp)
459  *========================================================*/
460 ZSTR
transl_get_description(XLAT xlat)461 transl_get_description (XLAT xlat)
462 {
463 	ZSTR zstr = xlat_get_description(xlat);
464 	INT index = xl_get_uparam(xlat)-1;
465 	struct legacytt_s * legtt = (index>=0 ? &legacytts[index] : NULL);
466 	if (legtt && legtt->tt) {
467 		ZSTR zdesc = get_trantable_desc(legtt->tt);
468 		/* TRANSLATORS: db internal translation table note for tt menu */
469 		zs_appf(zstr, _(" (dbint tt: %s)"), zs_str(zdesc));
470 		zs_free(&zdesc);
471 	}
472 
473 	return zstr;
474 }
475 /*==========================================================
476  * transl_parse_codeset -- Parse out subcode suffixes of a codeset
477  *  eg, "CP437//TrGreekAscii//TrCyrillicAscii"
478  *  will recognize CP437 as the codeset name, and list
479  *  "TrGreekAscii" and "TrCyrillicAscii"  as subcodes
480  * Created: 2002/11/28 (Perry Rapp)
481  *========================================================*/
482 void
transl_parse_codeset(CNSTRING codeset,ZSTR zcsname,LIST * subcodes)483 transl_parse_codeset (CNSTRING codeset, ZSTR zcsname, LIST * subcodes)
484 {
485 	xl_parse_codeset(codeset, zcsname, subcodes);
486 }
487 /*==========================================================
488  * transl_are_all_conversions_ok --
489  *  return FALSE if there any conversions we couldn't figure out
490  * Created: 2002/11/28 (Perry Rapp)
491  *========================================================*/
492 BOOLEAN
transl_are_all_conversions_ok(void)493 transl_are_all_conversions_ok (void)
494 {
495 	INT i;
496 	for (i=0; i<NUM_TT_MAPS; ++i) {
497 		if (conversions[i].src_codeset && !conversions[i].xlat)
498 			return FALSE;
499 	}
500 	return TRUE;
501 }
502 /*==========================================================
503  * getconvert -- return conversion for trnum
504  * Simply a wrapper for ASSERT to check validity of trnum
505  * Created: 2002/12/13 (Perry Rapp)
506  *========================================================*/
507 static struct conversion_s *
getconvert(INT trnum)508 getconvert (INT trnum)
509 {
510 	ASSERT(trnum>=0);
511 	ASSERT(trnum<NUM_TT_MAPS);
512 	return &conversions[trnum];
513 }
514 /*==========================================================
515  * transl_has_legacy_tt -- Is there a legacy (in-database)
516  *  translation table for this entry ?
517  * Created: 2002/12/13 (Perry Rapp)
518  *========================================================*/
519 TRANTABLE
transl_get_legacy_tt(INT trnum)520 transl_get_legacy_tt (INT trnum)
521 {
522 	getconvert(trnum); /* check validity of trnum */
523 	return legacytts[trnum].tt;
524 }
525 /*==========================================================
526  * transl_has_legacy_tt -- Is there a legacy (in-database)
527  *  translation table for this entry ?
528  * Created: 2002/12/13 (Perry Rapp)
529  *========================================================*/
530 void
transl_set_legacy_tt(INT trnum,TRANTABLE tt)531 transl_set_legacy_tt (INT trnum, TRANTABLE tt)
532 {
533 	struct legacytt_s * leg;
534 	clear_legacy_tt(trnum); /* ensures trnum validity */
535 	getconvert(trnum); /* check validity of trnum */
536 	leg = &legacytts[trnum];
537 	leg->tt = tt;
538 	leg->first = is_legacy_first(trnum);
539 }
540 /*==========================================================
541  * clear_legacy_tt -- Remove this legacy tt if loaded
542  * Created: 2002/12/13 (Perry Rapp)
543  *========================================================*/
544 static void
clear_legacy_tt(INT trnum)545 clear_legacy_tt (INT trnum)
546 {
547 	struct legacytt_s * leg;
548 	getconvert(trnum); /* check validity of trnum */
549 	leg = &legacytts[trnum];
550 	if (leg->tt) {
551 		remove_trantable(leg->tt);
552 		leg->tt = 0;
553 	}
554 }
555 /*==========================================================
556  * transl_free_predefined_xlats -- Free all our predefined
557  *  translations; this is called when a database is closed
558  * Created: 2002/12/13 (Perry Rapp)
559  *========================================================*/
560 void
transl_free_predefined_xlats(void)561 transl_free_predefined_xlats (void)
562 {
563 	clear_predefined_list();
564 }
565 /*==========================================================
566  * transl_is_xlat_valid -- Does it do the job ?
567  * Created: 2002/12/15 (Perry Rapp)
568  *========================================================*/
569 BOOLEAN
transl_is_xlat_valid(XLAT xlat)570 transl_is_xlat_valid (XLAT xlat)
571 {
572 	return xl_is_xlat_valid(xlat);
573 }
574 /*==========================================================
575  * transl_get_map_name -- get name of translation
576  * eg, "Editor to Internal"
577  * (localized)
578  *========================================================*/
579 CNSTRING
transl_get_map_name(INT trnum)580 transl_get_map_name (INT trnum)
581 {
582 	ASSERT(trnum>=0);
583 	ASSERT(trnum<NUM_TT_MAPS);
584 	return _(getconvert(trnum)->name);
585 }
586 /*==========================================================
587  * transl_release_xlat -- Client finished with this
588  * Created: 2002/12/15 (Perry Rapp)
589  *========================================================*/
590 void
transl_release_xlat(XLAT xlat)591 transl_release_xlat (XLAT xlat)
592 {
593 	xl_release_xlat(xlat);
594 }
595 
596