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