Convert uses of XKeycodeToKeysym (deprecated) to XkbKeycodeToKeysym
[oweals/cde.git] / cde / lib / DtHelp / StringFuncs.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: StringFuncs.c /main/15 1998/03/19 09:49:44 mgreess $ */
24 /************************************<+>*************************************
25  ****************************************************************************
26  **
27  **   File:     StringFuncs.c
28  **
29  **   Project:  Cde DtHelp
30  **
31  **   Description: Semi private string functions - can be platform dependent.
32  **
33  **
34  **  (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 Hewlett-Packard Company
35  **
36  **  (c) Copyright 1993, 1994 Hewlett-Packard Company
37  **  (c) Copyright 1993, 1994 International Business Machines Corp.
38  **  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
39  **  (c) Copyright 1993, 1994 Novell, Inc.
40  **
41  **
42  **
43  ****************************************************************************
44  ************************************<+>*************************************/
45 /*
46  * system includes
47  */
48 #include <stdlib.h>
49 #include <string.h>
50 #include <limits.h>
51 #include <errno.h>
52 #include <locale.h>  /* getlocale(), LOCALE_STATUS, LC_xxx */
53
54 #if defined(_AIX) || defined(CSRG_BASED) || defined(__linux__)
55 #include <ctype.h>
56 #endif
57
58 #include "CvStringI.h"        /* for string functions used by Canvas Engine */
59 #include "StringFuncsI.h"     /* for _CEStrcollProc */
60
61 /* JET: This was if !defined(linux), which is wrong.  We should use the
62  * real deal on linux too */
63
64 #include <iconv.h>
65
66 #if 0
67 # define iconv_t                int
68 # define iconv_open(a, b)       ((iconv_t) -1)
69 # define iconv(a, b, c, d, e)   ((size_t) 0)
70 # define iconv_close(a)         (0)
71 #endif
72
73 #ifdef ICONV_INBUF_CONST
74 # define ICONV_INBUF_TYPE       const char **
75 #else
76 # define ICONV_INBUF_TYPE       char **
77 #endif
78
79 /**** Types ****/
80 /* Private structure of the IconvContext.  Public
81    structure doesn't reveal implementation. */
82 typedef struct _DtHelpCeIconvContextRec
83 {
84     iconv_t         cd;
85     int             tableSize;
86     unsigned char * table;        /* translation table */
87     char *          fromCodeset;
88     char *          toCodeset;
89 } _DtHelpCeIconvContextRec;
90
91
92 #ifndef True
93 #define True    1
94 #endif
95 #ifndef TRUE
96 #define TRUE    1
97 #endif
98 #ifndef False
99 #define False   0
100 #endif
101 #ifndef FALSE
102 #define FALSE   0
103 #endif
104
105 /******************************************************************************
106  *
107  * Private variables and defines.
108  *
109  *****************************************************************************/
110 #define EOS '\0'
111
112 /******************************************************************************
113  *
114  * Semi Public Functions
115  *
116  *****************************************************************************/
117 /******************************************************************************
118  * Function: _DtHelpCeStrcspn (const char *s1, const char *s2, max_len, &ret_len)
119  *
120  *      Returns in 'ret_len' the length of the initial segment of string
121  *      s1 which consists entirely of characters not found in string s2.
122  *
123  * Returns:
124  *      -1  If found an invalid character.
125  *       0  If found a character in string s2
126  *       1  If found the null byte character.
127  *****************************************************************************/
128 int
129 _DtHelpCeStrcspn (
130     const char    *s1,
131     const char    *s2,
132     int            max_len,
133     int           *ret_len )
134 {
135     int    len;
136     int    len2;
137     const char  *p1;
138     const char  *p2;
139
140     if (!s1)
141       {
142         *ret_len = 0;
143         return 0;
144       }
145
146     if (*s1 == '\0')
147       {
148         *ret_len = 0;
149         return 1;
150       }
151
152     if (!s2 || *s2 == '\0')
153       {
154         *ret_len = strlen (s1);
155         return 1;
156       }
157
158     if (max_len == 1)
159       {
160         /*
161          * no need to go through any hassle, just use the 3C function
162          */
163         *ret_len = strcspn (s1, s2);
164         if (s1[*ret_len] == '\0')
165             return 1;
166         return 0;
167       }
168
169     p1 = s1;
170     while (*p1 != '\0')
171       {
172         len = mblen (p1, max_len);
173         if (len == -1)
174           {
175             /*
176              * we found an invalid character
177              * return the length found so far and the flag.
178              */
179             *ret_len = p1 - s1;
180             return -1;
181           }
182
183         p2 = s2;
184         while (*p2 != '\0')
185           {
186             len2 = mblen (p2, max_len);
187             if (len2 == -1)
188                 len2 = 1;
189
190             if (len2 == len && strncmp (p1, p2, len) == 0)
191               {
192                 *ret_len = p1 - s1;
193                 return 0;
194               }
195             p2 += len2;
196           }
197         p1 += len;
198       }
199
200     *ret_len = p1 - s1;
201     return 1;
202 }
203
204 /******************************************************************************
205  * Function: _DtHelpCeStrspn (const char *s1, const char *s2, max_len, &ret_len)
206  *
207  *      Returns in 'ret_len' the length of the initial segment of string
208  *      s1 which consists entirely of characters found in string s2.
209  *
210  * Returns:
211  *      -1  If found an invalid character.
212  *       0  If found a character not in string s2
213  *       1  If found the null byte character.
214  *****************************************************************************/
215 int
216 _DtHelpCeStrspn (
217     char    *s1,
218     char    *s2,
219     int      max_len,
220     int     *ret_len )
221 {
222     int    len;
223     int    len2;
224     char  *p1;
225     char  *p2;
226     char   found;
227
228     if (!s1 || !s2 || *s2 == '\0')
229       {
230         *ret_len = 0;
231         return 0;
232       }
233     if (*s1 == '\0')
234       {
235         *ret_len = 0;
236         return 1;
237       }
238
239     if (max_len == 1)
240       {
241         /*
242          * no need to go through any hassle, just use the 3C function
243          */
244         *ret_len = strspn (s1, s2);
245         if (s1[*ret_len] == '\0')
246             return 1;
247         return 0;
248       }
249
250     p1 = s1;
251     found = True;
252     while (*p1 != '\0' && found)
253       {
254         len = mblen (p1, max_len);
255         if (len == -1)
256           {
257             /*
258              * we found an invalid character
259              * return the length found so far and the flag.
260              */
261             *ret_len = p1 - s1;
262             return -1;
263           }
264
265         p2 = s2;
266         found = False;
267         while (*p2 != '\0' && !found)
268           {
269             len2 = mblen (p2, max_len);
270             if (len2 == -1)
271                 len2 = 1;
272
273             if (len2 == len && strncmp (p1, p2, len) == 0)
274                 found = True;
275             p2 += len2;
276           }
277
278         if (found)
279             p1 += len;
280       }
281
282     *ret_len = p1 - s1;
283
284     if (found)
285         return 1;
286
287     return 0;
288 }
289
290 /******************************************************************************
291  * Function: _DtHelpCeStrchr (char *s1, char *value, max_len, ret_ptr)
292  *
293  *      Returns in 'ret_ptr' the address of the first occurence of 'value'
294  *      in string s1.
295  *
296  * Returns:
297  *      -1  If found an invalid character.
298  *       0  If found value in string s2
299  *       1  If found the null byte character without finding 'value'.
300  *          'ret_ptr' will also be null in this case.
301  *****************************************************************************/
302 int
303 _DtHelpCeStrchr (
304     const char    *s1,
305     const char    *value,
306     int            max_len,
307     char         **ret_ptr )
308 {
309     int      len;
310     int      valLen;
311     const char *p1;
312
313     *ret_ptr = NULL;
314
315     if (s1 == NULL || *s1 == '\0')
316         return 1;
317
318     if (max_len == 1)
319       {
320         *ret_ptr = strchr (s1, ((int)*value));
321         if (*ret_ptr)
322             return 0;
323         return 1;
324       }
325
326     p1 = s1;
327     valLen = mblen(value, max_len);
328     if (valLen < 1)
329         return -1;
330
331     while (*p1 != '\0')
332       {
333         len = mblen (p1, max_len);
334         if (len == -1)
335             return -1;
336         if (len == valLen && strncmp(p1, value, len) == 0)
337           {
338             *ret_ptr = (char *)p1;
339             return 0;
340           }
341         p1 += len;
342       }
343
344     return 1;
345 }
346
347 /******************************************************************************
348  * Function: _DtHelpCeStrrchr (char *s1, char *value, max_len, ret_ptr)
349  *
350  *      Returns in 'ret_ptr' the address of the last occurence of 'value'
351  *      in string s1.
352  *
353  * Returns:
354  *      -1  If found an invalid character.
355  *       0  If found value in string s2
356  *       1  If found the null byte character without finding 'value'.
357  *          'ret_ptr' will also be null in this case.
358  *****************************************************************************/
359 int
360 _DtHelpCeStrrchr (
361     const char    *s1,
362     const char    *value,
363     int            max_len,
364     char         **ret_ptr )
365 {
366     int      len;
367     int      valLen;
368     const char *p1;
369
370     *ret_ptr = NULL;
371
372     if (s1 == NULL || *s1 == '\0')
373         return 1;
374
375     if (max_len == 1)
376       {
377         *ret_ptr = strrchr (s1, ((int)*value));
378         if (*ret_ptr != NULL)
379             return 0;
380         return 1;
381       }
382
383     p1 = s1;
384     valLen = mblen(value, max_len);
385     if (valLen < 1)
386         return -1;
387
388     while (*p1 != '\0')
389       {
390         len = mblen (p1, max_len);
391         if (len == -1)
392             return -1;
393         if (len == valLen && strncmp(p1, value, len) == 0)
394             *ret_ptr = (char *)p1;
395
396         p1 += len;
397       }
398
399     if (*ret_ptr != NULL)
400         return 0;
401
402     return 1;
403 }
404
405 /******************************************************************************
406  * Function: _DtHelpCeCountChars (char *s1, max_len, ret_len)
407  *
408  *      Returns in 'ret_len' the number of characters (not bytes)
409  *      in string s1.
410  *
411  * Returns:
412  *      -1  If found an invalid character. 'ret_len' contains the
413  *          number of 'good' characters found.
414  *       0  If successful.
415  *****************************************************************************/
416 int
417 _DtHelpCeCountChars (
418     char    *s1,
419     int      max_len,
420     int     *ret_len )
421 {
422     int    len;
423
424     *ret_len = 0;
425
426     if (s1)
427       {
428         if (max_len == 1)
429             *ret_len = strlen (s1);
430         else
431           {
432             while (*s1)
433               {
434                 len = mblen (s1, max_len);
435                 if (len == -1)
436                     return -1;
437                 *ret_len = *ret_len + 1;
438                 s1 += len;
439               }
440           }
441       }
442     return 0;
443 }
444
445 /*****************************************************************************
446  * Function: _DtHelpCeUpperCase
447  *
448  * Parameters:  string          Specifies the string to change into
449  *                              upper case.
450  *
451  * Return Value: Nothing
452  *
453  * Purpose:     To change all lower case characters into upper case.
454  *
455  *****************************************************************************/
456 void
457 _DtHelpCeUpperCase ( char *string )
458 {
459     int   len;
460
461     if (string)
462       {
463         while (*string != '\0')
464           {
465             len = mblen (string, MB_CUR_MAX);
466             if (len == 1)
467               {
468                 *string = (unsigned char) toupper (*(unsigned char *)string);
469                 string++;
470               }
471             else if (len > 0)
472                 string += len;
473             else
474                 return;
475           }
476       }
477 }
478
479 /************************************************************************
480  * Function: _DtHelpCeStrHashToKey
481  *
482  * Parameters:  C-format string to hash
483  *
484  * Purpose:
485  *   Does a very simple hash operation on the string and returns the value
486  *
487  * Returns:  hash value
488  *
489  ************************************************************************/
490 int _DtHelpCeStrHashToKey(
491         const char * str)
492 {
493     char c;
494     const char * tstr;
495     int key = 0;
496
497     if (!str) return 0;                  /* RETURN */
498
499     for (tstr = str; (c = *tstr++); )
500         key = (key << 1) + c;
501
502     return key;
503 }
504
505
506
507 /******************************************************************************
508  * Function:    _DtHelpCeGetStrcollProc
509  *
510  * Parameters:  none
511  *
512  * Returns:     Ptr to the proper collation function to use
513  *              If the codeset of the locale is "C", then it is 
514  *              strcasecmp(). If it's not, then it is strcoll().
515  *
516  * Purpose:     When the codeset of the locale "C", strcoll() 
517  *              performs collation identical to strcmp(), which is 
518  *              strictly bitwise.
519  *
520  *              To get case-insensitive collation, you need to use
521  *              strcasecmp() instead.  If codeset != "C", then 
522  *              strcoll() collates according to the language
523  *              setting.
524  * 
525  * Warning:     This code is not multi-thread safe.  The multi-thread
526  *              safe setlocale must be used instead to make it so.
527  *
528  *****************************************************************************/
529    _CEStrcollProc _DtHelpCeGetStrcollProc(void)
530 {
531    int Clang = 0;
532 #if defined(__hpux)
533    struct locale_data * li;
534 #else
535    char * locale;
536 #endif
537
538    extern int strcoll(const char *,const char *);
539 #if defined(_AIX)
540    extern int _DtHelpCeStrCaseCmp(const char *,const char *);
541 #else
542    extern int strcasecmp(const char *,const char *);
543 #endif
544
545 #define C_LANG  "C"
546
547    /* if locale is C, use the explicit case insensitive compare */
548 #if defined(__hpux)
549    li = getlocale(LOCALE_STATUS);
550    if ( NULL == li->LC_COLLATE_D || strcmp(C_LANG,li->LC_COLLATE_D) == 0 )
551      Clang = 1;
552 #else
553    locale = setlocale(LC_COLLATE,NULL); /* put locale in buf */
554    if (strcmp(locale,C_LANG) == 0)
555      Clang = 1;
556 #endif
557
558    if (Clang)
559 #if defined(_AIX)
560      return _DtHelpCeStrCaseCmp;
561 #else
562      return strcasecmp; 
563 #endif
564    return strcoll;
565 }
566
567 /*****************************************************************************
568  * Function:        String _DtHelpCeStripSpaces (string)
569  *
570  *
571  * Parameters:    String to process
572  *
573  * Return Value:  Processed string
574  *
575  * Purpose:       Strip all leading and trailing spaces.
576  *                Processing is in place
577  *
578  *****************************************************************************/
579 char * _DtHelpCeStripSpaces (
580     char * string)
581 {
582    int i;
583    int multiLen = MB_CUR_MAX;
584    char * space;
585
586    if (string == NULL)
587       return (string);
588
589    /* Strip off leading spaces first */
590    i = 0;
591    while ((multiLen == 1 || (mblen(string + i, MB_LEN_MAX) == 1)) &&
592           isspace((unsigned char) string[i]))
593    {
594       i++;
595    }
596    /* Copy over the leading spaces */
597    strcpy(string, string + i);
598
599    /* Drop out, if the string is now empty */
600    if ((i = strlen(string) - 1) < 0)
601       return(string);
602
603    /* Strip off trailing spaces */
604    if (multiLen == 1)
605    {
606       /* No multibyte; simply work back through the string */
607       while ((i >= 0) && (isspace((unsigned char) string[i])))
608          i--;
609       string[i + 1] = '\0';
610    }
611    else
612    {
613       /* Work forward, looking for a trailing space of spaces */
614       int len;
615
616       i = 0;
617       space = NULL;
618
619       while (string[i])
620       {
621          if (    ((len =mblen(string + i, MB_LEN_MAX)) == 1) 
622               && isspace((unsigned char) string[i]))
623          {
624             /* Found a space */
625             if (space == NULL)
626                space = string + i;
627          }
628          else if (space)
629             space = NULL;
630
631          /* if there is an invalid character, treat as a valid one-byte */
632          if (len == -1)
633            len = 1;
634          i += len;
635
636       }
637
638       if (space)
639          *space = '\0';
640    }
641
642    return (string);
643 }
644
645
646 /*****************************************************************************
647  * Function:        void _DtHelpCeCompressSpace (string)
648  *
649  * Parameters:      string to process
650  *
651  * Return Value:    processed string
652  *
653  * Purpose:           This function strips all leading and trailing spaces
654  *                    from the string; it also compresses any intervening
655  *                    spaces into a single space.  This is useful when
656  *                    comparing name strings.  For instance, the string:
657  *                    "    First    Middle    Last   "
658  *
659  *                    would compress to:
660  *
661  *                    "First Middle Last"
662  *
663  *                     Processing is in place.
664  *
665  *****************************************************************************/
666 void _DtHelpCeCompressSpace (
667     char * string)
668
669 {
670    char * ptr;
671
672    /* Strip leading and trailing spaces */
673    _DtHelpCeStripSpaces(string);
674
675    /* Compress intervening spaces */
676    _DtHelpCeStrchr(string, " ", 1, &ptr);
677    while (ptr)
678    {
679       /* Skip over the one space we plan to keep */
680       ptr++;
681       _DtHelpCeStripSpaces(ptr);
682       _DtHelpCeStrchr(ptr, " ", 1, &ptr);
683    }
684 }
685
686 /*****************************************************************************
687  * Function:        void _DtHelpCeIconvStr1Step (string)
688  *
689  * Parameters:      
690  *    fromCode;      codeset name
691  *    fromStr;       string to convert
692  *    toCode;        codeset name
693  *    ret_toStr;     converted str; this string is malloc'd by this routine
694  *                   and the CALLER MUST FREE it when no longer needed.
695  *    dflt1;         1-byte default char
696  *    dflt2;         2-byte default char
697  *
698  * Return Value:    
699  *                  0: ok
700  *                 -1: missing (NULL) argument
701  *                 -2: no translation available from fromCode to toCode
702  *                 -3: couldn't allocate memory 
703  *                 -4: couldn't start conversion 
704  *                 -5: incomplete multibyte char
705  *                 -6: invalid char found
706  *
707  * Purpose:
708  *                  Converts string from fromCode to toCode using iconv(3)
709  *                  It expects the codeset strings to be iconv(3) compatible.
710  *                  Generally, compatible strings can be retrieved using
711  *                  the _DtHelpCeXlateStdToOpLocale() call.
712  *
713  * Comments:
714  *                  iconv(3) is standardized in XPG4, which is just starting
715  *                  to be supported.  Below are several different implementations 
716  *                  of _DtHelpCeIconvStr, each using what is available on different 
717  *                  platforms.  If no code is #ifdef'd, the XPG4 code defaults.
718  *****************************************************************************/
719
720 int _DtHelpCeIconvStr1Step(
721       const char * fromCode,   /* codeset name */
722       const char * fromStr,    /* string to convert */
723       const char * toCode,     /* codeset name */
724       char * *     ret_toStr,  /* converted str */
725       int          dflt1,      /* 1-byte default char */
726       int          dflt2)      /* 2-byte default char */
727
728 {
729    _DtHelpCeIconvContextRec * iconvContext;
730    int ret;
731
732    ret = _DtHelpCeIconvOpen(&iconvContext,fromCode,toCode,dflt1,dflt2);
733    if (0 == ret) 
734       ret = _DtHelpCeIconvStr(iconvContext,fromStr, ret_toStr,NULL,NULL,0);
735    _DtHelpCeIconvClose(&iconvContext);
736    return ret;
737 }
738
739
740 /*****************************************************************************
741  * Function:        void _DtHelpCeIconvOpen (string)
742  *
743  * Parameters:      
744  *    iconvContext   context 
745  *    fromStr;       string to convert
746  *    ret_toStr;     converted str; this string is malloc'd by this routine
747  *                   and the CALLER MUST FREE it when no longer needed.
748  *    dflt1;         1-byte default char
749  *    dflt2;         2-byte default char
750  *
751  * Return Value:    
752  *                  0: ok
753  *                 -1: missing (NULL) argument
754  *                 -2: no translation available from fromCode to toCode
755  *                 -3: couldn't allocate memory 
756  *                 -4: couldn't start conversion 
757  *                 -5: incomplete multibyte char
758  *                 -6: invalid char found
759  *
760  * Purpose:
761  *              Opens an iconv table/algorithm to convert string from 
762  *              fromCode to toCode using iconv(3)
763  *              It expects the codeset strings to be iconv(3) compatible.
764  *              Generally, compatible strings can be retrieved using
765  *              the _DtHelpCeXlateStdToOpLocale() call.
766  *
767  * Comments:
768  *              iconv(3) is standardized in XPG4, which is just starting
769  *              to be supported.  Below are several different implementations 
770  *              of _DtHelpCeIconvStr, each using what is available on different 
771  *              platforms.  If no code is #ifdef'd, the XPG4 code defaults.
772  *****************************************************************************/
773 int _DtHelpCeIconvOpen(
774       _DtHelpCeIconvContext * ret_iconvContext,  /* iconv */
775       const char * fromCode,   /* codeset name */
776       const char * toCode,     /* codeset name */
777       int          dflt1,      /* 1-byte default char */
778       int          dflt2)      /* 2-byte default char */
779
780 {  /* XPG4-compliant code (args dflt1 & dflt2 are ignored in this code) */
781    int              err;          /* error code of function */
782    _DtHelpCeIconvContextRec * ic;
783
784 #define BAD (-1)
785 #define MEM_INC 20
786
787    err = 0;  /* ok */
788
789    /* check args */
790    if (!ret_iconvContext || !fromCode || !toCode )
791       return -1;                         /* RETURN error */
792
793    /* init state */
794    ic = *ret_iconvContext = calloc(1,sizeof(_DtHelpCeIconvContextRec));
795    if (NULL == ic) return -3;   /* RETURN error */
796
797    if ( strcmp(fromCode,toCode) == 0 )
798    {
799       ic->cd = (iconv_t) BAD;           /* BAD means use strdup() */
800       goto success;
801    }
802
803    ic->cd = iconv_open(toCode,fromCode);
804    if ( ic->cd == (iconv_t) BAD ) 
805    {
806       err = -4;                         /* error */
807       goto success;
808    }
809
810 success:
811    ic->fromCodeset = strdup(fromCode);
812    ic->toCodeset = strdup(toCode);
813    return err;                             /* RETURN status */
814 }
815
816 /*****************************************************************************
817  * Function:        void _DtHelpCeIconvStr (string)
818  *
819  * Parameters:      
820  *    iconvContext   context for the conversion
821  *    fromStr;       string to convert
822  *    ret_toStr;     converted str; this string is malloc'd by this routine
823  *                   and the CALLER MUST FREE it when no longer needed.
824  *    toStrBuf;      for efficiency, can pass in a buf 
825  *    toStrBufLen;   length of buf
826  *
827  * Return Value:    
828  *                  0: ok
829  *                 -1: missing (NULL) argument
830  *                 -2: no translation available from fromCode to toCode
831  *                 -3: couldn't allocate memory 
832  *                 -4: couldn't start conversion 
833  *                 -5: incomplete multibyte char
834  *                 -6: invalid char found
835  *
836  * Purpose:
837  *              Converts string from fromCode to toCode using iconv(3)
838  *              If toStrBuf is NULL, memory for the converted string
839  *                will be malloced as needed.
840  *              If toStrBuf is not NULL, the conversion will use up 
841  *                to toStrBufLen bytes of the buffer and then realloc
842  *                more memory if needed.
843  *              If toStrBuf is not NULL, the size of the buf is
844  *                returned in ret_toStrLen; otherwise, the value is
845  *                not set.
846  *              ret_toStr receives the pointer to the buf, which may
847  *                be different from toStrBuf if memory was allocated
848  *                or NULL if an error occurred.  If toStrBuf is
849  *                not NULL and memory must be allocated, a realloc()
850  *                call is used, possibly invalidating the toStrBuf ptr.
851  *              ret_toStrLen receives the length of the buffer if
852  *                toStrBuf is not NULL.  If it is NULL, the length
853  *                is not returned.
854  * Comments:
855  *              iconv(3) is standardized in XPG4, which is just starting
856  *              to be supported.  Below are several different implementations 
857  *              of _DtHelpCeIconvStr, each using what is available on different 
858  *              platforms.  If no code is #ifdef'd, the XPG4 code defaults.
859  *****************************************************************************/
860 int _DtHelpCeIconvStr(
861       _DtHelpCeIconvContext iconvContext, /* iconv */
862       const char * fromStr,      /* string to convert */
863       char * *     ret_toStr,    /* converted str */
864       size_t *     ret_toStrLen, /* converted str */
865       char *       toStrBuf,     /* for efficiency, can pass in a buf */
866       size_t       toStrBufLen)  /* length of buf */
867 {  /* XPG4-compliant code (args dflt1 & dflt2 are ignored in this code) */
868    char *           toStr;        /* ptr to tostr memory */
869    int              toStrSize;    /* size of mallocd string */
870    size_t           inBytesLeft;  /* bytes left to use from input buf */
871    const char *     inChar;       /* ptr into fromstr */
872    char *           outChar;      /* ptr into tostr  */
873    size_t           outBytesLeft; /* bytes left in the output str */
874    int              err;          /* error code of function */
875
876 #define BAD (-1)
877 #define MEM_INC 20
878
879    /* init ret values; allows function to be called nicely in a loop.  */
880    if (ret_toStr) *ret_toStr = toStrBuf;
881    if (ret_toStrLen) *ret_toStrLen = toStrBufLen;
882
883    /* check args */
884    if (   !iconvContext || !fromStr || !ret_toStr
885        || (!ret_toStrLen && toStrBuf))
886       return -1;                         /* RETURN error */
887
888    /* just do a straight copy if codesets the same or invalid context */
889    if ( iconvContext->cd == (iconv_t) BAD ) 
890    {
891       if (NULL == toStrBuf)
892       {
893          *ret_toStr = strdup(fromStr);
894       }
895       else  /* reuse the buffer */
896       {
897          int len = strlen(fromStr) + 1;
898          if (len > toStrBufLen)
899             *ret_toStr = realloc(toStrBuf,len);
900          else 
901          {
902             *ret_toStr = toStrBuf;
903             len = toStrBufLen;
904          }
905          /* set return values */
906          strcpy(*ret_toStr,fromStr);
907          *ret_toStrLen = len;
908       }
909       return (NULL != *ret_toStr ? 0 : -3);    /* RETURN result */
910    }
911
912
913    /* init ptrs */
914    toStr = toStrBuf;
915    toStrSize = (NULL == toStrBuf ? 0 : toStrBufLen);
916    inChar = fromStr;
917    inBytesLeft = strlen(fromStr);
918    outChar = toStr;
919    outBytesLeft = toStrSize;
920
921    /* translate the string */
922    err = -3;
923    while ( inBytesLeft > 0 )
924    {
925       /* convert a character */
926       if(iconv(iconvContext->cd, (ICONV_INBUF_TYPE)&inChar,
927                &inBytesLeft,&outChar,&outBytesLeft) == -1)
928       {
929          switch(errno)
930          {
931          case 0: /* no error */
932             continue;
933          case EINVAL: /* inChar pts to incomplete multibyte char */
934             inBytesLeft = 0;       /* end the translation */
935             err = -5;
936             break;
937          case EILSEQ: /* invalid char at inChar */
938             inBytesLeft = 0;       /* end the translation */
939             err = -6;
940             break;
941          case E2BIG: /* no room in toStr */
942             /* provide enough mem in the toStr */
943             if (outBytesLeft < sizeof(wchar_t))
944             {
945                size_t offset = outChar - (char *) toStr;
946    
947                outBytesLeft += MEM_INC;
948                toStrSize += MEM_INC;
949                toStr = realloc(toStr,toStrSize * sizeof(char));
950                if (NULL == toStr)
951                {
952                   inBytesLeft = 0;       /* end the translation */
953                   err = -3;
954                   break;                 /* BREAK */
955                }
956                outChar = (char *) (toStr + offset); /* recalc ptr */
957             }
958             break;
959          default:
960             inBytesLeft = 0;             /* breakout of loop */
961             break;
962          }  /* switch on convertsion result */
963       } /* if an error */
964    } /* while chars left to translate */
965
966    /* set the EOS */
967    if(outChar) *outChar = EOS;
968
969    /* set return values */
970    *ret_toStr = (char *) toStr;
971    if (toStrBuf) *ret_toStrLen = toStrSize;
972
973    return (NULL != toStr ? 0 : err);    /* RETURN result */
974 }
975
976
977 /*****************************************************************************
978  * Function:        void _DtHelpCeIconvClose()
979  *
980  * Parameters:      
981  *    io_iconvContext;      context
982  *
983  * Return Value:    none
984  *
985  * Purpose:
986  *              Closes an iconv context used to convert
987  *              fromCode to toCode using iconv(3)
988  *
989  * Comments:
990  *              iconv(3) is standardized in XPG4, which is just starting
991  *              to be supported.  Below are several different implementations 
992  *              of _DtHelpCeIconvStr, each using what is available on different 
993  *              platforms.  If no code is #ifdef'd, the XPG4 code defaults.
994  *****************************************************************************/
995 void _DtHelpCeIconvClose(
996          _DtHelpCeIconvContext * io_iconvContext)
997 {  /* XPG4-compliant code (args dflt1 & dflt2 are ignored in this code) */
998    _DtHelpCeIconvContextRec * ic;
999
1000    if (!io_iconvContext || NULL == *io_iconvContext) return;
1001    ic = *io_iconvContext;
1002
1003    if ( ic->cd != (iconv_t) BAD ) 
1004         iconv_close(ic->cd);
1005    if (ic->fromCodeset) free(ic->fromCodeset);
1006    if (ic->toCodeset) free(ic->toCodeset);
1007    free(ic);
1008    *io_iconvContext = NULL;
1009 }
1010
1011
1012 /*****************************************************************************
1013  * Function:        void _DtHelpCeIconvContextSuitable()
1014  *
1015  * Parameters:      
1016  *    iconvContext:   context
1017  *    fromCode:       proposed fromCodeset
1018  *    toCode:         proposed toCodeset
1019  *
1020  * Return Value:    True: proposed conversion compatible with this context
1021  *                  False: proposed conversion is not compatible
1022  *
1023  * Purpose:
1024  *              Checks whether the proposed conversion from
1025  *              fromCodeset to toCodeset can be handled by
1026  *              the iconv context that already exists.
1027  *
1028  * Comments:
1029  *              This function is designed to allow a context
1030  *              to stay open as long as possible and avoid
1031  *              closing and then reopening the contexts for
1032  *              the same conversion.
1033  *****************************************************************************/
1034 int _DtHelpCeIconvContextSuitable(
1035          _DtHelpCeIconvContext iconvContext,
1036          const char *          fromCode,
1037          const char *          toCode)
1038 {
1039    if (   !iconvContext 
1040        || !iconvContext->fromCodeset 
1041        || !iconvContext->toCodeset
1042        || !fromCode 
1043        || !toCode) 
1044        return False;
1045
1046    if (   strcmp(iconvContext->fromCodeset,fromCode) == 0
1047        && strcmp(iconvContext->toCodeset,toCode) == 0)
1048        return True;
1049
1050    return False;
1051 }
1052
1053
1054 #if defined(_AIX)
1055 /*****************************************************************************
1056  * Function: _DtHelpCeStrCaseCmp
1057  *
1058  * Parameters:
1059  *
1060  * Return Value:
1061  *
1062  * Purpose: IBM does not support the 'strcasecmp' routine. This takes it's
1063  *          place.
1064  *****************************************************************************/
1065 int
1066 _DtHelpCeStrCaseCmp (
1067     const char  *s1,
1068     const char  *s2)
1069 {
1070     return (_DtCvStrCaseCmp(s1, s2));
1071 }
1072 #endif /* _AIX */
1073
1074 /******************************************************************************
1075  * Function:     int _DtHelpCeFreeStringArray (char **array)
1076  *
1077  * Parameters:   array           A pointer to the NULL-terminated
1078  *                               string array which is to be freed.
1079  *
1080  * Return Value: 0 if successful, -1 if a failure occurs
1081  *
1082  * Purpose:      Free the memory used for a NULL-terminated string array.
1083  *
1084  ******************************************************************************/
1085 int
1086 _DtHelpCeFreeStringArray (char **array)
1087 {
1088     char        **next;
1089
1090     if (array == NULL)
1091         return -1;
1092
1093     for (next = array; *next != NULL; next++)
1094         free (*next);
1095
1096     free (array);
1097     return (0);
1098 }
1099
1100 /****************************************************************************
1101  * Function:    void **_DtHelpCeAddPtrToArray (void **array, void *ptr)
1102  *
1103  * Parameters:  array           A pointer to a NULL-terminated array
1104  *                              of pointers.
1105  *              ptr             The pointer which is to be added to
1106  *                              the end of the array.
1107  *
1108  * Returns:     A pointer to the NULL-terminated array created
1109  *              by adding 'ptr' to the end of 'array'.
1110  *
1111  * Purpose:     Add a new element to a NULL-terminated array of pointers.
1112  *              These are typed as "void *" so that they can be used with
1113  *              pointers to any type of data.
1114  *
1115  ****************************************************************************/
1116 void **
1117 _DtHelpCeAddPtrToArray (
1118        void  **array,
1119        void   *ptr)
1120 {
1121   return (_DtCvAddPtrToArray(array, ptr));
1122 }
1123
1124 /*****************************************************************************
1125  * Function: _DtHelpCeStrCaseCmpLatin1
1126  *
1127  * Parameters:
1128  *
1129  * Return Value:
1130  *
1131  * Purpose: Use a version of CaseCmp that does not go through tolower().
1132  *          This routine should be used only for compares that now the
1133  *          strings are in English (iso8859-1) and do not want setlocale
1134  *          to screw it up.
1135  *****************************************************************************/
1136 int
1137 _DtHelpCeStrCaseCmpLatin1 (
1138     const char  *s1,
1139     const char  *s2)
1140 {
1141     return (_DtCvStrCaseCmpLatin1(s1, s2));
1142 }
1143
1144 /*****************************************************************************
1145  * Function: _DtHelpCeStrNCaseCmpLatin1
1146  *
1147  * Parameters:
1148  *
1149  * Return Value:
1150  *
1151  * Purpose: Use a version of CaseCmp that does not go through tolower().
1152  *          This routine should be used only for compares that now the
1153  *          strings are in English (iso8859-1) and do not want setlocale
1154  *          to screw it up.
1155  *****************************************************************************/
1156 int
1157 _DtHelpCeStrNCaseCmpLatin1 (
1158     const char  *s1,
1159     const char  *s2,
1160     size_t        n)
1161 {
1162     return (_DtCvStrNCaseCmpLatin1(s1, s2, n));
1163 }
1164