1 /*
2 8bit strings utilities
3
4 Copyright (C) 2007-2021
5 Free Software Foundation, Inc.
6
7 Written by:
8 Rostislav Benes, 2007
9
10 This file is part of the Midnight Commander.
11
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
16
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include <config.h>
27
28 #include <ctype.h>
29 #include <stdlib.h>
30
31 #include "lib/global.h"
32 #include "lib/strutil.h"
33
34 /* Functions for singlebyte encodings, all characters have width 1
35 * using standard system functions.
36 * There are only small differences between functions in strutil8bit.c
37 * and strutilascii.c.
38 */
39
40 /*** global variables ****************************************************************************/
41
42 /*** file scope macro definitions ****************************************************************/
43
44 /*
45 * Inlines to equalize 'char' signedness for single 'char' encodings.
46 * Instead of writing
47 * isspace ((unsigned char) c);
48 * you can write
49 * char_isspace (c);
50 */
51 #define DECLARE_CTYPE_WRAPPER(func_name) \
52 static inline int char_##func_name(char c) \
53 { \
54 return func_name((int)(unsigned char)c); \
55 }
56
57 /*** file scope type declarations ****************************************************************/
58
59 /*** file scope variables ************************************************************************/
60
61 static const char replch = '?';
62
63 /* --------------------------------------------------------------------------------------------- */
64 /*** file scope functions ************************************************************************/
65 /* --------------------------------------------------------------------------------------------- */
66
67 /* *INDENT-OFF* */
68 DECLARE_CTYPE_WRAPPER (isalnum)
DECLARE_CTYPE_WRAPPER(isdigit)69 DECLARE_CTYPE_WRAPPER (isdigit)
70 DECLARE_CTYPE_WRAPPER (isprint)
71 DECLARE_CTYPE_WRAPPER (ispunct)
72 DECLARE_CTYPE_WRAPPER (isspace)
73 DECLARE_CTYPE_WRAPPER (toupper)
74 DECLARE_CTYPE_WRAPPER (tolower)
75 /* *INDENT-ON* */
76
77 /* --------------------------------------------------------------------------------------------- */
78
79 static void
80 str_8bit_insert_replace_char (GString * buffer)
81 {
82 g_string_append_c (buffer, replch);
83 }
84
85 /* --------------------------------------------------------------------------------------------- */
86
87 static gboolean
str_8bit_is_valid_string(const char * text)88 str_8bit_is_valid_string (const char *text)
89 {
90 (void) text;
91 return TRUE;
92 }
93
94 /* --------------------------------------------------------------------------------------------- */
95
96 static int
str_8bit_is_valid_char(const char * ch,size_t size)97 str_8bit_is_valid_char (const char *ch, size_t size)
98 {
99 (void) ch;
100 (void) size;
101 return 1;
102 }
103
104 /* --------------------------------------------------------------------------------------------- */
105
106 static void
str_8bit_cnext_char(const char ** text)107 str_8bit_cnext_char (const char **text)
108 {
109 (*text)++;
110 }
111
112 /* --------------------------------------------------------------------------------------------- */
113
114 static void
str_8bit_cprev_char(const char ** text)115 str_8bit_cprev_char (const char **text)
116 {
117 (*text)--;
118 }
119
120 /* --------------------------------------------------------------------------------------------- */
121
122 static int
str_8bit_cnext_noncomb_char(const char ** text)123 str_8bit_cnext_noncomb_char (const char **text)
124 {
125 if (*text[0] == '\0')
126 return 0;
127
128 (*text)++;
129 return 1;
130 }
131
132 /* --------------------------------------------------------------------------------------------- */
133
134 static int
str_8bit_cprev_noncomb_char(const char ** text,const char * begin)135 str_8bit_cprev_noncomb_char (const char **text, const char *begin)
136 {
137 if ((*text) == begin)
138 return 0;
139
140 (*text)--;
141 return 1;
142 }
143
144 /* --------------------------------------------------------------------------------------------- */
145
146 static gboolean
str_8bit_isspace(const char * text)147 str_8bit_isspace (const char *text)
148 {
149 return char_isspace (text[0]) != 0;
150 }
151
152 /* --------------------------------------------------------------------------------------------- */
153
154 static gboolean
str_8bit_ispunct(const char * text)155 str_8bit_ispunct (const char *text)
156 {
157 return char_ispunct (text[0]) != 0;
158 }
159
160 /* --------------------------------------------------------------------------------------------- */
161
162 static gboolean
str_8bit_isalnum(const char * text)163 str_8bit_isalnum (const char *text)
164 {
165 return char_isalnum (text[0]) != 0;
166 }
167
168 /* --------------------------------------------------------------------------------------------- */
169
170 static gboolean
str_8bit_isdigit(const char * text)171 str_8bit_isdigit (const char *text)
172 {
173 return char_isdigit (text[0]) != 0;
174 }
175
176 /* --------------------------------------------------------------------------------------------- */
177
178 static gboolean
str_8bit_isprint(const char * text)179 str_8bit_isprint (const char *text)
180 {
181 return char_isprint (text[0]) != 0;
182 }
183
184 /* --------------------------------------------------------------------------------------------- */
185
186 static gboolean
str_8bit_iscombiningmark(const char * text)187 str_8bit_iscombiningmark (const char *text)
188 {
189 (void) text;
190 return FALSE;
191 }
192
193 /* --------------------------------------------------------------------------------------------- */
194
195 static int
str_8bit_toupper(const char * text,char ** out,size_t * remain)196 str_8bit_toupper (const char *text, char **out, size_t * remain)
197 {
198 if (*remain <= 1)
199 return FALSE;
200
201 (*out)[0] = char_toupper (text[0]);
202 (*out)++;
203 (*remain)--;
204 return TRUE;
205 }
206
207 /* --------------------------------------------------------------------------------------------- */
208
209 static gboolean
str_8bit_tolower(const char * text,char ** out,size_t * remain)210 str_8bit_tolower (const char *text, char **out, size_t * remain)
211 {
212 if (*remain <= 1)
213 return FALSE;
214
215 (*out)[0] = char_tolower (text[0]);
216 (*out)++;
217 (*remain)--;
218 return TRUE;
219 }
220
221 /* --------------------------------------------------------------------------------------------- */
222
223 static int
str_8bit_length(const char * text)224 str_8bit_length (const char *text)
225 {
226 return strlen (text);
227 }
228
229 /* --------------------------------------------------------------------------------------------- */
230
231 static int
str_8bit_length2(const char * text,int size)232 str_8bit_length2 (const char *text, int size)
233 {
234 return (size >= 0) ? MIN (strlen (text), (gsize) size) : strlen (text);
235 }
236
237 /* --------------------------------------------------------------------------------------------- */
238
239 static gchar *
str_8bit_conv_gerror_message(GError * mcerror,const char * def_msg)240 str_8bit_conv_gerror_message (GError * mcerror, const char *def_msg)
241 {
242 GIConv conv;
243 gchar *ret;
244
245 /* glib messages are in UTF-8 charset */
246 conv = str_crt_conv_from ("UTF-8");
247
248 if (conv == INVALID_CONV)
249 ret = g_strdup (def_msg != NULL ? def_msg : "");
250 else
251 {
252 GString *buf;
253
254 buf = g_string_new ("");
255
256 if (str_convert (conv, mcerror->message, buf) != ESTR_FAILURE)
257 ret = g_string_free (buf, FALSE);
258 else
259 {
260 ret = g_strdup (def_msg != NULL ? def_msg : "");
261 g_string_free (buf, TRUE);
262 }
263
264 str_close_conv (conv);
265 }
266
267 return ret;
268 }
269
270 /* --------------------------------------------------------------------------------------------- */
271
272 static estr_t
str_8bit_vfs_convert_to(GIConv coder,const char * string,int size,GString * buffer)273 str_8bit_vfs_convert_to (GIConv coder, const char *string, int size, GString * buffer)
274 {
275 estr_t result = ESTR_SUCCESS;
276
277 if (coder == str_cnv_not_convert)
278 g_string_append_len (buffer, string, size);
279 else
280 result = str_nconvert (coder, string, size, buffer);
281
282 return result;
283 }
284
285 /* --------------------------------------------------------------------------------------------- */
286
287 static const char *
str_8bit_term_form(const char * text)288 str_8bit_term_form (const char *text)
289 {
290 static char result[BUF_MEDIUM];
291 char *actual;
292 size_t remain;
293 size_t length;
294 size_t pos = 0;
295
296 actual = result;
297 remain = sizeof (result);
298 length = strlen (text);
299
300 for (; pos < length && remain > 1; pos++, actual++, remain--)
301 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
302
303 actual[0] = '\0';
304 return result;
305 }
306
307 /* --------------------------------------------------------------------------------------------- */
308
309 static const char *
str_8bit_fit_to_term(const char * text,int width,align_crt_t just_mode)310 str_8bit_fit_to_term (const char *text, int width, align_crt_t just_mode)
311 {
312 static char result[BUF_MEDIUM];
313 char *actual;
314 size_t remain;
315 int ident = 0;
316 size_t length;
317 size_t pos = 0;
318
319 length = strlen (text);
320 actual = result;
321 remain = sizeof (result);
322
323 if ((int) length <= width)
324 {
325 switch (HIDE_FIT (just_mode))
326 {
327 case J_CENTER_LEFT:
328 case J_CENTER:
329 ident = (width - length) / 2;
330 break;
331 case J_RIGHT:
332 ident = width - length;
333 break;
334 default:
335 break;
336 }
337
338 if ((int) remain <= ident)
339 goto finally;
340 memset (actual, ' ', ident);
341 actual += ident;
342 remain -= ident;
343
344 for (; pos < length && remain > 1; pos++, actual++, remain--)
345 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
346
347 if (width - length - ident > 0)
348 {
349 if (remain <= width - length - ident)
350 goto finally;
351 memset (actual, ' ', width - length - ident);
352 actual += width - length - ident;
353 }
354 }
355 else if (IS_FIT (just_mode))
356 {
357 for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
358 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
359
360 if (remain <= 1)
361 goto finally;
362 actual[0] = '~';
363 actual++;
364 remain--;
365
366 pos += length - width + 1;
367 for (; pos < length && remain > 1; pos++, actual++, remain--)
368 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
369 }
370 else
371 {
372 switch (HIDE_FIT (just_mode))
373 {
374 case J_CENTER:
375 ident = (length - width) / 2;
376 break;
377 case J_RIGHT:
378 ident = length - width;
379 break;
380 default:
381 break;
382 }
383
384 pos += ident;
385 for (; pos < (gsize) (ident + width) && remain > 1; pos++, actual++, remain--)
386 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
387 }
388
389 finally:
390 if (actual >= result + sizeof (result))
391 actual = result + sizeof (result) - 1;
392 actual[0] = '\0';
393 return result;
394 }
395
396 /* --------------------------------------------------------------------------------------------- */
397
398 static const char *
str_8bit_term_trim(const char * text,int width)399 str_8bit_term_trim (const char *text, int width)
400 {
401 static char result[BUF_MEDIUM];
402 size_t remain;
403 char *actual;
404 size_t length;
405
406 length = strlen (text);
407 actual = result;
408 remain = sizeof (result);
409
410 if (width > 0)
411 {
412 size_t pos;
413
414 if (width >= (int) length)
415 {
416 for (pos = 0; pos < length && remain > 1; pos++, actual++, remain--)
417 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
418 }
419 else if (width <= 3)
420 {
421 memset (actual, '.', width);
422 actual += width;
423 }
424 else
425 {
426 memset (actual, '.', 3);
427 actual += 3;
428 remain -= 3;
429
430 for (pos = length - width + 3; pos < length && remain > 1; pos++, actual++, remain--)
431 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
432 }
433 }
434
435 actual[0] = '\0';
436 return result;
437 }
438
439 /* --------------------------------------------------------------------------------------------- */
440
441 static int
str_8bit_term_width2(const char * text,size_t length)442 str_8bit_term_width2 (const char *text, size_t length)
443 {
444 return (length != (size_t) (-1)) ? MIN (strlen (text), length) : strlen (text);
445 }
446
447 /* --------------------------------------------------------------------------------------------- */
448
449 static int
str_8bit_term_width1(const char * text)450 str_8bit_term_width1 (const char *text)
451 {
452 return str_8bit_term_width2 (text, (size_t) (-1));
453 }
454
455 /* --------------------------------------------------------------------------------------------- */
456
457 static int
str_8bit_term_char_width(const char * text)458 str_8bit_term_char_width (const char *text)
459 {
460 (void) text;
461 return 1;
462 }
463
464 /* --------------------------------------------------------------------------------------------- */
465
466 static const char *
str_8bit_term_substring(const char * text,int start,int width)467 str_8bit_term_substring (const char *text, int start, int width)
468 {
469 static char result[BUF_MEDIUM];
470 size_t remain;
471 char *actual;
472 size_t length;
473
474 actual = result;
475 remain = sizeof (result);
476 length = strlen (text);
477
478 if (start < (int) length)
479 {
480 size_t pos;
481
482 for (pos = start; pos < length && width > 0 && remain > 1;
483 pos++, width--, actual++, remain--)
484 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
485 }
486
487 for (; width > 0 && remain > 1; actual++, remain--, width--)
488 actual[0] = ' ';
489
490 actual[0] = '\0';
491 return result;
492 }
493
494 /* --------------------------------------------------------------------------------------------- */
495
496 static const char *
str_8bit_trunc(const char * text,int width)497 str_8bit_trunc (const char *text, int width)
498 {
499 static char result[MC_MAXPATHLEN];
500 int remain;
501 char *actual;
502 size_t pos = 0;
503 size_t length;
504
505 actual = result;
506 remain = sizeof (result);
507 length = strlen (text);
508
509 if ((int) length > width)
510 {
511 for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
512 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
513
514 if (remain <= 1)
515 goto finally;
516 actual[0] = '~';
517 actual++;
518 remain--;
519
520 pos += length - width + 1;
521 for (; pos < length && remain > 1; pos++, actual++, remain--)
522 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
523 }
524 else
525 {
526 for (; pos < length && remain > 1; pos++, actual++, remain--)
527 actual[0] = char_isprint (text[pos]) ? text[pos] : '.';
528 }
529
530 finally:
531 actual[0] = '\0';
532 return result;
533 }
534
535 /* --------------------------------------------------------------------------------------------- */
536
537 static int
str_8bit_offset_to_pos(const char * text,size_t length)538 str_8bit_offset_to_pos (const char *text, size_t length)
539 {
540 (void) text;
541 return (int) length;
542 }
543
544 /* --------------------------------------------------------------------------------------------- */
545
546 static int
str_8bit_column_to_pos(const char * text,size_t pos)547 str_8bit_column_to_pos (const char *text, size_t pos)
548 {
549 (void) text;
550 return (int) pos;
551 }
552
553 /* --------------------------------------------------------------------------------------------- */
554
555 static char *
str_8bit_create_search_needle(const char * needle,gboolean case_sen)556 str_8bit_create_search_needle (const char *needle, gboolean case_sen)
557 {
558 (void) case_sen;
559 return (char *) needle;
560 }
561
562 /* --------------------------------------------------------------------------------------------- */
563
564 static void
str_8bit_release_search_needle(char * needle,gboolean case_sen)565 str_8bit_release_search_needle (char *needle, gboolean case_sen)
566 {
567 (void) case_sen;
568 (void) needle;
569 }
570
571 /* --------------------------------------------------------------------------------------------- */
572
573 static char *
str_8bit_strdown(const char * str)574 str_8bit_strdown (const char *str)
575 {
576 char *rets, *p;
577
578 if (str == NULL)
579 return NULL;
580
581 rets = g_strdup (str);
582
583 for (p = rets; *p != '\0'; p++)
584 *p = char_tolower (*p);
585
586 return rets;
587 }
588
589 /* --------------------------------------------------------------------------------------------- */
590
591 static const char *
str_8bit_search_first(const char * text,const char * search,gboolean case_sen)592 str_8bit_search_first (const char *text, const char *search, gboolean case_sen)
593 {
594 char *fold_text;
595 char *fold_search;
596 const char *match;
597
598 fold_text = case_sen ? (char *) text : str_8bit_strdown (text);
599 fold_search = case_sen ? (char *) search : str_8bit_strdown (search);
600
601 match = g_strstr_len (fold_text, -1, fold_search);
602 if (match != NULL)
603 {
604 size_t offset;
605
606 offset = match - fold_text;
607 match = text + offset;
608 }
609
610 if (!case_sen)
611 {
612 g_free (fold_text);
613 g_free (fold_search);
614 }
615
616 return match;
617 }
618
619 /* --------------------------------------------------------------------------------------------- */
620
621 static const char *
str_8bit_search_last(const char * text,const char * search,gboolean case_sen)622 str_8bit_search_last (const char *text, const char *search, gboolean case_sen)
623 {
624 char *fold_text;
625 char *fold_search;
626 const char *match;
627
628 fold_text = case_sen ? (char *) text : str_8bit_strdown (text);
629 fold_search = case_sen ? (char *) search : str_8bit_strdown (search);
630
631 match = g_strrstr_len (fold_text, -1, fold_search);
632 if (match != NULL)
633 {
634 size_t offset;
635
636 offset = match - fold_text;
637 match = text + offset;
638 }
639
640 if (!case_sen)
641 {
642 g_free (fold_text);
643 g_free (fold_search);
644 }
645
646 return match;
647 }
648
649 /* --------------------------------------------------------------------------------------------- */
650
651 static int
str_8bit_compare(const char * t1,const char * t2)652 str_8bit_compare (const char *t1, const char *t2)
653 {
654 return strcmp (t1, t2);
655 }
656
657 /* --------------------------------------------------------------------------------------------- */
658
659 static int
str_8bit_ncompare(const char * t1,const char * t2)660 str_8bit_ncompare (const char *t1, const char *t2)
661 {
662 return strncmp (t1, t2, MIN (strlen (t1), strlen (t2)));
663 }
664
665 /* --------------------------------------------------------------------------------------------- */
666
667 static int
str_8bit_casecmp(const char * s1,const char * s2)668 str_8bit_casecmp (const char *s1, const char *s2)
669 {
670 /* code from GLib */
671
672 #ifdef HAVE_STRCASECMP
673 g_return_val_if_fail (s1 != NULL, 0);
674 g_return_val_if_fail (s2 != NULL, 0);
675
676 return strcasecmp (s1, s2);
677 #else
678 gint c1, c2;
679
680 g_return_val_if_fail (s1 != NULL, 0);
681 g_return_val_if_fail (s2 != NULL, 0);
682
683 while (*s1 != '\0' && *s2 != '\0')
684 {
685 /* According to A. Cox, some platforms have islower's that
686 * don't work right on non-uppercase
687 */
688 c1 = isupper ((guchar) * s1) ? tolower ((guchar) * s1) : *s1;
689 c2 = isupper ((guchar) * s2) ? tolower ((guchar) * s2) : *s2;
690 if (c1 != c2)
691 return (c1 - c2);
692 s1++;
693 s2++;
694 }
695
696 return (((gint) (guchar) * s1) - ((gint) (guchar) * s2));
697 #endif
698 }
699
700 /* --------------------------------------------------------------------------------------------- */
701
702 static int
str_8bit_ncasecmp(const char * s1,const char * s2)703 str_8bit_ncasecmp (const char *s1, const char *s2)
704 {
705 size_t n;
706
707 g_return_val_if_fail (s1 != NULL, 0);
708 g_return_val_if_fail (s2 != NULL, 0);
709
710 n = MIN (strlen (s1), strlen (s2));
711
712 /* code from GLib */
713
714 #ifdef HAVE_STRNCASECMP
715 return strncasecmp (s1, s2, n);
716 #else
717 gint c1, c2;
718
719 while (n != 0 && *s1 != '\0' && *s2 != '\0')
720 {
721 n -= 1;
722 /* According to A. Cox, some platforms have islower's that
723 * don't work right on non-uppercase
724 */
725 c1 = isupper ((guchar) * s1) ? tolower ((guchar) * s1) : *s1;
726 c2 = isupper ((guchar) * s2) ? tolower ((guchar) * s2) : *s2;
727 if (c1 != c2)
728 return (c1 - c2);
729 s1++;
730 s2++;
731 }
732
733 if (n == 0)
734 return 0;
735
736 return (((gint) (guchar) * s1) - ((gint) (guchar) * s2));
737
738 #endif
739 }
740
741 /* --------------------------------------------------------------------------------------------- */
742
743 static int
str_8bit_prefix(const char * text,const char * prefix)744 str_8bit_prefix (const char *text, const char *prefix)
745 {
746 int result;
747
748 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
749 && text[result] == prefix[result]; result++);
750
751 return result;
752 }
753
754 /* --------------------------------------------------------------------------------------------- */
755
756 static int
str_8bit_caseprefix(const char * text,const char * prefix)757 str_8bit_caseprefix (const char *text, const char *prefix)
758 {
759 int result;
760
761 for (result = 0; text[result] != '\0' && prefix[result] != '\0'
762 && char_toupper (text[result]) == char_toupper (prefix[result]); result++);
763
764 return result;
765 }
766
767 /* --------------------------------------------------------------------------------------------- */
768
769 static void
str_8bit_fix_string(char * text)770 str_8bit_fix_string (char *text)
771 {
772 (void) text;
773 }
774
775 /* --------------------------------------------------------------------------------------------- */
776
777 static char *
str_8bit_create_key(const char * text,gboolean case_sen)778 str_8bit_create_key (const char *text, gboolean case_sen)
779 {
780 return case_sen ? (char *) text : str_8bit_strdown (text);
781 }
782
783 /* --------------------------------------------------------------------------------------------- */
784
785 static int
str_8bit_key_collate(const char * t1,const char * t2,gboolean case_sen)786 str_8bit_key_collate (const char *t1, const char *t2, gboolean case_sen)
787 {
788 return case_sen ? strcmp (t1, t2) : strcoll (t1, t2);
789 }
790
791 /* --------------------------------------------------------------------------------------------- */
792
793 static void
str_8bit_release_key(char * key,gboolean case_sen)794 str_8bit_release_key (char *key, gboolean case_sen)
795 {
796 if (!case_sen)
797 g_free (key);
798 }
799
800 /* --------------------------------------------------------------------------------------------- */
801 /*** public functions ****************************************************************************/
802 /* --------------------------------------------------------------------------------------------- */
803
804 struct str_class
str_8bit_init(void)805 str_8bit_init (void)
806 {
807 struct str_class result;
808
809 result.conv_gerror_message = str_8bit_conv_gerror_message;
810 result.vfs_convert_to = str_8bit_vfs_convert_to;
811 result.insert_replace_char = str_8bit_insert_replace_char;
812 result.is_valid_string = str_8bit_is_valid_string;
813 result.is_valid_char = str_8bit_is_valid_char;
814 result.cnext_char = str_8bit_cnext_char;
815 result.cprev_char = str_8bit_cprev_char;
816 result.cnext_char_safe = str_8bit_cnext_char;
817 result.cprev_char_safe = str_8bit_cprev_char;
818 result.cnext_noncomb_char = str_8bit_cnext_noncomb_char;
819 result.cprev_noncomb_char = str_8bit_cprev_noncomb_char;
820 result.char_isspace = str_8bit_isspace;
821 result.char_ispunct = str_8bit_ispunct;
822 result.char_isalnum = str_8bit_isalnum;
823 result.char_isdigit = str_8bit_isdigit;
824 result.char_isprint = str_8bit_isprint;
825 result.char_iscombiningmark = str_8bit_iscombiningmark;
826 result.char_toupper = str_8bit_toupper;
827 result.char_tolower = str_8bit_tolower;
828 result.length = str_8bit_length;
829 result.length2 = str_8bit_length2;
830 result.length_noncomb = str_8bit_length;
831 result.fix_string = str_8bit_fix_string;
832 result.term_form = str_8bit_term_form;
833 result.fit_to_term = str_8bit_fit_to_term;
834 result.term_trim = str_8bit_term_trim;
835 result.term_width2 = str_8bit_term_width2;
836 result.term_width1 = str_8bit_term_width1;
837 result.term_char_width = str_8bit_term_char_width;
838 result.term_substring = str_8bit_term_substring;
839 result.trunc = str_8bit_trunc;
840 result.offset_to_pos = str_8bit_offset_to_pos;
841 result.column_to_pos = str_8bit_column_to_pos;
842 result.create_search_needle = str_8bit_create_search_needle;
843 result.release_search_needle = str_8bit_release_search_needle;
844 result.search_first = str_8bit_search_first;
845 result.search_last = str_8bit_search_last;
846 result.compare = str_8bit_compare;
847 result.ncompare = str_8bit_ncompare;
848 result.casecmp = str_8bit_casecmp;
849 result.ncasecmp = str_8bit_ncasecmp;
850 result.prefix = str_8bit_prefix;
851 result.caseprefix = str_8bit_caseprefix;
852 result.create_key = str_8bit_create_key;
853 result.create_key_for_filename = str_8bit_create_key;
854 result.key_collate = str_8bit_key_collate;
855 result.release_key = str_8bit_release_key;
856
857 return result;
858 }
859
860 /* --------------------------------------------------------------------------------------------- */
861