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