1 /* File: util-dll.c */
2 
3 /* Purpose: misc stuff */
4 
5 /*
6  * Copyright (c) 1997-2001 Tim Baker
7  *
8  * This software may be copied and distributed for educational, research, and
9  * not for profit purposes provided that this copyright and statement are
10  * included in all such copies.
11  */
12 
13 #include "tnb.h"
14 
15 #include <limits.h>
16 #ifndef USHRT_MAX
17 #define USHRT_MAX 65535
18 #endif
19 
20 #define MAX_DELTA (255 * 6)
21 #define MAX_COLOR_ENTRY 1021
22 
23 #ifdef HAVE_TKFONT_H
24 #include <tkFont.h>
25 #else /* HAVE_TKFONT_H */
26 
27 typedef struct TkFontAttributes {
28     Tk_Uid family;		/* Font family, or NULL to represent
29 				 * plaform-specific default system font. */
30     int size;			/* Pointsize of font, 0 for default size, or
31 				 * negative number meaning pixel size. */
32     int weight;			/* Weight flag; see below for def'n. */
33     int slant;			/* Slant flag; see below for def'n. */
34     int underline;		/* Non-zero for underline font. */
35     int overstrike;		/* Non-zero for overstrike font. */
36 } TkFontAttributes;
37 
38 #define TK_FW_NORMAL	0
39 #define TK_FW_BOLD	1
40 
41 #define TK_FS_ROMAN	0
42 #define TK_FS_ITALIC	1
43 
44 typedef struct TkFontMetrics {
45     int	ascent;			/* From baseline to top of font. */
46     int	descent;		/* From baseline to bottom of font. */
47     int maxWidth;		/* Width of widest character in font. */
48     int fixed;			/* Non-zero if this is a fixed-width font,
49 				 * 0 otherwise. */
50 } TkFontMetrics;
51 
52 
53 typedef struct TkFont {
54     /*
55      * Fields used and maintained exclusively by generic code.
56      */
57 
58     int resourceRefCount;	/* Number of active uses of this font (each
59 				 * active use corresponds to a call to
60 				 * Tk_AllocFontFromTable or Tk_GetFont).
61 				 * If this count is 0, then this TkFont
62 				 * structure is no longer valid and it isn't
63 				 * present in a hash table: it is being
64 				 * kept around only because there are objects
65 				 * referring to it.  The structure is freed
66 				 * when resourceRefCount and objRefCount
67 				 * are both 0. */
68     int objRefCount;		/* The number of Tcl objects that reference
69 				 * this structure. */
70     Tcl_HashEntry *cacheHashPtr;/* Entry in font cache for this structure,
71 				 * used when deleting it. */
72     Tcl_HashEntry *namedHashPtr;/* Pointer to hash table entry that
73 				 * corresponds to the named font that the
74 				 * tkfont was based on, or NULL if the tkfont
75 				 * was not based on a named font. */
76     Screen *screen;		/* The screen where this font is valid. */
77     int tabWidth;		/* Width of tabs in this font (pixels). */
78     int	underlinePos;		/* Offset from baseline to origin of
79 				 * underline bar (used for drawing underlines
80 				 * on a non-underlined font). */
81     int underlineHeight;	/* Height of underline bar (used for drawing
82 				 * underlines on a non-underlined font). */
83 
84     /*
85      * Fields used in the generic code that are filled in by
86      * platform-specific code.
87      */
88 
89     Font fid;			/* For backwards compatibility with XGCValues
90 				 * structures.  Remove when TkGCValues is
91 				 * implemented.  */
92     TkFontAttributes fa;	/* Actual font attributes obtained when the
93 				 * the font was created, as opposed to the
94 				 * desired attributes passed in to
95 				 * TkpGetFontFromAttributes().  The desired
96 				 * metrics can be determined from the string
97 				 * that was used to create this font. */
98     TkFontMetrics fm;		/* Font metrics determined when font was
99 				 * created. */
100     struct TkFont *nextPtr;	/* Points to the next TkFont structure with
101 				 * the same name.  All fonts with the
102 				 * same name (but different displays) are
103 				 * chained together off a single entry in
104 				 * a hash table. */
105 } TkFont;
106 
107 #endif /* !HAVE_TKFONT_H */
108 
109 /* Structure for a hash table used by rgb2index() */
110 typedef struct
111 {
112 	int valid; /* The hash-table entry is valid */
113 	u32b pixel; /* an RGB pixel value */
114 	int index; /* closest matching palette index for 'pixel' */
115 } t_color_entry;
116 
117 typedef struct IndexedColor IndexedColor;
118 struct IndexedColor
119 {
120 	byte rgb[256 * 3];
121 	t_color_entry hash[MAX_COLOR_ENTRY];
122 	void *platData;
123 };
124 
125 static IndexedColor g_palette;
126 static bool Palette_Initialized = 0;
127 
128 int g_palette_black = 255;
129 int g_palette_white = 0;
130 int g_colormap_black;
131 int g_colormap_white;
132 
133 byte g_palette2colormap[256];
134 
135 /*
136  * Append an element to an array
137  */
Array_Append(void * array_ptr,int * count,int elem_size,void * elem_ptr)138 void *Array_Append(void *array_ptr, int *count, int elem_size,
139 	void *elem_ptr)
140 {
141 	char *ap = array_ptr;
142 	int n = (*count) + 1;
143 
144 	ap = Tcl_Realloc(ap, n * elem_size);
145 	(void) memcpy(ap + (n - 1) * elem_size, elem_ptr, elem_size);
146 	(*count) = n;
147 	return ap;
148 }
149 
150 /*
151  * Insert an element in an array
152  */
Array_Insert(void * array_ptr,int * count,int elem_size,int index)153 void *Array_Insert(void *array_ptr, int *count, int elem_size,
154 	int index)
155 {
156 	char *ap = array_ptr;
157 	int n = (*count) + 1;
158 
159 	if (index < 0) index = 0;
160 	if (index >= n) index = n - 1;
161 
162 	ap = Tcl_Realloc(ap, n * elem_size);
163 	if (index != n - 1)
164 	{
165 		(void) memcpy(ap + (index + 1) * elem_size,
166 			ap + index * elem_size,
167 			(n - index - 1) * elem_size);
168 	}
169 	else
170 	{
171 		memset(ap + index * elem_size, 0, elem_size);
172 	}
173 	(*count) = n;
174 	return ap;
175 }
176 
177 /*
178  * Delete an element from an array
179  */
Array_Delete(void * array_ptr,int * count,int elem_size,int index)180 void *Array_Delete(void *array_ptr, int *count, int elem_size,
181 	int index)
182 {
183 	char *ap = array_ptr;
184 	int i, n = (*count) - 1;
185 
186 	if (index < 0) index = 0;
187 	if (index > n) index = n;
188 
189 	if (index != n)
190 	{
191 		(void) memcpy(ap + index * elem_size,
192 			ap + (index + 1) * elem_size,
193 			(n - index) * elem_size);
194 	}
195 
196 	/* Zero the trailing slot to catch errors */
197 	for (i = 0; i < elem_size; i++)
198 	{
199 		ap[n * elem_size + i] = 0;
200 	}
201 
202 	(*count) = n;
203 	return (void *) Tcl_Realloc(ap, n * elem_size);
204 }
205 
IndexedColor_ResetHash(IndexedColor * idc)206 static void IndexedColor_ResetHash(IndexedColor *idc)
207 {
208 	int i;
209 
210 	for (i = 0; i < 256; i++)
211 	{
212 		idc->hash[i].valid = 0;
213 	}
214 }
215 
216 /*
217  * Returns the nearest matching palette index for the given
218  * RGB values.
219  */
IndexedColor_RGB2Index(IndexedColor * idc,unsigned char r,unsigned char g,unsigned char b)220 static int IndexedColor_RGB2Index(IndexedColor *idc, unsigned char r, unsigned char g, unsigned char b)
221 {
222 	int i, diff, index, max;
223 	unsigned char *col;
224 	unsigned long pixel;
225 	t_color_entry *entry;
226 
227 	/* Calculate the pixel value */
228 	pixel = (r << 16) | (g << 8) | b;
229 
230 	/* Hash the pixel value */
231 	entry = &idc->hash[pixel % MAX_COLOR_ENTRY];
232 
233 	/* We already calculated the palette index */
234 	if (entry->valid && (entry->pixel == pixel))
235 	{
236 		/* Return the palette index */
237 		return entry->index;
238     }
239 
240 	index = 0;
241 	max = MAX_DELTA;
242 
243 	col = idc->rgb;
244 
245 	/* Check each palette entry */
246 	for (i = 0; i < 256; i++)
247 	{
248 		/* Work out the 'difference' between the colours */
249 
250 		diff = abs(r - col[0]);
251 		diff += abs(g - col[1]);
252 		diff += abs(b - col[2]);
253 
254 		/* Multiply by the 'colour factor' */
255 		diff *= 3;
256 
257 		/* Add in the effects of brightness */
258 		diff += abs(b + r + g - col[0] - col[1] - col[2]);
259 
260 		col += 3;
261 
262 		/* This palette entry is a better match than any other so far */
263 		if (diff < max)
264 		{
265 			/* Remember the palette index */
266 			index = i;
267 
268 			/* Remember the minimum difference */
269 			max = diff;
270 		}
271 	}
272 
273 	/* Remember the hash table entry info */
274 	entry->pixel = pixel;
275 	entry->index = index;
276 	entry->valid = 1;
277 
278 	/* Return the palette index */
279 	return index;
280 }
281 
282 /* set $index ?$color? */
objcmd_palette_set(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])283 static int objcmd_palette_set(ClientData clientData, Tcl_Interp *interp, int objc,
284 	Tcl_Obj *CONST objv[])
285 {
286 	CommandInfo *infoCmd = (CommandInfo *) clientData;
287 	int objC = objc - infoCmd->depth;
288 	Tcl_Obj *CONST *objV = objv + infoCmd->depth;
289 	char buf[20];
290 	int i, r, g, b;
291 
292 	if (Tcl_GetIntFromObj(interp, objV[1], &i) != TCL_OK)
293 	{
294 		return TCL_ERROR;
295 	}
296 	if ((i < 0) || (i >= 256))
297 	{
298 		return TCL_ERROR;
299 	}
300 
301 	if (objC == 3)
302 	{
303 		XColor *xColorPtr = Tk_AllocColorFromObj(interp, Tk_MainWindow(interp), objV[2]);
304 		if (xColorPtr == NULL)
305 		{
306 			return TCL_ERROR;
307 		}
308 		g_palette.rgb[i * 3] = xColorPtr->red / 255;
309 		g_palette.rgb[i * 3 + 1] = xColorPtr->green / 255;
310 		g_palette.rgb[i * 3 + 2] = xColorPtr->blue / 255;
311 		Tk_FreeColor(xColorPtr);
312 		return TCL_OK;
313 	}
314 
315 	r = g_palette.rgb[i * 3];
316 	g = g_palette.rgb[i * 3 + 1];
317 	b = g_palette.rgb[i * 3 + 2];
318 	strnfmt(buf, 20, "#%02X%02X%02X", r, g, b);
319 	Tcl_SetResult(interp, buf, TCL_VOLATILE);
320 
321 	return TCL_OK;
322 }
323 
324 static CommandInit commandInit[] = {
325 	{0, "palette", 0, 0, NULL, NULL, (ClientData) 0},
326 		{1, "set", 2, 3, "?color?", objcmd_palette_set, (ClientData) 0},
327 	{0, NULL, 0, 0, NULL, NULL, 0}
328 };
329 
330 /* Uniform colour table */
331 static byte def_pal1[6] = {255, 204, 153, 102, 51, 0};
332 static byte def_pal2[10] = {238, 221, 187, 170, 136, 119, 85, 68, 34, 17};
333 
Palette_Init(Tcl_Interp * interp)334 int Palette_Init(Tcl_Interp *interp)
335 {
336 	int i, j, k;
337 	unsigned char *rgb;
338 
339 	if (Palette_Initialized) return TCL_OK;
340 
341 	rgb = g_palette.rgb;
342 	g_palette.platData = NULL;
343 
344 	/* Create colour cube */
345 	for (i = 0; i < 6; i++)
346 	{
347 		for (j = 0; j < 6; j++)
348 		{
349 			for (k = 0; k < 6; k++)
350 			{
351 				/* Write this color to the array */
352 				*rgb++ = def_pal1[i];
353 				*rgb++ = def_pal1[j];
354 				*rgb++ = def_pal1[k];
355 			}
356 		}
357 	}
358 
359 	/* Create primary colours */
360 	for (i = 0; i < 10; i++)
361 	{
362 		*rgb++ = def_pal2[i];
363 		*rgb++ = 0;
364 		*rgb++ = 0;
365 	}
366 	for (i = 0; i < 10; i++)
367 	{
368 		*rgb++ = 0;
369 		*rgb++ = def_pal2[i];
370 		*rgb++ = 0;
371 	}
372 	for (i = 0; i < 10; i++)
373 	{
374 		*rgb++ = 0;
375 		*rgb++ = 0;
376 		*rgb++ = def_pal2[i];
377 	}
378 
379 	/* Create greys */
380 	for (i = 0; i < 10; i++)
381 	{
382 		*rgb++ = def_pal2[i];
383 		*rgb++ = def_pal2[i];
384 		*rgb++ = def_pal2[i];
385 	}
386 
387 	g_palette.platData = Plat_PaletteInit(g_palette.rgb);
388 
389 	(void) CommandInfo_Init(interp, commandInit, NULL);
390 
391 	Palette_ResetHash();
392 
393 	Palette_Initialized = TRUE;
394 
395 	Colormap_Init(interp);
396 
397 	return TCL_OK;
398 }
399 
400 
Palette_ResetHash(void)401 void Palette_ResetHash(void)
402 {
403 	IndexedColor_ResetHash(&g_palette);
404 }
405 
406 /*
407  * Returns the nearest matching palette index for the given
408  * RGB values.
409  */
Palette_RGB2Index(unsigned char r,unsigned char g,unsigned char b)410 int Palette_RGB2Index(unsigned char r, unsigned char g, unsigned char b)
411 {
412 	return IndexedColor_RGB2Index(&g_palette, r, g, b);
413 }
414 
415 
416 #ifdef PLATFORM_WIN
417 
Palette_GetHPal(void)418 void *Palette_GetHPal(void)
419 {
420 	return g_palette.platData; /* HPALETTE */
421 }
422 
423 #endif /* PLATFORM_WIN */
424 
Palette_GetRGB(void)425 unsigned char *Palette_GetRGB(void)
426 {
427 	return g_palette.rgb;
428 }
429 
430 
ExtToUtf_NewStringObj(CONST char * bytes,int length)431 Tcl_Obj *ExtToUtf_NewStringObj(CONST char *bytes, int length)
432 {
433 	char *utfString;
434 	Tcl_DString utfDString;
435 	Tcl_Obj *objResult;
436 
437 	utfString = Tcl_ExternalToUtfDString(NULL, bytes, length, &utfDString);
438 	objResult = Tcl_NewStringObj(utfString, Tcl_DStringLength(&utfDString));
439 	Tcl_DStringFree(&utfDString);
440 	return objResult;
441 }
442 
ExtToUtf_SetResult(Tcl_Interp * interp,cptr string)443 void ExtToUtf_SetResult(Tcl_Interp *interp, cptr string)
444 {
445 	char *utfString;
446 	Tcl_DString utfDString;
447 
448 	utfString = Tcl_ExternalToUtfDString(NULL, string, -1, &utfDString);
449 	Tcl_SetResult(interp, utfString, TCL_VOLATILE);
450 	Tcl_DStringFree(&utfDString);
451 }
452 
UtfToExt_TranslateFileName(Tcl_Interp * interp,char * utfPath,Tcl_DString * extDStringPtr)453 char *UtfToExt_TranslateFileName(Tcl_Interp *interp, char *utfPath, Tcl_DString *extDStringPtr)
454 {
455 	char *extString, *utfString;
456 	Tcl_DString utfDString;
457 	int utfLen;
458 
459 	utfString = Tcl_TranslateFileName(interp, utfPath, &utfDString);
460 	if (utfString == NULL) return NULL;
461 	utfLen = Tcl_DStringLength(&utfDString);
462 	extString = Tcl_UtfToExternalDString(NULL, utfString, utfLen, extDStringPtr);
463 	Tcl_DStringFree(&utfDString);
464 	return extString;
465 }
466 
467 static IndexedColor g_colormap;
468 unsigned char *g_colormap_rgb;
469 
Colormap_Init(Tcl_Interp * interp)470 int Colormap_Init(Tcl_Interp *interp)
471 {
472 #ifdef PLATFORM_X11
473 	Tk_Window tkwin = Tk_MainWindow(interp);
474 	Display *display = Tk_Display(tkwin);
475 	Colormap colormap = Tk_Colormap(tkwin); /* DefaultColormap() */
476 	XColor xColor;
477 #endif
478 	int i, k, r, g, b;
479 
480 	IndexedColor_ResetHash(&g_colormap);
481 
482 #ifdef PLATFORM_X11
483 	if (Tk_Depth(tkwin) == 8)
484 	{
485 		/*
486 		 * Allocate each color in the colormap, to prevent the colormap
487 		 * entries from changing.
488 		 */
489 		for (i = 0; i < 256; i++)
490 		{
491 			xColor.pixel = i;
492 			XQueryColor(display, colormap, &xColor);
493 			(void) Tk_GetColorByValue(tkwin, &xColor);
494 		}
495 	}
496 #endif /* PLATFORM_X11 */
497 
498 	for (i = 0; i < 256; i++)
499 	{
500 		r = g_palette.rgb[i * 3 + 0];
501 		g = g_palette.rgb[i * 3 + 1];
502 		b = g_palette.rgb[i * 3 + 2];
503 
504 #ifdef PLATFORM_X11
505 		if (Tk_Depth(tkwin) == 8)
506 		{
507 			/* Get the XColor at this location in the colormap */
508 			xColor.pixel = i;
509 			XQueryColor(display, colormap, &xColor);
510 
511 			/* Convert RGB values to 0-255 */
512 			r = xColor.red / 255;
513 			g = xColor.green / 255;
514 			b = xColor.blue / 255;
515 		}
516 #endif /* PLATFORM_X11 */
517 
518 		/* Remember RGB values at this colormap index */
519 		g_colormap.rgb[i * 3 + 0] = r;
520 		g_colormap.rgb[i * 3 + 1] = g;
521 		g_colormap.rgb[i * 3 + 2] = b;
522 	}
523 
524 	for (i = 0; i < 256; i++)
525 	{
526 		/* Get the RGB values at this palette index */
527 		r = g_palette.rgb[i * 3 + 0];
528 		g = g_palette.rgb[i * 3 + 1];
529 		b = g_palette.rgb[i * 3 + 2];
530 
531 		/* Find the closest color in the colormap */
532 		k = Colormap_RGB2Index(r, g, b);
533 
534 		/* Map palette index -> colormap index */
535 		g_palette2colormap[i] = k;
536 	}
537 
538 	/* Get the black and white pixels */
539 	g_colormap_black = PALETTE_BLACK;
540 	g_colormap_white = PALETTE_WHITE;
541 
542 #ifdef PLATFORM_X11
543 	if (Tk_Depth(tkwin) == 8)
544 	{
545 		g_colormap_black = BlackPixelOfScreen(Tk_Screen(tkwin));
546 		g_colormap_white = WhitePixelOfScreen(Tk_Screen(tkwin));
547 	}
548 #endif /* PLATFORM_X11 */
549 
550 	g_colormap_rgb = g_colormap.rgb;
551 
552 	return TCL_OK;
553 }
554 
Colormap_GetRGB(void)555 unsigned char *Colormap_GetRGB(void)
556 {
557 	return g_colormap.rgb;
558 }
559 
Colormap_RGB2Index(unsigned char r,unsigned char g,unsigned char b)560 int Colormap_RGB2Index(unsigned char r, unsigned char g, unsigned char b)
561 {
562 	return IndexedColor_RGB2Index(&g_colormap, r, g, b);
563 }
564 
565 /*
566  * Return a "standardized" string describing a font.
567  */
objcmd_fontdesc(ClientData dummy,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])568 int objcmd_fontdesc(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
569 {
570 	Tk_Font tkfont;
571 	TkFont *fontPtr;
572 	char buf[1024];
573 
574 	/* Hack - ignore unused parameter */
575 	(void) dummy;
576 
577     if (objc != 2)
578     {
579 		Tcl_WrongNumArgs(interp, 1, objv, "font");
580 		return TCL_ERROR;
581     }
582 
583 	tkfont = Tk_AllocFontFromObj(interp, Tk_MainWindow(interp), objv[1]);
584 	if (tkfont == NULL)
585 	{
586 		return TCL_ERROR;
587 	}
588 
589 	fontPtr = (TkFont *) tkfont;
590 
591 	strnfmt(buf, 1024, "-family {%s} -size %d -weight %s -slant %s "
592 		"-underline %d -overstrike %d",
593 		fontPtr->fa.family, fontPtr->fa.size,
594 		(fontPtr->fa.weight == TK_FW_BOLD) ? "bold" : "normal",
595 		(fontPtr->fa.slant == TK_FS_ITALIC) ? "italic" : "roman",
596 		fontPtr->fa.underline,
597 		fontPtr->fa.overstrike);
598 
599 	Tcl_SetStringObj(Tcl_GetObjResult(interp), buf, -1);
600 
601 	Tk_FreeFontFromObj(Tk_MainWindow(interp), objv[1]);
602 
603 	return TCL_OK;
604 }
605 
606 
607 cptr keyword_term_color[16] = {
608 	"TERM_DARK",
609 	"TERM_WHITE",
610 	"TERM_SLATE",
611 	"TERM_ORANGE",
612 	"TERM_RED",
613 	"TERM_GREEN",
614 	"TERM_BLUE",
615 	"TERM_UMBER",
616 	"TERM_L_DARK",
617 	"TERM_L_WHITE",
618 	"TERM_VIOLET",
619 	"TERM_YELLOW",
620 	"TERM_L_RED",
621 	"TERM_L_GREEN",
622 	"TERM_L_BLUE",
623 	"TERM_L_UMBER"
624 };
625 
626 
627 byte g_prompt_attr = TERM_WHITE;
628 
629 /*
630  * Display a prompt in the "message line", but don't save it.
631  */
prompt_print(cptr str)632 void prompt_print(cptr str)
633 {
634 	cptr attr = keyword_term_color[g_prompt_attr];
635 
636 	angtk_eval("angband_prompt", "set", str, attr, NULL);
637 }
638 
639 /*
640  * Erase the "message line".
641  */
prompt_erase(void)642 void prompt_erase(void)
643 {
644 	angtk_eval("angband_prompt", "wipe", NULL);
645 }
646 
647 /*
648  * Display a formatted prompt, using "vstrnfmt()" and "prompt_print()".
649  */
prompt_format(cptr fmt,...)650 void prompt_format(cptr fmt, ...)
651 {
652 	va_list vp;
653 
654 	char buf[1024];
655 
656 	/* Begin the Varargs Stuff */
657 	va_start(vp, fmt);
658 
659 	/* Format the args, save the length */
660 	(void)vstrnfmt(buf, 1024, fmt, &vp);
661 
662 	/* End the Varargs Stuff */
663 	va_end(vp);
664 
665 	/* Display */
666 	prompt_print(buf);
667 }
668 
prompt_append(cptr str)669 void prompt_append(cptr str)
670 {
671 	cptr attr = keyword_term_color[g_prompt_attr];
672 
673 	angtk_eval("angband_prompt", "append", str, attr, NULL);
674 }
675 
prompt_open(cptr str)676 void prompt_open(cptr str)
677 {
678 	cptr attr = keyword_term_color[g_prompt_attr];
679 
680 	angtk_eval("angband_prompt", "open", str, attr, NULL);
681 }
682 
prompt_update(cptr str)683 void prompt_update(cptr str)
684 {
685 	cptr attr = keyword_term_color[g_prompt_attr];
686 
687 	angtk_eval("angband_prompt", "update", str, attr, NULL);
688 }
689 
690 /*
691  * Display a prompt, wait for a keypress.
692  */
any_more(cptr prompt)693 void any_more(cptr prompt)
694 {
695 	bool old_quick = quick_messages;
696 
697 	/* Set the prompt */
698 	if (!prompt)
699 		prompt = "Hit any key to continue";
700 
701 	/* Set quick_messages so any key is accepted */
702 	quick_messages = TRUE;
703 
704 	/* Display the message, wait for a response */
705 	msgf(prompt);
706 	message_flush();
707 
708 	/* Restore quick_messages */
709 	quick_messages = old_quick;
710 }
711 
ExtToUtf_SetArrayValueString(cptr varName,cptr field,cptr value)712 int ExtToUtf_SetArrayValueString(cptr varName, cptr field, cptr value)
713 {
714 	Tcl_DString utfDString;
715 	cptr utfString;
716 
717 	Tcl_ExternalToUtfDString(NULL, value, -1, &utfDString);
718 	utfString = Tcl_DStringValue(&utfDString);
719 	if (Tcl_SetVar2(g_interp, varName, field, utfString, TCL_LEAVE_ERR_MSG)
720 		== NULL)
721 	{
722 		Tcl_DStringFree(&utfDString);
723 		return TCL_ERROR;
724 	}
725 	Tcl_DStringFree(&utfDString);
726 	return TCL_OK;
727 }
728 
729 
730