Build with debug symbols enabled.
[oweals/cde.git] / cde / lib / DtSvc / DtUtil2 / DtNlUtils.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 librararies 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: DtNlUtils.c /main/10 1999/10/15 12:07:23 mgreess $ */
24 /*
25  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
26  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
27  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
28  * (c) Copyright 1993, 1994 Novell, Inc.                                *
29  */
30 /*****************************************************************************/
31 /*                                                                           */
32 /* This file contains the Dt versions of common string functions, which     */
33 /* have not yet been provided by the HP-UX platform.                         */
34 /* These functions know how to handle multi-byte strings.                    */
35 /*                                                                           */
36 /*****************************************************************************/
37
38 #include <string.h>
39 #include <Dt/DtNlUtils.h>
40 #include "DtSvcLock.h"
41
42 /*
43  * Globals
44  */
45 Boolean _DtNl_is_multibyte = False;
46
47
48 #ifdef NLS16
49 /*
50  * Dt nls initialization function.
51  *    will see if multibyte characters are
52  *    supported for the locale.  If multibyte characters are not supported,
53  *    then all of our string utilites simply call the standard libc function.
54  */
55
56 void 
57 Dt_nlInit( void )
58 {
59    char * bc;
60    static Boolean first = True;
61
62    _DtSvcProcessLock();
63    if (!first) {
64       _DtSvcProcessUnlock();
65       return;
66    }
67
68    first = False;
69    _DtSvcProcessUnlock();
70
71    if (MB_CUR_MAX > 1)
72       _DtNl_is_multibyte = True;
73    else
74       _DtNl_is_multibyte = False;
75 }
76
77 /*
78  * Dt version of strtok(s1, s2).
79  *    Returns a pointer to the span of characters in s1 terminated by
80  *    one of the characters in s2.  Only s1 can be multibyte.
81  */
82
83 char * 
84 Dt_strtok(
85         char *s1,
86         char *s2 )
87 {
88    static char *ptr;
89    char * return_ptr;
90    int len;
91    int offset;
92
93    /* Use standard libc function, if no multibyte */
94    if (!_DtNl_is_multibyte)
95       return(strtok(s1, s2));
96
97    /* 
98     * If this is the first call, save the string pointer, and bypass
99     * any leading separators.
100     */
101    if (s1)
102       ptr = s1 + Dt_strspn(s1, s2);
103
104    /* A Null string pointer has no tokens */
105    if (ptr == NULL)
106       return(NULL);
107
108    /* Find out where the first terminator is */
109    if ((len = Dt_strcspn(ptr, s2)) <= 0)
110    {
111       /* No tokens left */
112       return(NULL);
113    }
114
115    /* Keep track of where the token started */
116    return_ptr = ptr;
117
118    /* Null out the terminator; we need to know how many bytes are
119     * occupied by the terminator, so that we can skip over it to
120     * the next character.
121     */
122    /*
123     * We have to take care of the case when mblen() returns -1.
124     */
125    offset = mblen(ptr + len, MB_CUR_MAX);
126    if( offset == -1 )
127         offset = 1;
128    *(ptr + len) = '\0';
129    ptr += (len + offset);
130
131   /* 
132    * In preparation for the next pass, skip any other occurrances of
133    * the terminator characters which were joined with the terminator
134    * we first encountered.
135    */
136    len = Dt_strspn(ptr, s2);
137    ptr += len;
138
139    return(return_ptr);
140 }
141
142
143 char * 
144 Dt_strtok_r(
145         char *s1,
146         char *s2,
147         char **ptr )
148 {
149    char * return_ptr;
150    int len;
151    int offset;
152
153    /* Use standard libc function, if no multibyte */
154    if (!_DtNl_is_multibyte)
155       return((char*) strtok_r(s1, s2, ptr));
156
157    /* 
158     * If this is the first call, save the string pointer, and bypass
159     * any leading separators.
160     */
161    if (s1)
162       *ptr = s1 + Dt_strspn(s1, s2);
163
164    /* A Null string pointer has no tokens */
165    if (*ptr == NULL)
166       return(NULL);
167
168    /* Find out where the first terminator is */
169    if ((len = Dt_strcspn(*ptr, s2)) <= 0)
170    {
171       /* No tokens left */
172       return(NULL);
173    }
174
175    /* Keep track of where the token started */
176    return_ptr = *ptr;
177
178    /* Null out the terminator; we need to know how many bytes are
179     * occupied by the terminator, so that we can skip over it to
180     * the next character.
181     */
182    /*
183     * We have to take care of the case when mblen() returns -1.
184     */
185    offset = mblen(*ptr + len, MB_CUR_MAX);
186    if( offset == -1 )
187         offset = 1;
188    *(*ptr + len) = '\0';
189    *ptr += (len + offset);
190
191   /* 
192    * In preparation for the next pass, skip any other occurrances of
193    * the terminator characters which were joined with the terminator
194    * we first encountered.
195    */
196    len = Dt_strspn(*ptr, s2);
197    *ptr += len;
198
199    return(return_ptr);
200 }
201
202 /*
203  * Dt version of strspn(s1, s2).
204  *    Returns the span of characters in s1 contained in s2.  
205  *    Only s1 can be multibyte.
206  */
207
208 int 
209 Dt_strspn(
210         char *s1,
211         char *s2 )
212 {
213    wchar_t s1char, s2char;
214    int s1len, s2len;
215    int i;
216    int count;
217    char * ptr;
218    Boolean match;
219
220    /* Use the standard libc function, if multibyte is not present */
221    if (!_DtNl_is_multibyte)
222       return(strspn(s1, s2));
223
224    /* A Null string has no spans */
225    if (s1 == NULL)
226       return(0);
227
228    count = 0;
229    while (*s1)
230    {
231       /* Extract the next character from s1; may be multibyte */
232       if ((s1len = mbtowc(&s1char, s1, MB_CUR_MAX)) < 0)
233          return(0);
234       s1 += s1len;
235
236       /* 
237        * Compare this character against all the chars in s2.  Keep
238        * working through s1, until a character is found in s1 which
239        * is not contained in s2.
240        */
241       ptr = s2;
242       match = False;
243       while (*ptr)
244       {
245          /* Extract the next character from s2; cannot be multibyte */
246          s2char = *ptr++;
247
248          /* If a match is found, keep processing s1 */
249          if (s1char == s2char)
250          {
251             match = True;
252             count += s1len;
253             break;
254          }
255       }
256
257       /* 
258        * If we made it here because all of s2 was searched, and a match
259        * was not found against s1, then we are done.
260        */
261       if (!match)
262          return(count);
263    }
264
265    return(count);
266 }
267
268
269 /*
270  * Dt version of strcspn(s1, s2).
271  *    Returns the span of characters in s1 not contained in s2.
272  *    Only s1 can be multibyte.
273  */
274
275 int 
276 Dt_strcspn(
277         char *s1,
278         char *s2 )
279 {
280    wchar_t s1char, s2char;
281    int s1len, s2len;
282    int i;
283    int count;
284    char * ptr;
285
286    /* Use the standard libc function, if multibyte is not present */
287    if (!_DtNl_is_multibyte)
288       return(strcspn(s1, s2));
289
290    /* An empty string has no spans */
291    if (s1 == NULL)
292       return(0);
293
294    count = 0;
295    while (*s1)
296    {
297       /* Extract the next character from s1; may be multibyte */
298       if ((s1len = mbtowc(&s1char, s1, MB_CUR_MAX)) < 0)
299          return(0);
300       s1 += s1len;
301
302       /* 
303        * Compare this character against all the chars in s2.  Keep
304        * working through s1, until a character is found in s1 which
305        * is contained in s2.
306        */
307       ptr = s2;
308       while (*ptr)
309       {
310          /* Extract the next character from s2; cannot be multibyte */
311          s2char = *ptr++;
312  
313          /* If a match occurs, then we are done */
314          if (s1char == s2char)
315             return(count);
316       }
317
318       /*
319        * If we've made it here, then we searched all of s2, and none of
320        * its components matched s1; continue with the next character
321        * in s1.
322        */
323       count += s1len;
324    }
325
326    return(count);
327 }
328
329
330 /*
331  * Dt version of strchr(s, c).
332  *    Returns a pointer to the first occurance of 'c' in 's'.
333  */
334
335 char * 
336 Dt_strchr(
337         char *s,
338         char c )
339 {
340    wchar_t schar;
341    int i;
342    int slen;
343    wchar_t wc;
344    char foo[2];
345
346    if (s == NULL)
347       return(NULL);
348
349    /* Use standard libc function if multibyte is not enabled */
350    if (!_DtNl_is_multibyte)
351       return(strchr(s, c));
352
353    foo[0] = c;
354    foo[1] = '\0';
355    mbtowc(&wc, foo, 2);
356
357    do
358    {
359       /* Extract next char from 's'; may be multibyte */
360       if ((slen = mbtowc(&schar, s, MB_CUR_MAX)) < 0)
361          return(NULL);
362       s += slen;
363
364       /* If we match 'c', then return a pointer to this character */
365       if (schar == wc)
366          return (s - slen);
367    } while (slen > 0);
368
369    /* No match was found */
370    return(NULL);
371 }
372
373
374 /*
375  * Dt version of strrchr(s, c).
376  *    Returns a pointer to the last occurance of 'c' in 's'.
377  */
378
379 char * 
380 Dt_strrchr(
381         char *s,
382         char c )
383 {
384    wchar_t schar;
385    int i;
386    int slen;
387    char * last = NULL;
388    wchar_t wc;
389    char foo[2];
390
391    if (s == NULL)
392       return(NULL);
393
394    /* Use standard libc function if multibyte is not enabled */
395    if (!_DtNl_is_multibyte)
396       return(strrchr(s, c));
397
398    foo[0] = c;
399    foo[1] = '\0';
400    mbtowc(&wc, foo, 2);
401
402    do
403    {
404       /* Extract next char from 's'; may be multibyte */
405       if ((slen = mbtowc(&schar, s, MB_CUR_MAX)) < 0)
406          return(NULL);
407       s += slen;
408
409       /* If we match 'c', keep track of it, and keep looking */
410       if (schar == wc)
411          last = s - slen;
412    } while (slen > 0);
413
414    return(last);
415 }
416
417
418 /*
419  * Dt equivalent of s[strlen(s) - 1]
420  *    Returns the last character in the string 's'.
421  */
422
423 void 
424 Dt_lastChar(
425         char *s,
426         char **cptr,
427         int *lenptr )
428 {
429    int len = 0;
430
431    if ((s == NULL) || (*s == '\0'))
432    {
433       *lenptr = 0;
434       *cptr = NULL;
435       return;
436    }
437
438    /* Use the easy method, if possible */
439    if (!_DtNl_is_multibyte)
440    {
441       *cptr = s + strlen(s) - 1;
442       *lenptr = 1;
443       return;
444    }
445
446    /* Move through the string, keeping a ptr to the last character found */
447    while (*s)
448    {
449       /*
450        * We have to take care of the case when mbtowc() returns -1
451        */
452       len = mbtowc(NULL, s, MB_CUR_MAX);
453       if ( len == -1 )
454          len = 1;
455       s += len;
456    }
457
458    /* Backup to the character before the NULL */
459    *lenptr = mblen(s-len, MB_CUR_MAX);
460    *cptr = s - len;
461 }
462
463
464 /*
465  * Dt equivalent of strlen()
466  *    Returns the number of characters (not bytes) in a string
467  */
468
469 int 
470 Dt_charCount(
471         char *s )
472 {
473    int count = 0;
474    int len;
475
476    if (s == NULL)
477       return(0);
478
479    if (!_DtNl_is_multibyte)
480       return(strlen(s));
481
482    /* Move through the string, counting each character present */
483    while (*s)
484    {
485       len = mblen(s, MB_CUR_MAX);
486       /* if invalid character, still count it and continue */
487       if (len == -1)
488         len = 1;
489       s += len;
490       count++;
491    }
492
493    return(count);
494 }
495
496 /******************************************************************************
497  *
498  * _Dt_NextChar(s)
499  *      return a pointer to the next multi-byte character after the character
500  *      pointed to by "s".  If "s" does not point to a valid multi-byte
501  *      character advance one byte.
502  *
503  ******************************************************************************/
504 char *
505 _Dt_NextChar(char *s)
506 {
507         int len=1;
508         
509         if (_DtNl_is_multibyte || (MB_CUR_MAX > 1))
510             len = mblen ( s, MB_CUR_MAX);
511
512         /*
513          * If "s" did not point to a vaild multi-byte character, 
514          * move ahead one byte.
515          */  
516         if ( len == -1 )
517             len = 1;
518
519         return s + len;
520 }
521
522 /******************************************************************************
523  *
524  * _Dt_PrevChar(start,s)
525  *      return a pointer to the  multi-byte character preceding the
526  *      character pointed to by "s".  If "s" does not point to a valid
527  *      multi-byte character retreat one byte. "start" should point to 
528  *      a character preceding "s" in the multi-byte string. 
529  *
530  ******************************************************************************/
531 char *
532 _Dt_PrevChar(const char *start, char *s)
533 {
534         char *p;
535         int len;
536
537         if ( !_DtNl_is_multibyte || (MB_CUR_MAX == 1) )
538             return (s - 1);
539
540         /*
541          * Check if "*s" is a valid multi-byte character.
542          * if not just return the previous byte.
543          */
544         if ( mblen(s,MB_CUR_MAX) < 0 )
545             return (s - 1);
546
547         /*
548          * "start" must be less than "s" ; if not return
549          * (s-1)
550          */
551         if ( start >= s )
552              return (s - 1);
553  
554         /*
555          * Check that "start" points to a valid multi-byte character.
556          * otherwise return "s-1"
557          */
558         if ( mblen(start,MB_CUR_MAX) < 0 )
559              return (s-1);
560
561         /*
562          * Starting from "start" traverse the string until we find
563          * the character preceding "s". 
564          */
565         /*
566          * We have to take care of the case when mblen() returns -1.
567          */
568         for (p = (char *)start;
569                 p + (len = (mblen(p,MB_CUR_MAX) == -1 ? 1 : mblen(p,MB_CUR_MAX))) < s;
570                 p += len)
571                 /* NULL STATEMENT */;
572
573         /*
574          * We should always find a multi-byte character preceding "s" if
575          * "*s" is a valid multi-byte char and not the first character of
576          * the text.
577          */
578         /* myassert(p < s); */
579          
580         return p;
581 }
582
583 /*
584  * Dt mult-byte equivalent of isspace()
585  */
586 int
587 _Dt_isspace(char *s)
588 {
589         if ( !_DtNl_is_multibyte || MB_CUR_MAX == 1 )
590                 return isspace((u_char)*s);
591
592         if ( mblen(s,MB_CUR_MAX) == 1 )
593                 return isspace((u_char)*s);
594         else
595                 return 0;
596 }
597
598 /*
599  * Dt mult-byte equivalent of isdigit()
600  */
601 int
602 _Dt_isdigit(char *s)
603 {
604         if ( !_DtNl_is_multibyte || MB_CUR_MAX == 1 )
605                 return isdigit(*s);
606
607         if ( mblen(s,MB_CUR_MAX) == 1 )
608                 return isdigit(*s);
609         else
610                 return 0;
611 }
612
613
614
615
616 /*
617  * Dt equivalent of &(s[n])
618  *    Returns a pointer to the indicated character
619  */
620
621 char * 
622 _DtGetNthChar(
623         char *s,
624         int n )
625 {
626    int count;
627    int len;
628
629    if ((s == NULL) || (n < 0) || (n > Dt_charCount(s)))
630       return(NULL);
631
632    count = 0;
633    while ((count < n) && (*s))
634    {
635       if (_DtNl_is_multibyte)
636          len = mblen(s, MB_CUR_MAX);
637       else
638          len = 1;
639       /*
640        * We have to take care of the case when mblen() returns -1.
641        */
642       if ( len == -1 )
643          len = 1;
644
645       s += len;
646       count++;
647    }
648
649    return(s);
650 }
651
652
653 /*
654  * multibyte version of strpbrk().
655  * Only cs can be multibyte.
656  */
657 char *
658 _dt_strpbrk(
659         char *cs,
660         char *ct)
661 {
662     int len;
663     size_t i;
664
665     if(MB_CUR_MAX == 1)
666         return(strpbrk(cs, ct));
667
668     while(*cs) {
669         len = mblen(cs, MB_CUR_MAX);
670         if(len < 1)
671             len = 1;
672         if(len == 1) {
673             for(i = 0; i < strlen(ct); i++) {
674                 if(*cs == *(ct + i))
675                     return(cs);
676             }
677         }
678         cs += len;
679     }
680     return(NULL);
681 }
682
683
684 /*
685  * returns 1 if a character before s2 in s1 is single-byte,
686  * returns 0 if it is multi-byte.
687  */
688 int
689 _is_previous_single(
690         char *s1,
691         char *s2)
692 {
693     int n = 1;
694
695     if(MB_CUR_MAX == 1)
696         return(1);
697
698     while(*s1) {
699         if(s1 == s2) {
700             if(n > 1)
701                 return(0);
702             else
703                 return(1);
704         }
705         n = mblen(s1, MB_CUR_MAX) > 1 ? mblen(s1, MB_CUR_MAX) : 1;
706         s1 += n;
707     }
708     return(1);
709 }
710
711 #else
712
713 char * 
714 _DtGetNthChar(
715         char *s,
716         int n )
717 {
718    if ((s == NULL) || (n < 0) || (n > strlen(s)))
719       return(NULL);
720
721    return (s + n);
722 }
723
724 char *
725 _dt_strpbrk(
726         char *cs,
727         char *ct)
728 {
729     return(strpbrk(cs, ct));
730 }
731
732 int
733 _is_previous_single(
734         char *s1,
735         char *s2)
736 {
737     return(1);
738 }
739 #endif /* NLS16 */