740 lines
16 KiB
C
740 lines
16 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these librararies and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $TOG: DtNlUtils.c /main/10 1999/10/15 12:07:23 mgreess $ */
|
|
/*
|
|
* (c) Copyright 1993, 1994 Hewlett-Packard Company *
|
|
* (c) Copyright 1993, 1994 International Business Machines Corp. *
|
|
* (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
|
|
* (c) Copyright 1993, 1994 Novell, Inc. *
|
|
*/
|
|
/*****************************************************************************/
|
|
/* */
|
|
/* This file contains the Dt versions of common string functions, which */
|
|
/* have not yet been provided by the HP-UX platform. */
|
|
/* These functions know how to handle multi-byte strings. */
|
|
/* */
|
|
/*****************************************************************************/
|
|
|
|
#include <string.h>
|
|
#include <Dt/DtNlUtils.h>
|
|
#include "DtSvcLock.h"
|
|
|
|
/*
|
|
* Globals
|
|
*/
|
|
Boolean _DtNl_is_multibyte = False;
|
|
|
|
|
|
#ifdef NLS16
|
|
/*
|
|
* Dt nls initialization function.
|
|
* will see if multibyte characters are
|
|
* supported for the locale. If multibyte characters are not supported,
|
|
* then all of our string utilites simply call the standard libc function.
|
|
*/
|
|
|
|
void
|
|
Dt_nlInit( void )
|
|
{
|
|
char * bc;
|
|
static Boolean first = True;
|
|
|
|
_DtSvcProcessLock();
|
|
if (!first) {
|
|
_DtSvcProcessUnlock();
|
|
return;
|
|
}
|
|
|
|
first = False;
|
|
_DtSvcProcessUnlock();
|
|
|
|
if (MB_CUR_MAX > 1)
|
|
_DtNl_is_multibyte = True;
|
|
else
|
|
_DtNl_is_multibyte = False;
|
|
}
|
|
|
|
/*
|
|
* Dt version of strtok(s1, s2).
|
|
* Returns a pointer to the span of characters in s1 terminated by
|
|
* one of the characters in s2. Only s1 can be multibyte.
|
|
*/
|
|
|
|
char *
|
|
Dt_strtok(
|
|
char *s1,
|
|
char *s2 )
|
|
{
|
|
static char *ptr;
|
|
char * return_ptr;
|
|
int len;
|
|
int offset;
|
|
|
|
/* Use standard libc function, if no multibyte */
|
|
if (!_DtNl_is_multibyte)
|
|
return(strtok(s1, s2));
|
|
|
|
/*
|
|
* If this is the first call, save the string pointer, and bypass
|
|
* any leading separators.
|
|
*/
|
|
if (s1)
|
|
ptr = s1 + Dt_strspn(s1, s2);
|
|
|
|
/* A Null string pointer has no tokens */
|
|
if (ptr == NULL)
|
|
return(NULL);
|
|
|
|
/* Find out where the first terminator is */
|
|
if ((len = Dt_strcspn(ptr, s2)) <= 0)
|
|
{
|
|
/* No tokens left */
|
|
return(NULL);
|
|
}
|
|
|
|
/* Keep track of where the token started */
|
|
return_ptr = ptr;
|
|
|
|
/* Null out the terminator; we need to know how many bytes are
|
|
* occupied by the terminator, so that we can skip over it to
|
|
* the next character.
|
|
*/
|
|
/*
|
|
* We have to take care of the case when mblen() returns -1.
|
|
*/
|
|
offset = mblen(ptr + len, MB_CUR_MAX);
|
|
if( offset == -1 )
|
|
offset = 1;
|
|
*(ptr + len) = '\0';
|
|
ptr += (len + offset);
|
|
|
|
/*
|
|
* In preparation for the next pass, skip any other occurrances of
|
|
* the terminator characters which were joined with the terminator
|
|
* we first encountered.
|
|
*/
|
|
len = Dt_strspn(ptr, s2);
|
|
ptr += len;
|
|
|
|
return(return_ptr);
|
|
}
|
|
|
|
|
|
char *
|
|
Dt_strtok_r(
|
|
char *s1,
|
|
char *s2,
|
|
char **ptr )
|
|
{
|
|
char * return_ptr;
|
|
int len;
|
|
int offset;
|
|
|
|
/* Use standard libc function, if no multibyte */
|
|
if (!_DtNl_is_multibyte)
|
|
return((char*) strtok_r(s1, s2, ptr));
|
|
|
|
/*
|
|
* If this is the first call, save the string pointer, and bypass
|
|
* any leading separators.
|
|
*/
|
|
if (s1)
|
|
*ptr = s1 + Dt_strspn(s1, s2);
|
|
|
|
/* A Null string pointer has no tokens */
|
|
if (*ptr == NULL)
|
|
return(NULL);
|
|
|
|
/* Find out where the first terminator is */
|
|
if ((len = Dt_strcspn(*ptr, s2)) <= 0)
|
|
{
|
|
/* No tokens left */
|
|
return(NULL);
|
|
}
|
|
|
|
/* Keep track of where the token started */
|
|
return_ptr = *ptr;
|
|
|
|
/* Null out the terminator; we need to know how many bytes are
|
|
* occupied by the terminator, so that we can skip over it to
|
|
* the next character.
|
|
*/
|
|
/*
|
|
* We have to take care of the case when mblen() returns -1.
|
|
*/
|
|
offset = mblen(*ptr + len, MB_CUR_MAX);
|
|
if( offset == -1 )
|
|
offset = 1;
|
|
*(*ptr + len) = '\0';
|
|
*ptr += (len + offset);
|
|
|
|
/*
|
|
* In preparation for the next pass, skip any other occurrances of
|
|
* the terminator characters which were joined with the terminator
|
|
* we first encountered.
|
|
*/
|
|
len = Dt_strspn(*ptr, s2);
|
|
*ptr += len;
|
|
|
|
return(return_ptr);
|
|
}
|
|
|
|
/*
|
|
* Dt version of strspn(s1, s2).
|
|
* Returns the span of characters in s1 contained in s2.
|
|
* Only s1 can be multibyte.
|
|
*/
|
|
|
|
int
|
|
Dt_strspn(
|
|
char *s1,
|
|
char *s2 )
|
|
{
|
|
wchar_t s1char, s2char;
|
|
int s1len, s2len;
|
|
int i;
|
|
int count;
|
|
char * ptr;
|
|
Boolean match;
|
|
|
|
/* Use the standard libc function, if multibyte is not present */
|
|
if (!_DtNl_is_multibyte)
|
|
return(strspn(s1, s2));
|
|
|
|
/* A Null string has no spans */
|
|
if (s1 == NULL)
|
|
return(0);
|
|
|
|
count = 0;
|
|
while (*s1)
|
|
{
|
|
/* Extract the next character from s1; may be multibyte */
|
|
if ((s1len = mbtowc(&s1char, s1, MB_CUR_MAX)) < 0)
|
|
return(0);
|
|
s1 += s1len;
|
|
|
|
/*
|
|
* Compare this character against all the chars in s2. Keep
|
|
* working through s1, until a character is found in s1 which
|
|
* is not contained in s2.
|
|
*/
|
|
ptr = s2;
|
|
match = False;
|
|
while (*ptr)
|
|
{
|
|
/* Extract the next character from s2; cannot be multibyte */
|
|
s2char = *ptr++;
|
|
|
|
/* If a match is found, keep processing s1 */
|
|
if (s1char == s2char)
|
|
{
|
|
match = True;
|
|
count += s1len;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we made it here because all of s2 was searched, and a match
|
|
* was not found against s1, then we are done.
|
|
*/
|
|
if (!match)
|
|
return(count);
|
|
}
|
|
|
|
return(count);
|
|
}
|
|
|
|
|
|
/*
|
|
* Dt version of strcspn(s1, s2).
|
|
* Returns the span of characters in s1 not contained in s2.
|
|
* Only s1 can be multibyte.
|
|
*/
|
|
|
|
int
|
|
Dt_strcspn(
|
|
char *s1,
|
|
char *s2 )
|
|
{
|
|
wchar_t s1char, s2char;
|
|
int s1len, s2len;
|
|
int i;
|
|
int count;
|
|
char * ptr;
|
|
|
|
/* Use the standard libc function, if multibyte is not present */
|
|
if (!_DtNl_is_multibyte)
|
|
return(strcspn(s1, s2));
|
|
|
|
/* An empty string has no spans */
|
|
if (s1 == NULL)
|
|
return(0);
|
|
|
|
count = 0;
|
|
while (*s1)
|
|
{
|
|
/* Extract the next character from s1; may be multibyte */
|
|
if ((s1len = mbtowc(&s1char, s1, MB_CUR_MAX)) < 0)
|
|
return(0);
|
|
s1 += s1len;
|
|
|
|
/*
|
|
* Compare this character against all the chars in s2. Keep
|
|
* working through s1, until a character is found in s1 which
|
|
* is contained in s2.
|
|
*/
|
|
ptr = s2;
|
|
while (*ptr)
|
|
{
|
|
/* Extract the next character from s2; cannot be multibyte */
|
|
s2char = *ptr++;
|
|
|
|
/* If a match occurs, then we are done */
|
|
if (s1char == s2char)
|
|
return(count);
|
|
}
|
|
|
|
/*
|
|
* If we've made it here, then we searched all of s2, and none of
|
|
* its components matched s1; continue with the next character
|
|
* in s1.
|
|
*/
|
|
count += s1len;
|
|
}
|
|
|
|
return(count);
|
|
}
|
|
|
|
|
|
/*
|
|
* Dt version of strchr(s, c).
|
|
* Returns a pointer to the first occurance of 'c' in 's'.
|
|
*/
|
|
|
|
char *
|
|
Dt_strchr(
|
|
char *s,
|
|
char c )
|
|
{
|
|
wchar_t schar;
|
|
int i;
|
|
int slen;
|
|
wchar_t wc;
|
|
char foo[2];
|
|
|
|
if (s == NULL)
|
|
return(NULL);
|
|
|
|
/* Use standard libc function if multibyte is not enabled */
|
|
if (!_DtNl_is_multibyte)
|
|
return(strchr(s, c));
|
|
|
|
foo[0] = c;
|
|
foo[1] = '\0';
|
|
mbtowc(&wc, foo, 2);
|
|
|
|
do
|
|
{
|
|
/* Extract next char from 's'; may be multibyte */
|
|
if ((slen = mbtowc(&schar, s, MB_CUR_MAX)) < 0)
|
|
return(NULL);
|
|
s += slen;
|
|
|
|
/* If we match 'c', then return a pointer to this character */
|
|
if (schar == wc)
|
|
return (s - slen);
|
|
} while (slen > 0);
|
|
|
|
/* No match was found */
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
* Dt version of strrchr(s, c).
|
|
* Returns a pointer to the last occurance of 'c' in 's'.
|
|
*/
|
|
|
|
char *
|
|
Dt_strrchr(
|
|
char *s,
|
|
char c )
|
|
{
|
|
wchar_t schar;
|
|
int i;
|
|
int slen;
|
|
char * last = NULL;
|
|
wchar_t wc;
|
|
char foo[2];
|
|
|
|
if (s == NULL)
|
|
return(NULL);
|
|
|
|
/* Use standard libc function if multibyte is not enabled */
|
|
if (!_DtNl_is_multibyte)
|
|
return(strrchr(s, c));
|
|
|
|
foo[0] = c;
|
|
foo[1] = '\0';
|
|
mbtowc(&wc, foo, 2);
|
|
|
|
do
|
|
{
|
|
/* Extract next char from 's'; may be multibyte */
|
|
if ((slen = mbtowc(&schar, s, MB_CUR_MAX)) < 0)
|
|
return(NULL);
|
|
s += slen;
|
|
|
|
/* If we match 'c', keep track of it, and keep looking */
|
|
if (schar == wc)
|
|
last = s - slen;
|
|
} while (slen > 0);
|
|
|
|
return(last);
|
|
}
|
|
|
|
|
|
/*
|
|
* Dt equivalent of s[strlen(s) - 1]
|
|
* Returns the last character in the string 's'.
|
|
*/
|
|
|
|
void
|
|
Dt_lastChar(
|
|
char *s,
|
|
char **cptr,
|
|
int *lenptr )
|
|
{
|
|
int len = 0;
|
|
|
|
if ((s == NULL) || (*s == '\0'))
|
|
{
|
|
*lenptr = 0;
|
|
*cptr = NULL;
|
|
return;
|
|
}
|
|
|
|
/* Use the easy method, if possible */
|
|
if (!_DtNl_is_multibyte)
|
|
{
|
|
*cptr = s + strlen(s) - 1;
|
|
*lenptr = 1;
|
|
return;
|
|
}
|
|
|
|
/* Move through the string, keeping a ptr to the last character found */
|
|
while (*s)
|
|
{
|
|
/*
|
|
* We have to take care of the case when mbtowc() returns -1
|
|
*/
|
|
len = mbtowc(NULL, s, MB_CUR_MAX);
|
|
if ( len == -1 )
|
|
len = 1;
|
|
s += len;
|
|
}
|
|
|
|
/* Backup to the character before the NULL */
|
|
*lenptr = mblen(s-len, MB_CUR_MAX);
|
|
*cptr = s - len;
|
|
}
|
|
|
|
|
|
/*
|
|
* Dt equivalent of strlen()
|
|
* Returns the number of characters (not bytes) in a string
|
|
*/
|
|
|
|
int
|
|
Dt_charCount(
|
|
char *s )
|
|
{
|
|
int count = 0;
|
|
int len;
|
|
|
|
if (s == NULL)
|
|
return(0);
|
|
|
|
if (!_DtNl_is_multibyte)
|
|
return(strlen(s));
|
|
|
|
/* Move through the string, counting each character present */
|
|
while (*s)
|
|
{
|
|
len = mblen(s, MB_CUR_MAX);
|
|
/* if invalid character, still count it and continue */
|
|
if (len == -1)
|
|
len = 1;
|
|
s += len;
|
|
count++;
|
|
}
|
|
|
|
return(count);
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* _Dt_NextChar(s)
|
|
* return a pointer to the next multi-byte character after the character
|
|
* pointed to by "s". If "s" does not point to a valid multi-byte
|
|
* character advance one byte.
|
|
*
|
|
******************************************************************************/
|
|
char *
|
|
_Dt_NextChar(char *s)
|
|
{
|
|
int len=1;
|
|
|
|
if (_DtNl_is_multibyte || (MB_CUR_MAX > 1))
|
|
len = mblen ( s, MB_CUR_MAX);
|
|
|
|
/*
|
|
* If "s" did not point to a vaild multi-byte character,
|
|
* move ahead one byte.
|
|
*/
|
|
if ( len == -1 )
|
|
len = 1;
|
|
|
|
return s + len;
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* _Dt_PrevChar(start,s)
|
|
* return a pointer to the multi-byte character preceding the
|
|
* character pointed to by "s". If "s" does not point to a valid
|
|
* multi-byte character retreat one byte. "start" should point to
|
|
* a character preceding "s" in the multi-byte string.
|
|
*
|
|
******************************************************************************/
|
|
char *
|
|
_Dt_PrevChar(const char *start, char *s)
|
|
{
|
|
char *p;
|
|
int len;
|
|
|
|
if ( !_DtNl_is_multibyte || (MB_CUR_MAX == 1) )
|
|
return (s - 1);
|
|
|
|
/*
|
|
* Check if "*s" is a valid multi-byte character.
|
|
* if not just return the previous byte.
|
|
*/
|
|
if ( mblen(s,MB_CUR_MAX) < 0 )
|
|
return (s - 1);
|
|
|
|
/*
|
|
* "start" must be less than "s" ; if not return
|
|
* (s-1)
|
|
*/
|
|
if ( start >= s )
|
|
return (s - 1);
|
|
|
|
/*
|
|
* Check that "start" points to a valid multi-byte character.
|
|
* otherwise return "s-1"
|
|
*/
|
|
if ( mblen(start,MB_CUR_MAX) < 0 )
|
|
return (s-1);
|
|
|
|
/*
|
|
* Starting from "start" traverse the string until we find
|
|
* the character preceding "s".
|
|
*/
|
|
/*
|
|
* We have to take care of the case when mblen() returns -1.
|
|
*/
|
|
for (p = (char *)start;
|
|
p + (len = (mblen(p,MB_CUR_MAX) == -1 ? 1 : mblen(p,MB_CUR_MAX))) < s;
|
|
p += len)
|
|
/* NULL STATEMENT */;
|
|
|
|
/*
|
|
* We should always find a multi-byte character preceding "s" if
|
|
* "*s" is a valid multi-byte char and not the first character of
|
|
* the text.
|
|
*/
|
|
/* myassert(p < s); */
|
|
|
|
return p;
|
|
}
|
|
|
|
/*
|
|
* Dt mult-byte equivalent of isspace()
|
|
*/
|
|
int
|
|
_Dt_isspace(char *s)
|
|
{
|
|
if ( !_DtNl_is_multibyte || MB_CUR_MAX == 1 )
|
|
return isspace((u_char)*s);
|
|
|
|
if ( mblen(s,MB_CUR_MAX) == 1 )
|
|
return isspace((u_char)*s);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Dt mult-byte equivalent of isdigit()
|
|
*/
|
|
int
|
|
_Dt_isdigit(char *s)
|
|
{
|
|
if ( !_DtNl_is_multibyte || MB_CUR_MAX == 1 )
|
|
return isdigit(*s);
|
|
|
|
if ( mblen(s,MB_CUR_MAX) == 1 )
|
|
return isdigit(*s);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
* Dt equivalent of &(s[n])
|
|
* Returns a pointer to the indicated character
|
|
*/
|
|
|
|
char *
|
|
_DtGetNthChar(
|
|
char *s,
|
|
int n )
|
|
{
|
|
int count;
|
|
int len;
|
|
|
|
if ((s == NULL) || (n < 0) || (n > Dt_charCount(s)))
|
|
return(NULL);
|
|
|
|
count = 0;
|
|
while ((count < n) && (*s))
|
|
{
|
|
if (_DtNl_is_multibyte)
|
|
len = mblen(s, MB_CUR_MAX);
|
|
else
|
|
len = 1;
|
|
/*
|
|
* We have to take care of the case when mblen() returns -1.
|
|
*/
|
|
if ( len == -1 )
|
|
len = 1;
|
|
|
|
s += len;
|
|
count++;
|
|
}
|
|
|
|
return(s);
|
|
}
|
|
|
|
|
|
/*
|
|
* multibyte version of strpbrk().
|
|
* Only cs can be multibyte.
|
|
*/
|
|
char *
|
|
_dt_strpbrk(
|
|
char *cs,
|
|
char *ct)
|
|
{
|
|
int len;
|
|
size_t i;
|
|
|
|
if(MB_CUR_MAX == 1)
|
|
return(strpbrk(cs, ct));
|
|
|
|
while(*cs) {
|
|
len = mblen(cs, MB_CUR_MAX);
|
|
if(len < 1)
|
|
len = 1;
|
|
if(len == 1) {
|
|
for(i = 0; i < strlen(ct); i++) {
|
|
if(*cs == *(ct + i))
|
|
return(cs);
|
|
}
|
|
}
|
|
cs += len;
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
* returns 1 if a character before s2 in s1 is single-byte,
|
|
* returns 0 if it is multi-byte.
|
|
*/
|
|
int
|
|
_is_previous_single(
|
|
char *s1,
|
|
char *s2)
|
|
{
|
|
int n = 1;
|
|
|
|
if(MB_CUR_MAX == 1)
|
|
return(1);
|
|
|
|
while(*s1) {
|
|
if(s1 == s2) {
|
|
if(n > 1)
|
|
return(0);
|
|
else
|
|
return(1);
|
|
}
|
|
n = mblen(s1, MB_CUR_MAX) > 1 ? mblen(s1, MB_CUR_MAX) : 1;
|
|
s1 += n;
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
#else
|
|
|
|
char *
|
|
_DtGetNthChar(
|
|
char *s,
|
|
int n )
|
|
{
|
|
if ((s == NULL) || (n < 0) || (n > strlen(s)))
|
|
return(NULL);
|
|
|
|
return (s + n);
|
|
}
|
|
|
|
char *
|
|
_dt_strpbrk(
|
|
char *cs,
|
|
char *ct)
|
|
{
|
|
return(strpbrk(cs, ct));
|
|
}
|
|
|
|
int
|
|
_is_previous_single(
|
|
char *s1,
|
|
char *s2)
|
|
{
|
|
return(1);
|
|
}
|
|
#endif /* NLS16 */
|