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