Fix typo in the last change.
[deliverable/binutils-gdb.git] / gdb / charset.c
1 /* Character set conversion support for GDB.
2
3 Copyright (C) 2001, 2003, 2007, 2008, 2009 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20 #include "defs.h"
21 #include "charset.h"
22 #include "gdbcmd.h"
23 #include "gdb_assert.h"
24 #include "gdb_obstack.h"
25 #include "charset-list.h"
26 #include "vec.h"
27
28 #include <stddef.h>
29 #include "gdb_string.h"
30 #include <ctype.h>
31
32 \f
33 /* How GDB's character set support works
34
35 GDB has three global settings:
36
37 - The `current host character set' is the character set GDB should
38 use in talking to the user, and which (hopefully) the user's
39 terminal knows how to display properly. Most users should not
40 change this.
41
42 - The `current target character set' is the character set the
43 program being debugged uses.
44
45 - The `current target wide character set' is the wide character set
46 the program being debugged uses, that is, the encoding used for
47 wchar_t.
48
49 There are commands to set each of these, and mechanisms for
50 choosing reasonable default values. GDB has a global list of
51 character sets that it can use as its host or target character
52 sets.
53
54 The header file `charset.h' declares various functions that
55 different pieces of GDB need to perform tasks like:
56
57 - printing target strings and characters to the user's terminal
58 (mostly target->host conversions),
59
60 - building target-appropriate representations of strings and
61 characters the user enters in expressions (mostly host->target
62 conversions),
63
64 and so on.
65
66 To avoid excessive code duplication and maintenance efforts,
67 GDB simply requires a capable iconv function. Users on platforms
68 without a suitable iconv can use the GNU iconv library. */
69
70 \f
71 #ifdef PHONY_ICONV
72
73 /* Provide a phony iconv that does as little as possible. Also,
74 arrange for there to be a single available character set. */
75
76 #undef GDB_DEFAULT_HOST_CHARSET
77 #define GDB_DEFAULT_HOST_CHARSET "ISO-8859-1"
78 #define GDB_DEFAULT_TARGET_CHARSET "ISO-8859-1"
79 #define GDB_DEFAULT_TARGET_WIDE_CHARSET "ISO-8859-1"
80 #undef DEFAULT_CHARSET_NAMES
81 #define DEFAULT_CHARSET_NAMES GDB_DEFAULT_HOST_CHARSET ,
82
83 #undef iconv_t
84 #define iconv_t int
85 #undef iconv_open
86 #undef iconv
87 #undef iconv_close
88
89 #undef ICONV_CONST
90 #define ICONV_CONST const
91
92 /* Some systems don't have EILSEQ, so we define it here, but not as
93 EINVAL, because callers of `iconv' want to distinguish EINVAL and
94 EILSEQ. This is what iconv.h from libiconv does as well. Note
95 that wchar.h may also define EILSEQ, so this needs to be after we
96 include wchar.h, which happens in defs.h through gdb_wchar.h. */
97 #ifndef EILSEQ
98 #define EILSEQ ENOENT
99 #endif
100
101 iconv_t
102 iconv_open (const char *to, const char *from)
103 {
104 /* We allow conversions from UCS-4BE, wchar_t, and the host charset.
105 We allow conversions to wchar_t and the host charset. */
106 if (strcmp (from, "UCS-4BE") && strcmp (from, "wchar_t")
107 && strcmp (from, GDB_DEFAULT_HOST_CHARSET))
108 return -1;
109 if (strcmp (to, "wchar_t") && strcmp (to, GDB_DEFAULT_HOST_CHARSET))
110 return -1;
111
112 /* Return 1 if we are converting from UCS-4BE, 0 otherwise. This is
113 used as a flag in calls to iconv. */
114 return !strcmp (from, "UCS-4BE");
115 }
116
117 int
118 iconv_close (iconv_t arg)
119 {
120 return 0;
121 }
122
123 size_t
124 iconv (iconv_t ucs_flag, const char **inbuf, size_t *inbytesleft,
125 char **outbuf, size_t *outbytesleft)
126 {
127 if (ucs_flag)
128 {
129 while (*inbytesleft >= 4)
130 {
131 size_t j;
132 unsigned long c = 0;
133
134 for (j = 0; j < 4; ++j)
135 {
136 c <<= 8;
137 c += (*inbuf)[j] & 0xff;
138 }
139
140 if (c >= 256)
141 {
142 errno = EILSEQ;
143 return -1;
144 }
145 **outbuf = c & 0xff;
146 ++*outbuf;
147 --*outbytesleft;
148
149 ++*inbuf;
150 *inbytesleft -= 4;
151 }
152 if (*inbytesleft < 4)
153 {
154 errno = EINVAL;
155 return -1;
156 }
157 }
158 else
159 {
160 /* In all other cases we simply copy input bytes to the
161 output. */
162 size_t amt = *inbytesleft;
163 if (amt > *outbytesleft)
164 amt = *outbytesleft;
165 memcpy (*outbuf, *inbuf, amt);
166 *inbuf += amt;
167 *outbuf += amt;
168 *inbytesleft -= amt;
169 *outbytesleft -= amt;
170 }
171
172 if (*inbytesleft)
173 {
174 errno = E2BIG;
175 return -1;
176 }
177
178 /* The number of non-reversible conversions -- but they were all
179 reversible. */
180 return 0;
181 }
182
183 #endif
184
185
186 \f
187 /* The global lists of character sets and translations. */
188
189
190 #ifndef GDB_DEFAULT_TARGET_CHARSET
191 #define GDB_DEFAULT_TARGET_CHARSET "ISO-8859-1"
192 #endif
193
194 #ifndef GDB_DEFAULT_TARGET_WIDE_CHARSET
195 #define GDB_DEFAULT_TARGET_WIDE_CHARSET "UCS-4"
196 #endif
197
198 static const char *auto_host_charset_name = GDB_DEFAULT_HOST_CHARSET;
199 static const char *host_charset_name = "auto";
200 static void
201 show_host_charset_name (struct ui_file *file, int from_tty,
202 struct cmd_list_element *c,
203 const char *value)
204 {
205 if (!strcmp (value, "auto"))
206 fprintf_filtered (file,
207 _("The host character set is \"auto; currently %s\".\n"),
208 auto_host_charset_name);
209 else
210 fprintf_filtered (file, _("The host character set is \"%s\".\n"), value);
211 }
212
213 static const char *target_charset_name = GDB_DEFAULT_TARGET_CHARSET;
214 static void
215 show_target_charset_name (struct ui_file *file, int from_tty,
216 struct cmd_list_element *c, const char *value)
217 {
218 fprintf_filtered (file, _("The target character set is \"%s\".\n"),
219 value);
220 }
221
222 static const char *target_wide_charset_name = GDB_DEFAULT_TARGET_WIDE_CHARSET;
223 static void
224 show_target_wide_charset_name (struct ui_file *file, int from_tty,
225 struct cmd_list_element *c, const char *value)
226 {
227 fprintf_filtered (file, _("The target wide character set is \"%s\".\n"),
228 value);
229 }
230
231 static const char *default_charset_names[] =
232 {
233 DEFAULT_CHARSET_NAMES
234 0
235 };
236
237 static const char **charset_enum;
238
239 \f
240 /* If the target wide character set has big- or little-endian
241 variants, these are the corresponding names. */
242 static const char *target_wide_charset_be_name;
243 static const char *target_wide_charset_le_name;
244
245 /* A helper function for validate which sets the target wide big- and
246 little-endian character set names, if possible. */
247
248 static void
249 set_be_le_names (void)
250 {
251 int i, len;
252
253 target_wide_charset_le_name = NULL;
254 target_wide_charset_be_name = NULL;
255
256 len = strlen (target_wide_charset_name);
257 for (i = 0; charset_enum[i]; ++i)
258 {
259 if (strncmp (target_wide_charset_name, charset_enum[i], len))
260 continue;
261 if ((charset_enum[i][len] == 'B'
262 || charset_enum[i][len] == 'L')
263 && charset_enum[i][len + 1] == 'E'
264 && charset_enum[i][len + 2] == '\0')
265 {
266 if (charset_enum[i][len] == 'B')
267 target_wide_charset_be_name = charset_enum[i];
268 else
269 target_wide_charset_le_name = charset_enum[i];
270 }
271 }
272 }
273
274 /* 'Set charset', 'set host-charset', 'set target-charset', 'set
275 target-wide-charset', 'set charset' sfunc's. */
276
277 static void
278 validate (void)
279 {
280 iconv_t desc;
281 const char *host_cset = host_charset ();
282
283 desc = iconv_open (target_wide_charset_name, host_cset);
284 if (desc == (iconv_t) -1)
285 error ("Cannot convert between character sets `%s' and `%s'",
286 target_wide_charset_name, host_cset);
287 iconv_close (desc);
288
289 desc = iconv_open (target_charset_name, host_cset);
290 if (desc == (iconv_t) -1)
291 error ("Cannot convert between character sets `%s' and `%s'",
292 target_charset_name, host_cset);
293 iconv_close (desc);
294
295 set_be_le_names ();
296 }
297
298 /* This is the sfunc for the 'set charset' command. */
299 static void
300 set_charset_sfunc (char *charset, int from_tty, struct cmd_list_element *c)
301 {
302 /* CAREFUL: set the target charset here as well. */
303 target_charset_name = host_charset_name;
304 validate ();
305 }
306
307 /* 'set host-charset' command sfunc. We need a wrapper here because
308 the function needs to have a specific signature. */
309 static void
310 set_host_charset_sfunc (char *charset, int from_tty,
311 struct cmd_list_element *c)
312 {
313 validate ();
314 }
315
316 /* Wrapper for the 'set target-charset' command. */
317 static void
318 set_target_charset_sfunc (char *charset, int from_tty,
319 struct cmd_list_element *c)
320 {
321 validate ();
322 }
323
324 /* Wrapper for the 'set target-wide-charset' command. */
325 static void
326 set_target_wide_charset_sfunc (char *charset, int from_tty,
327 struct cmd_list_element *c)
328 {
329 validate ();
330 }
331
332 /* sfunc for the 'show charset' command. */
333 static void
334 show_charset (struct ui_file *file, int from_tty, struct cmd_list_element *c,
335 const char *name)
336 {
337 show_host_charset_name (file, from_tty, c, host_charset_name);
338 show_target_charset_name (file, from_tty, c, target_charset_name);
339 show_target_wide_charset_name (file, from_tty, c, target_wide_charset_name);
340 }
341
342 \f
343 /* Accessor functions. */
344
345 const char *
346 host_charset (void)
347 {
348 if (!strcmp (host_charset_name, "auto"))
349 return auto_host_charset_name;
350 return host_charset_name;
351 }
352
353 const char *
354 target_charset (void)
355 {
356 return target_charset_name;
357 }
358
359 const char *
360 target_wide_charset (void)
361 {
362 if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
363 {
364 if (target_wide_charset_be_name)
365 return target_wide_charset_be_name;
366 }
367 else
368 {
369 if (target_wide_charset_le_name)
370 return target_wide_charset_le_name;
371 }
372
373 return target_wide_charset_name;
374 }
375
376 \f
377 /* Host character set management. For the time being, we assume that
378 the host character set is some superset of ASCII. */
379
380 char
381 host_letter_to_control_character (char c)
382 {
383 if (c == '?')
384 return 0177;
385 return c & 0237;
386 }
387
388 /* Convert a host character, C, to its hex value. C must already have
389 been validated using isxdigit. */
390
391 int
392 host_hex_value (char c)
393 {
394 if (isdigit (c))
395 return c - '0';
396 if (c >= 'a' && c <= 'f')
397 return 10 + c - 'a';
398 gdb_assert (c >= 'A' && c <= 'F');
399 return 10 + c - 'A';
400 }
401
402 \f
403 /* Public character management functions. */
404
405 /* A cleanup function which is run to close an iconv descriptor. */
406
407 static void
408 cleanup_iconv (void *p)
409 {
410 iconv_t *descp = p;
411 iconv_close (*descp);
412 }
413
414 void
415 convert_between_encodings (const char *from, const char *to,
416 const gdb_byte *bytes, unsigned int num_bytes,
417 int width, struct obstack *output,
418 enum transliterations translit)
419 {
420 iconv_t desc;
421 struct cleanup *cleanups;
422 size_t inleft;
423 char *inp;
424 unsigned int space_request;
425
426 /* Often, the host and target charsets will be the same. */
427 if (!strcmp (from, to))
428 {
429 obstack_grow (output, bytes, num_bytes);
430 return;
431 }
432
433 desc = iconv_open (to, from);
434 if (desc == (iconv_t) -1)
435 perror_with_name ("Converting character sets");
436 cleanups = make_cleanup (cleanup_iconv, &desc);
437
438 inleft = num_bytes;
439 inp = (char *) bytes;
440
441 space_request = num_bytes;
442
443 while (inleft > 0)
444 {
445 char *outp;
446 size_t outleft, r;
447 int old_size;
448
449 old_size = obstack_object_size (output);
450 obstack_blank (output, space_request);
451
452 outp = obstack_base (output) + old_size;
453 outleft = space_request;
454
455 r = iconv (desc, (ICONV_CONST char **) &inp, &inleft, &outp, &outleft);
456
457 /* Now make sure that the object on the obstack only includes
458 bytes we have converted. */
459 obstack_blank (output, - (int) outleft);
460
461 if (r == (size_t) -1)
462 {
463 switch (errno)
464 {
465 case EILSEQ:
466 {
467 int i;
468
469 /* Invalid input sequence. */
470 if (translit == translit_none)
471 error (_("Could not convert character to `%s' character set"),
472 to);
473
474 /* We emit escape sequence for the bytes, skip them,
475 and try again. */
476 for (i = 0; i < width; ++i)
477 {
478 char octal[5];
479
480 sprintf (octal, "\\%.3o", *inp & 0xff);
481 obstack_grow_str (output, octal);
482
483 ++inp;
484 --inleft;
485 }
486 }
487 break;
488
489 case E2BIG:
490 /* We ran out of space in the output buffer. Make it
491 bigger next time around. */
492 space_request *= 2;
493 break;
494
495 case EINVAL:
496 /* Incomplete input sequence. FIXME: ought to report this
497 to the caller somehow. */
498 inleft = 0;
499 break;
500
501 default:
502 perror_with_name ("Internal error while converting character sets");
503 }
504 }
505 }
506
507 do_cleanups (cleanups);
508 }
509
510 \f
511
512 /* An iterator that returns host wchar_t's from a target string. */
513 struct wchar_iterator
514 {
515 /* The underlying iconv descriptor. */
516 iconv_t desc;
517
518 /* The input string. This is updated as convert characters. */
519 char *input;
520 /* The number of bytes remaining in the input. */
521 size_t bytes;
522
523 /* The width of an input character. */
524 size_t width;
525
526 /* The output buffer and its size. */
527 gdb_wchar_t *out;
528 size_t out_size;
529 };
530
531 /* Create a new iterator. */
532 struct wchar_iterator *
533 make_wchar_iterator (const gdb_byte *input, size_t bytes, const char *charset,
534 size_t width)
535 {
536 struct wchar_iterator *result;
537 iconv_t desc;
538
539 desc = iconv_open ("wchar_t", charset);
540 if (desc == (iconv_t) -1)
541 perror_with_name ("Converting character sets");
542
543 result = XNEW (struct wchar_iterator);
544 result->desc = desc;
545 result->input = (char *) input;
546 result->bytes = bytes;
547 result->width = width;
548
549 result->out = XNEW (gdb_wchar_t);
550 result->out_size = 1;
551
552 return result;
553 }
554
555 static void
556 do_cleanup_iterator (void *p)
557 {
558 struct wchar_iterator *iter = p;
559
560 iconv_close (iter->desc);
561 xfree (iter->out);
562 xfree (iter);
563 }
564
565 struct cleanup *
566 make_cleanup_wchar_iterator (struct wchar_iterator *iter)
567 {
568 return make_cleanup (do_cleanup_iterator, iter);
569 }
570
571 int
572 wchar_iterate (struct wchar_iterator *iter,
573 enum wchar_iterate_result *out_result,
574 gdb_wchar_t **out_chars,
575 const gdb_byte **ptr,
576 size_t *len)
577 {
578 size_t out_request;
579
580 /* Try to convert some characters. At first we try to convert just
581 a single character. The reason for this is that iconv does not
582 necessarily update its outgoing arguments when it encounters an
583 invalid input sequence -- but we want to reliably report this to
584 our caller so it can emit an escape sequence. */
585 out_request = 1;
586 while (iter->bytes > 0)
587 {
588 char *outptr = (char *) &iter->out[0];
589 char *orig_inptr = iter->input;
590 size_t orig_in = iter->bytes;
591 size_t out_avail = out_request * sizeof (gdb_wchar_t);
592 size_t num;
593 gdb_wchar_t result;
594
595 size_t r = iconv (iter->desc,
596 (ICONV_CONST char **) &iter->input, &iter->bytes,
597 &outptr, &out_avail);
598 if (r == (size_t) -1)
599 {
600 switch (errno)
601 {
602 case EILSEQ:
603 /* Invalid input sequence. Skip it, and let the caller
604 know about it. */
605 *out_result = wchar_iterate_invalid;
606 *ptr = iter->input;
607 *len = iter->width;
608 iter->input += iter->width;
609 iter->bytes -= iter->width;
610 return 0;
611
612 case E2BIG:
613 /* We ran out of space. We still might have converted a
614 character; if so, return it. Otherwise, grow the
615 buffer and try again. */
616 if (out_avail < out_request * sizeof (gdb_wchar_t))
617 break;
618
619 ++out_request;
620 if (out_request > iter->out_size)
621 {
622 iter->out_size = out_request;
623 iter->out = xrealloc (iter->out,
624 out_request * sizeof (gdb_wchar_t));
625 }
626 continue;
627
628 case EINVAL:
629 /* Incomplete input sequence. Let the caller know, and
630 arrange for future calls to see EOF. */
631 *out_result = wchar_iterate_incomplete;
632 *ptr = iter->input;
633 *len = iter->bytes;
634 iter->bytes = 0;
635 return 0;
636
637 default:
638 perror_with_name ("Internal error while converting character sets");
639 }
640 }
641
642 /* We converted something. */
643 num = out_request - out_avail / sizeof (gdb_wchar_t);
644 *out_result = wchar_iterate_ok;
645 *out_chars = iter->out;
646 *ptr = orig_inptr;
647 *len = orig_in - iter->bytes;
648 return num;
649 }
650
651 /* Really done. */
652 *out_result = wchar_iterate_eof;
653 return -1;
654 }
655
656 \f
657 /* The charset.c module initialization function. */
658
659 extern initialize_file_ftype _initialize_charset; /* -Wmissing-prototype */
660
661 typedef char *char_ptr;
662 DEF_VEC_P (char_ptr);
663
664 static VEC (char_ptr) *charsets;
665
666 #ifdef PHONY_ICONV
667
668 static void
669 find_charset_names (void)
670 {
671 VEC_safe_push (char_ptr, charsets, GDB_DEFAULT_HOST_CHARSET);
672 VEC_safe_push (char_ptr, charsets, NULL);
673 }
674
675 #else /* PHONY_ICONV */
676
677 /* Sometimes, libiconv redefines iconvlist as libiconvlist -- but
678 provides different symbols in the static and dynamic libraries.
679 So, configure may see libiconvlist but not iconvlist. But, calling
680 iconvlist is the right thing to do and will work. Hence we do a
681 check here but unconditionally call iconvlist below. */
682 #if defined (HAVE_ICONVLIST) || defined (HAVE_LIBICONVLIST)
683
684 /* A helper function that adds some character sets to the vector of
685 all character sets. This is a callback function for iconvlist. */
686
687 static int
688 add_one (unsigned int count, const char *const *names, void *data)
689 {
690 unsigned int i;
691
692 for (i = 0; i < count; ++i)
693 VEC_safe_push (char_ptr, charsets, xstrdup (names[i]));
694
695 return 0;
696 }
697
698 static void
699 find_charset_names (void)
700 {
701 iconvlist (add_one, NULL);
702 VEC_safe_push (char_ptr, charsets, NULL);
703 }
704
705 #else
706
707 static void
708 find_charset_names (void)
709 {
710 FILE *in;
711
712 in = popen ("iconv -l", "r");
713 /* It is ok to ignore errors; we'll fall back on a default. */
714 if (!in)
715 return;
716
717 /* POSIX says that iconv -l uses an unspecified format. We parse
718 the glibc format; feel free to add others as needed. */
719 while (!feof (in))
720 {
721 /* The size of buf is chosen arbitrarily. A character set name
722 longer than this would not be very nice. */
723 char buf[80];
724 int len;
725 char *r = fgets (buf, sizeof (buf), in);
726 if (!r)
727 break;
728 len = strlen (r);
729 if (len <= 3)
730 continue;
731 if (buf[len - 2] == '/' && buf[len - 3] == '/')
732 buf[len - 3] = '\0';
733 VEC_safe_push (char_ptr, charsets, xstrdup (buf));
734 }
735
736 pclose (in);
737
738 VEC_safe_push (char_ptr, charsets, NULL);
739 }
740
741 #endif /* HAVE_ICONVLIST || HAVE_LIBICONVLIST */
742 #endif /* PHONY_ICONV */
743
744 void
745 _initialize_charset (void)
746 {
747 struct cmd_list_element *new_cmd;
748
749 /* The first element is always "auto"; then we skip it for the
750 commands where it is not allowed. */
751 VEC_safe_push (char_ptr, charsets, "auto");
752 find_charset_names ();
753
754 if (VEC_length (char_ptr, charsets) > 1)
755 charset_enum = (const char **) VEC_address (char_ptr, charsets);
756 else
757 charset_enum = default_charset_names;
758
759 #ifndef PHONY_ICONV
760 #ifdef HAVE_LANGINFO_CODESET
761 auto_host_charset_name = nl_langinfo (CODESET);
762 target_charset_name = auto_host_charset_name;
763
764 set_be_le_names ();
765 #endif
766 #endif
767
768 add_setshow_enum_cmd ("charset", class_support,
769 &charset_enum[1], &host_charset_name, _("\
770 Set the host and target character sets."), _("\
771 Show the host and target character sets."), _("\
772 The `host character set' is the one used by the system GDB is running on.\n\
773 The `target character set' is the one used by the program being debugged.\n\
774 You may only use supersets of ASCII for your host character set; GDB does\n\
775 not support any others.\n\
776 To see a list of the character sets GDB supports, type `set charset <TAB>'."),
777 /* Note that the sfunc below needs to set
778 target_charset_name, because the 'set
779 charset' command sets two variables. */
780 set_charset_sfunc,
781 show_charset,
782 &setlist, &showlist);
783
784 add_setshow_enum_cmd ("host-charset", class_support,
785 charset_enum, &host_charset_name, _("\
786 Set the host character set."), _("\
787 Show the host character set."), _("\
788 The `host character set' is the one used by the system GDB is running on.\n\
789 You may only use supersets of ASCII for your host character set; GDB does\n\
790 not support any others.\n\
791 To see a list of the character sets GDB supports, type `set host-charset <TAB>'."),
792 set_host_charset_sfunc,
793 show_host_charset_name,
794 &setlist, &showlist);
795
796 add_setshow_enum_cmd ("target-charset", class_support,
797 &charset_enum[1], &target_charset_name, _("\
798 Set the target character set."), _("\
799 Show the target character set."), _("\
800 The `target character set' is the one used by the program being debugged.\n\
801 GDB translates characters and strings between the host and target\n\
802 character sets as needed.\n\
803 To see a list of the character sets GDB supports, type `set target-charset'<TAB>"),
804 set_target_charset_sfunc,
805 show_target_charset_name,
806 &setlist, &showlist);
807
808 add_setshow_enum_cmd ("target-wide-charset", class_support,
809 &charset_enum[1], &target_wide_charset_name,
810 _("\
811 Set the target wide character set."), _("\
812 Show the target wide character set."), _("\
813 The `target wide character set' is the one used by the program being debugged.\n\
814 In particular it is the encoding used by `wchar_t'.\n\
815 GDB translates characters and strings between the host and target\n\
816 character sets as needed.\n\
817 To see a list of the character sets GDB supports, type\n\
818 `set target-wide-charset'<TAB>"),
819 set_target_wide_charset_sfunc,
820 show_target_wide_charset_name,
821 &setlist, &showlist);
822 }
This page took 0.047318 seconds and 5 git commands to generate.