Author: rmeggins
Update of /cvs/dirsec/adminserver/lib/base
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv8870
Modified Files:
Makefile
Added Files:
nscputil.cpp
Log Message:
renamed util.cpp to nscputil.cpp to avoid object/file naming conflict in autoconf builds
--- NEW FILE nscputil.cpp ---
/** BEGIN COPYRIGHT BLOCK
* Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
* Copyright (C) 2005 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* END COPYRIGHT BLOCK **/
/*
* util.c: A hodge podge of utility functions and standard functions which
* are unavailable on certain systems
*
* Rob McCool
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#ifdef XP_UNIX
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include "prthread.h"
#endif /* XP_UNIX */
#include "base/util.h"
#include "base/dbtbase.h"
#ifdef XP_UNIX
#include <sys/types.h>
#endif /* WIN32 */
#ifdef XP_WIN32
#define VC_EXTRALEAN // Exclude rarely-used stuff from afxwin.h
#include <afxwin.h> // MFC core and standard components`
#include <winnls.h>
#endif
#ifdef _WIN32
static char *win_char_converter(const char *instr, int bFromUTF8);
#else
#include <locale.h>
#endif
#ifndef _WIN32
#include <iconv.h>
#include <langinfo.h> /* for nl_langinfo() */
#endif
#if defined(_HPUX_SOURCE)
#define UTIL_CHARSET_UTF8 "utf8" /* HP/UX */
#else
#define UTIL_CHARSET_UTF8 "UTF-8" /* all others */
#endif
#if defined(_HPUX_SOURCE)
#define UTIL_CHARSET_DEFAULT "roma8" /* HP/UX */
#elif defined(__GLIBC__)
#define UTIL_CHARSET_DEFAULT "US-ASCII" /* glibc, e.g. Linux */
#else
#define UTIL_CHARSET_DEFAULT "646" /* all others */
#endif
#ifdef __cplusplus
extern "C" {
#endif
static char *convertor( const char *src, int fromUtf8 );
#ifndef _WIN32
static const char *GetCurrentCharset(void);
#endif
#ifdef __cplusplus
}
#endif
/* ----------------------------- util_getline ----------------------------- */
#define LF 10
#define CR 13
NSAPI_PUBLIC int util_getline(filebuf_t *buf, int lineno, int maxlen, char *l) {
int i, x;
x = 0;
while(1) {
switch(i = (int)filebuf_getc(buf)) {
case IO_EOF:
l[x] = '\0';
return 1;
case LF:
if(x && (l[x-1] == '\\')) {
--x;
continue;
}
l[x] = '\0';
return 0;
case IO_ERROR:
util_sprintf(l, "I/O error reading file at line %d", lineno);
return -1;
case CR:
continue;
default:
l[x] = (char) i;
if(++x == maxlen) {
util_sprintf(l, "line %d is too long", lineno);
return -1;
}
break;
}
}
}
/* ---------------------------- util_can_exec ----------------------------- */
#ifdef XP_UNIX
NSAPI_PUBLIC int util_can_exec(struct stat *fi, uid_t uid, gid_t gid)
{
if(!uid)
return 1;
if((fi->st_mode & S_IXOTH) ||
((gid == fi->st_gid) && (fi->st_mode & S_IXGRP)) ||
((uid == fi->st_uid) && (fi->st_mode & S_IXUSR)))
return 1;
return 0;
}
#endif /* XP_UNIX */
/* --------------------------- util_env_create ---------------------------- */
NSAPI_PUBLIC char **util_env_create(char **env, int n, int *pos)
{
int x;
if(!env) {
*pos = 0;
return (char **) MALLOC((n + 1)*sizeof(char *));
}
else {
for(x = 0; (env[x]); x++);
env = (char **) REALLOC(env, (n + x + 1)*(sizeof(char *)));
*pos = x;
return env;
}
}
/* ---------------------------- util_env_free ----------------------------- */
NSAPI_PUBLIC void util_env_free(char **env)
{
register char **ep = env;
for(ep = env; *ep; ep++)
FREE(*ep);
FREE(env);
}
/* ----------------------------- util_env_str ----------------------------- */
NSAPI_PUBLIC char *util_env_str(char *name, char *value) {
char *t,*tp;
t = (char *) MALLOC(strlen(name)+strlen(value)+2); /* 2: '=' and '\0'
*/
for(tp=t; (*tp = *name); tp++,name++);
for(*tp++ = '='; (*tp = *value); tp++,value++);
return t;
}
/* --------------------------- util_env_replace --------------------------- */
NSAPI_PUBLIC void util_env_replace(char **env, char *name, char *value)
{
int x, y, z;
char *i;
for(x = 0; env[x]; x++) {
i = strchr(env[x], '=');
*i = '\0';
if(!strcmp(env[x], name)) {
y = strlen(env[x]);
z = strlen(value);
env[x] = (char *) REALLOC(env[x], y + z + 2);
util_sprintf(&env[x][y], "=%s", value);
return;
}
*i = '=';
}
}
/* ---------------------------- util_env_find ----------------------------- */
NSAPI_PUBLIC char *util_env_find(char **env, char *name)
{
char *i;
int x, r;
for(x = 0; env[x]; x++) {
i = strchr(env[x], '=');
*i = '\0';
r = !strcmp(env[x], name);
*i = '=';
if(r)
return i + 1;
}
return NULL;
}
/* ---------------------------- util_env_copy ----------------------------- */
NSAPI_PUBLIC char **util_env_copy(char **src, char **dst)
{
char **src_ptr;
int src_cnt;
int index;
if (!src)
return NULL;
for (src_cnt = 0, src_ptr = src; *src_ptr; src_ptr++, src_cnt++);
if (!src_cnt)
return NULL;
dst = util_env_create(dst, src_cnt, &index);
for (src_ptr = src, index=0; *src_ptr; index++, src_ptr++)
dst[index] = STRDUP(*src_ptr);
dst[index] = NULL;
return dst;
}
/* ---------------------------- util_hostname ----------------------------- */
/*
* MOVED TO NET.C TO AVOID INTERDEPENDENCIES
*/
/* --------------------------- util_chdir2path ---------------------------- */
NSAPI_PUBLIC int util_chdir2path(char *path)
{
/* use FILE_PATHSEP to accomodate WIN32 */
char *t = strrchr(path, FILE_PATHSEP);
int ret;
if(!t)
return -1;
*t = '\0';
#ifdef XP_UNIX
ret = chdir(path);
#else /* WIN32 */
ret = SetCurrentDirectory(path);
#endif /* XP_UNIX */
/* use FILE_PATHSEP instead of chdir to accomodate WIN32 */
*t = FILE_PATHSEP;
return ret;
}
/* --------------------------- util_is_mozilla ---------------------------- */
NSAPI_PUBLIC int util_is_mozilla(char *ua, char *major, char *minor)
{
if((!ua) || strncasecmp(ua, "Mozilla/", 8))
return 0;
/* Major version. I punted on supporting versions like 10.0 */
if(ua[8] > major[0])
return 1;
else if((ua[8] < major[0]) || (ua[9] != '.'))
return 0;
/* Minor version. Support version numbers like 0.96 */
if(ua[10] < minor[0])
return 0;
else if((ua[10] > minor[0]) || (!minor[1]))
return 1;
if((!isdigit(ua[11])) || (ua[11] < minor[1]))
return 0;
else
return 1;
}
/* ----------------------------- util_is_url ------------------------------ */
#include <ctype.h> /* isalpha */
NSAPI_PUBLIC int util_is_url(char *url)
{
char *t = url;
while(*t) {
if(*t == ':')
return 1;
if(!isalpha(*t))
return 0;
++t;
}
return 0;
}
/* --------------------------- util_later_than ---------------------------- */
int _mstr2num(char *str) {
if(!strcasecmp(str, "Jan")) return 0;
if(!strcasecmp(str, "Feb")) return 1;
if(!strcasecmp(str, "Mar")) return 2;
if(!strcasecmp(str, "Apr")) return 3;
if(!strcasecmp(str, "May")) return 4;
if(!strcasecmp(str, "Jun")) return 5;
if(!strcasecmp(str, "Jul")) return 6;
if(!strcasecmp(str, "Aug")) return 7;
if(!strcasecmp(str, "Sep")) return 8;
if(!strcasecmp(str, "Oct")) return 9;
if(!strcasecmp(str, "Nov")) return 10;
if(!strcasecmp(str, "Dec")) return 11;
return -1;
}
int _time_compare(struct tm *lms, char *ims, int later_than_op)
{
int y = 0, mnum = 0, d = 0, h = 0, m = 0, s = 0, x;
char t[128];
/* Supported formats start with weekday (which we don't care about) */
/* The sizeof(t) is to avoid buffer overflow with t */
if((!(ims = strchr(ims,' '))) || (strlen(ims) > (sizeof(t) - 2)))
return 0;
while(*ims && isspace(*ims)) ++ims;
if((!(*ims)) || (strlen(ims) < 2))
return 0;
/* Standard HTTP (RFC 850) starts with dd-mon-yy */
if(ims[2] == '-') {
/* Warning - hardcoded 128 is sizeof(t) - scanf is not security conscious */
sscanf(ims, "%128s %d:%d:%d", t, &h, &m, &s);
t[sizeof(t)-1] = 0;
if(strlen(t) < 6)
return 0;
t[2] = '\0';
t[6] = '\0';
d = atoi(t);
mnum = _mstr2num(&t[3]);
x = atoi(&t[7]);
/* Postpone wraparound until 2070 */
y = x + (x < 70 ? 2000 : 1900);
}
/* The ctime format starts with a month name */
else if(isalpha(*ims)) {
/* Warning - hardcoded 128 is sizeof(t) - scanf is not security conscious */
sscanf(ims,"%128s %d %d:%d:%d %*s %d", t, &d, &h, &m,
&s, &y);
t[sizeof(t)-1] = 0;
mnum = _mstr2num(t);
}
/* RFC 822 */
else {
/* Warning - hardcoded 128 is sizeof(t) - scanf is not security conscious */
sscanf(ims, "%d %128s %d %d:%d:%d", &d, t, &y, &h, &m,
&s);
t[sizeof(t)-1] = 0;
mnum = _mstr2num(t);
}
if (later_than_op) {
if( (x = (1900 + lms->tm_year) - y) )
return x < 0;
if(mnum == -1)
return 0;
/* XXXMB - this will fail if you check if december 31 1996 is later
* than january 1 1997
*/
if((x = lms->tm_mon - mnum) || (x = lms->tm_mday - d) ||
(x = lms->tm_hour - h) || (x = lms->tm_min - m) ||
(x = lms->tm_sec - s))
return x < 0;
return 1;
}
else {
return (mnum != -1 &&
1900 + lms->tm_year == y &&
lms->tm_mon == mnum &&
lms->tm_mday == d &&
lms->tm_hour == h &&
lms->tm_min == m &&
lms->tm_sec == s);
}
}
/* Returns 0 if lms later than ims
* Returns 1 if equal
* Returns 1 if ims later than lms
*/
NSAPI_PUBLIC int util_later_than(struct tm *lms, char *ims)
{
return _time_compare(lms, ims, 1);
}
NSAPI_PUBLIC int util_time_equal(struct tm *lms, char *ims)
{
return _time_compare(lms, ims, 0);
}
/* util_str_time_equal()
*
* Function to compare if two time strings are equal
*
* Acceptible date formats:
* Saturday, 17-Feb-96 19:41:34 GMT <RFC850>
* Sat, 17 Mar 1996 19:41:34 GMT <RFC1123>
*
* Argument t1 MUST be RFC1123 format.
*
* Note- it is not the intention of this routine to *always* match
* There are cases where we would return != when the strings might
* be equal (especially with case). The converse should not be true.
*
* Return 0 if equal, -1 if not equal.
*/
#define MINIMUM_LENGTH 18
#define RFC1123_DAY 5
#define RFC1123_MONTH 8
#define RFC1123_YEAR 12
#define RFC1123_HOUR 17
#define RFC1123_MINUTE 20
#define RFC1123_SECOND 23
NSAPI_PUBLIC int util_str_time_equal(char *t1, char *t2)
{
int index;
/* skip over leading whitespace... */
while(*t1 && isspace(*t1)) ++t1;
while(*t2 && isspace(*t2)) ++t2;
/* Check weekday */
if ( (t1[0] != t2[0]) || (t1[1] != t2[1]) )
return -1;
/* Skip to date */
while(*t2 && !isspace(*t2)) ++t2;
t2++;
/* skip if not strings not long enough */
if ( (strlen(t1) < MINIMUM_LENGTH) || (strlen(t2) < MINIMUM_LENGTH) )
return -1;
if ( (t1[RFC1123_DAY] != t2[0]) || (t1[RFC1123_DAY+1] != t2[1]) )
return -1;
/* Skip to the month */
t2 += 3;
if ( (t1[RFC1123_MONTH] != t2[0]) || (t1[RFC1123_MONTH+1] != t2[1]) ||
(t1[RFC1123_MONTH+2] != t2[2]) )
return -1;
/* Skip to year */
t2 += 4;
if ( (t1[RFC1123_YEAR] != t2[0]) ) {
/* Assume t2 is RFC 850 format */
if ( (t1[RFC1123_YEAR+2] != t2[0]) || (t1[RFC1123_YEAR+3] != t2[1]) )
return -1;
/* skip to hour */
t2 += 3;
} else {
/* Assume t2 is RFC 1123 format */
if ( (t1[RFC1123_YEAR+1] != t2[1]) || (t1[RFC1123_YEAR+2] != t2[2]) ||
(t1[RFC1123_YEAR+3] != t2[3]) )
return -1;
/* skip to hour */
t2 += 5;
}
/* check date */
for (index=0; index<8; index++) {
if ( t1[RFC1123_HOUR+index] != t2[index] )
return -1;
}
/* Ignore timezone */
return 0;
}
/* --------------------------- util_uri_is_evil --------------------------- */
NSAPI_PUBLIC int util_uri_is_evil(char *t)
{
register int x;
for(x = 0; t[x]; ++x) {
if(t[x] == '/') {
if(t[x+1] == '/')
return 1;
if(t[x+1] == '.') {
switch(t[x+2]) {
case '.':
if((!t[x+3]) || (t[x+3] == '/'))
return 1;
case '/':
case '\0':
return 1;
}
}
}
#ifdef XP_WIN32
/* On NT, the directory "abc...." is the same as "abc"
* The only cheap way to catch this globally is to disallow
* names with the trailing "."s. Hopefully this is not over
* restrictive
*/
if ((t[x] == '.') && ( (t[x+1] == '/') || (t[x+1] ==
'\0') )) {
return 1;
}
#endif
}
return 0;
}
/* ---------------------------- util_uri_parse ---------------------------- */
NSAPI_PUBLIC void util_uri_parse(char *uri)
{
int spos = 0, tpos = 0;
int l = strlen(uri);
while(uri[spos]) {
if(uri[spos] == '/') {
if((spos != l) && (uri[spos+1] == '.')) {
if(uri[spos+2] == '/')
spos += 2;
else
if((spos <= (l-3)) &&
(uri[spos+2] == '.') && (uri[spos+3] ==
'/')) {
spos += 3;
while((tpos > 0) && (uri[--tpos] != '/'))
uri[tpos] = '\0';
} else
uri[tpos++] = uri[spos++];
} else {
if(uri[spos+1] != '/')
uri[tpos++] = uri[spos++];
else
spos++;
}
} else
uri[tpos++] = uri[spos++];
}
uri[tpos] = '\0';
}
/* -------------------- util_uri_unescape_and_normalize -------------------- */
#ifdef XP_WIN32
/* The server calls this function to unescape the URI and also normalize
* the uri. Normalizing the uri converts all "\" characters in the URI
* and pathinfo portion to "/". Does not touch "\" in query strings.
*/
void util_uri_unescape_and_normalize(char *s)
{
char *t, *u;
for(t = s, u = s; *t; ++t, ++u) {
if((*t == '%') && t[1] && t[2]) {
*u = ((t[1] >= 'A' ? ((t[1] & 0xdf) - 'A')+10 : (t[1] -
'0'))*16) +
(t[2] >= 'A' ? ((t[2] & 0xdf) - 'A')+10 : (t[2] -
'0'));
t += 2;
}
else
if(u != t)
*u = *t;
if (*u == '\\') /* normalize */
*u = '/';
}
*u = *t;
}
#endif /* XP_WIN32 */
/* -------------------------- util_uri_unescape --------------------------- */
NSAPI_PUBLIC void util_uri_unescape(char *s)
{
char *t, *u;
for(t = s, u = s; *t; ++t, ++u) {
if((*t == '%') && t[1] && t[2]) {
*u = ((t[1] >= 'A' ? ((t[1] & 0xdf) - 'A')+10 : (t[1] -
'0'))*16) +
(t[2] >= 'A' ? ((t[2] & 0xdf) - 'A')+10 : (t[2] -
'0'));
t += 2;
}
else
if(u != t)
*u = *t;
}
*u = *t;
}
/* --------------------------- util_uri_escape ---------------------------- */
NSAPI_PUBLIC char *util_uri_escape(char *od, char *s)
{
char *d;
if(!od)
od = (char *) MALLOC((strlen(s)*3) + 1);
d = od;
while(*s) {
if(strchr("% ?#:+&*\"<>\r\n", *s)) {
sprintf(d, "%%%2x", *s);
++s; d += 3;
}
else
*d++ = *s++;
}
*d = '\0';
return od;
}
/* --------------------------- util_url_escape ---------------------------- */
NSAPI_PUBLIC char *util_url_escape(char *od, char *s)
{
char *d;
if(!od)
od = (char *) MALLOC((strlen(s)*3) + 1);
d = od;
while(*s) {
if(strchr("% +*\"<>\r\n", *s)) {
sprintf(d, "%%%.2x", *s);
++s; d += 3;
}
else
*d++ = *s++;
}
*d = '\0';
return od;
}
/* ------------------------- util_mime_separator -------------------------- */
NSAPI_PUBLIC int util_mime_separator(char *sep)
{
srand(time(NULL));
return util_sprintf(sep, "%c%c--%d%d%d", CR, LF, rand(), rand(), rand());
}
/* ------------------------------ util_itoa ------------------------------- */
/*
* Assumption: Reversing the digits will be faster in the general case
* than doing a log10 or some nasty trick to find the # of digits.
*/
NSAPI_PUBLIC int util_itoa(int i, char *a)
{
register int x, y, p;
register char c;
int negative;
negative = 0;
if(i < 0) {
*a++ = '-';
negative = 1;
i = -i;
}
p = 0;
while(i > 9) {
a[p++] = (i%10) + '0';
i /= 10;
}
a[p++] = i + '0';
if(p > 1) {
for(x = 0, y = p - 1; x < y; ++x, --y) {
c = a[x];
a[x] = a[y];
a[y] = c;
}
}
a[p] = '\0';
return p + negative;
}
/* ----------------------------- util_sprintf ----------------------------- */
#include "prprf.h"
/*
XXXrobm the NSPR interfaces don't allow me to just pass in a buffer
without a size
*/
#define UTIL_PRF_MAXSIZE 1048576
NSAPI_PUBLIC int util_vsnprintf(char *s, int n, register const char *fmt,
va_list args)
{
return PR_vsnprintf(s, n, fmt, args);
}
NSAPI_PUBLIC int util_snprintf(char *s, int n, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
return PR_vsnprintf(s, n, fmt, args);
}
NSAPI_PUBLIC int util_vsprintf(char *s, register const char *fmt, va_list args)
{
return PR_vsnprintf(s, UTIL_PRF_MAXSIZE, fmt, args);
}
NSAPI_PUBLIC int util_sprintf(char *s, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
return PR_vsnprintf(s, UTIL_PRF_MAXSIZE, fmt, args);
}
/* ---------------------------- util_sh_escape ---------------------------- */
NSAPI_PUBLIC char *util_sh_escape(char *s)
{
char *ns = (char *) MALLOC(strlen(s) * 2 + 1); /* worst case */
register char *t, *u;
for(t = s, u = ns; *t; ++t, ++u) {
if(strchr("&;`'\"|*?~<>^()[]{}$\\ #!", *t))
*u++ = '\\';
*u = *t;
}
*u = '\0';
return ns;
}
/* --------------------------- util_strcasecmp ---------------------------- */
#ifdef NEED_STRCASECMP
/* These are stolen from mcom/lib/xp */
NSAPI_PUBLIC
int util_strcasecmp(CASECMPARG_T char *one, CASECMPARG_T char *two)
{
CASECMPARG_T char *pA;
CASECMPARG_T char *pB;
for(pA=one, pB=two; *pA && *pB; pA++, pB++)
{
int tmp = tolower(*pA) - tolower(*pB);
if (tmp)
return tmp;
}
if (*pA)
return 1;
if (*pB)
return -1;
return 0;
}
#endif /* NEED_STRCASECMP */
#ifdef NEED_STRNCASECMP
NSAPI_PUBLIC
int util_strncasecmp(CASECMPARG_T char *one, CASECMPARG_T char *two, int n)
{
CASECMPARG_T char *pA;
CASECMPARG_T char *pB;
for(pA=one, pB=two;; pA++, pB++)
{
int tmp;
if (pA == one+n)
return 0;
if (!(*pA && *pB))
return *pA - *pB;
tmp = tolower(*pA) - tolower(*pB);
if (tmp)
return tmp;
}
}
#endif /* NEED_STRNCASECMP */
#ifdef XP_WIN32
/* util_delete_directory()
* This routine deletes all the files in a directory. If delete_directory is
* TRUE it will also delete the directory itself.
*/
VOID
util_delete_directory(char *FileName, BOOL delete_directory)
{
HANDLE firstFile;
WIN32_FIND_DATA findData;
char *TmpFile, *NewFile;
if (FileName == NULL)
return;
TmpFile = (char *)MALLOC(strlen(FileName) + 5);
sprintf(TmpFile, "%s\\*.*", FileName);
firstFile = FindFirstFile(TmpFile, &findData);
FREE(TmpFile);
if (firstFile == INVALID_HANDLE_VALUE)
return;
if(strcmp(findData.cFileName, ".") &&
strcmp(findData.cFileName, "..")) {
NewFile = (char *)MALLOC(strlen(FileName) + 1 +
strlen(findData.cFileName) + 1);
sprintf(NewFile, "%s\\%s",FileName, findData.cFileName);
DeleteFile(NewFile);
FREE(NewFile);
}
while (TRUE) {
if(!(FindNextFile(firstFile, &findData))) {
if (GetLastError() != ERROR_NO_MORE_FILES) {
// ereport(LOG_WARN, XP_GetAdminStr(DBT_couldNotRemoveTemporaryDirectory_),
FileName, GetLastError());
} else {
FindClose(firstFile);
if (delete_directory)
if(!RemoveDirectory(FileName)) {
// ereport(LOG_WARN,
XP_GetAdminStr(DBT_couldNotRemoveTemporaryDirectory_1),
FileName, GetLastError());
}
return;
}
} else {
if(strcmp(findData.cFileName, ".") &&
strcmp(findData.cFileName, "..")) {
NewFile = (char *)MALLOC(strlen(FileName) + 5 +
strlen(findData.cFileName) + 1);
sprintf(NewFile,"%s\\%s", FileName, findData.cFileName);
DeleteFile(NewFile);
FREE(NewFile);
}
}
}
}
#endif
/* ------------------------------ util_strftime --------------------------- */
/*
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "(a)(#)strftime.c 5.11 (Berkeley) 2/24/91";
#endif /* LIBC_SCCS and not lint */
#ifdef XP_UNIX
#include <sys/types.h>
#include <sys/time.h>
#include <string.h>
#include <stdio.h>
#endif
static char *afmt[] = {
"Sun", "Mon", "Tue", "Wed", "Thu",
"Fri", "Sat",
};
static char *Afmt[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday",
"Saturday",
};
static char *bfmt[] = {
"Jan", "Feb", "Mar", "Apr", "May",
"Jun", "Jul", "Aug", "Sep",
"Oct", "Nov", "Dec",
};
static char *Bfmt[] = {
"January", "February", "March", "April",
"May", "June", "July",
"August", "September", "October", "November",
"December",
};
#define TM_YEAR_BASE 1900
static void _util_strftime_conv(char *, int, int, char);
#define _util_strftime_add(str) for (;(*pt = *str++); pt++);
#define _util_strftime_copy(str, len) memcpy(pt, str, len); pt += len;
#define _util_strftime_fmt util_strftime
/* util_strftime()
* This is an optimized version of strftime for speed. Avoids the thread
* unsafeness of BSD strftime calls.
*/
int
util_strftime(char *pt, const char *format, const struct tm *t)
{
char *start = pt;
char *scrap;
for (; *format; ++format) {
if (*format == '%')
switch(*++format) {
case 'a': /* abbreviated weekday name */
*pt++ = afmt[t->tm_wday][0];
*pt++ = afmt[t->tm_wday][1];
*pt++ = afmt[t->tm_wday][2];
continue;
case 'd': /* day of month */
_util_strftime_conv(pt, t->tm_mday, 2, '0');
pt += 2;
continue;
case 'S':
_util_strftime_conv(pt, t->tm_sec, 2, '0');
pt += 2;
continue;
case 'M':
_util_strftime_conv(pt, t->tm_min, 2, '0');
pt += 2;
continue;
case 'H':
_util_strftime_conv(pt, t->tm_hour, 2, '0');
pt += 2;
continue;
case 'Y':
if (t->tm_year < 100) {
*pt++ = '1';
*pt++ = '9';
_util_strftime_conv(pt, t->tm_year, 2, '0');
} else {
/* will fail after 2100; but who cares? */
*pt++ = '2';
*pt++ = '0';
_util_strftime_conv(pt, t->tm_year-100, 2, '0');
}
pt += 2;
continue;
case 'b': /* abbreviated month name */
case 'h':
*pt++ = bfmt[t->tm_mon][0];
*pt++ = bfmt[t->tm_mon][1];
*pt++ = bfmt[t->tm_mon][2];
continue;
case 'T':
case 'X':
pt += _util_strftime_fmt(pt, "%H:%M:%S", t);
continue;
case '\0':
--format;
break;
case 'A':
if (t->tm_wday < 0 || t->tm_wday > 6)
return(0);
scrap = Afmt[t->tm_wday];
_util_strftime_add(scrap);
continue;
case 'B':
if (t->tm_mon < 0 || t->tm_mon > 11)
return(0);
scrap = Bfmt[t->tm_mon];
_util_strftime_add(scrap);
continue;
case 'C':
pt += _util_strftime_fmt(pt, "%a %b %e %H:%M:%S %Y", t);
continue;
case 'c':
pt += _util_strftime_fmt(pt, "%m/%d/%y %H:%M:%S", t);
continue;
case 'D':
pt += _util_strftime_fmt(pt, "%m/%d/%y", t);
continue;
case 'e':
_util_strftime_conv(pt, t->tm_mday, 2, ' ');
pt += 2;
continue;
case 'I':
_util_strftime_conv(pt, t->tm_hour % 12 ?
t->tm_hour % 12 : 12, 2, '0');
pt += 2;
continue;
case 'j':
_util_strftime_conv(pt, t->tm_yday + 1, 3, '0');
pt += 3;
continue;
case 'k':
_util_strftime_conv(pt, t->tm_hour, 2, ' ');
pt += 2;
continue;
case 'l':
_util_strftime_conv(pt, t->tm_hour % 12 ?
t->tm_hour % 12 : 12, 2, ' ');
pt += 2;
continue;
case 'm':
_util_strftime_conv(pt, t->tm_mon + 1, 2, '0');
pt += 2;
continue;
case 'n':
*pt = '\n';
pt++;
continue;
case 'p':
if (t->tm_hour >= 12) {
*pt = 'P';
pt++;
} else {
*pt = 'A';
pt++;
}
*pt = 'M';
pt++;
continue;
case 'R':
pt += _util_strftime_fmt(pt, "%H:%M", t);
continue;
case 'r':
pt += _util_strftime_fmt(pt, "%I:%M:%S %p", t);
continue;
case 't':
*pt = '\t';
pt++;
continue;
case 'U':
_util_strftime_conv(pt, (t->tm_yday + 7 - t->tm_wday) / 7,
2, '0');
pt += 2;
continue;
case 'W':
_util_strftime_conv(pt, (t->tm_yday + 7 -
(t->tm_wday ? (t->tm_wday - 1) : 6))
/ 7, 2, '0');
pt += 2;
continue;
case 'w':
_util_strftime_conv(pt, t->tm_wday, 1, '0');
pt += 1;
continue;
case 'x':
pt += _util_strftime_fmt(pt, "%m/%d/%y", t);
continue;
case 'y':
_util_strftime_conv(pt, (t->tm_year + TM_YEAR_BASE)
% 100, 2, '0');
pt += 2;
continue;
case '%':
/*
* X311J/88-090 (4.12.3.5): if conversion char is
* undefined, behavior is undefined. Print out the
* character itself as printf(3) does.
*/
default:
break;
}
*pt = *format;
pt++;
}
start[pt-start] = '\0';
return pt - start;
}
static void
_util_strftime_conv(char *pt, int n, int digits, char pad)
{
static char buf[10];
register char *p;
if (n >= 100) {
p = buf + sizeof(buf)-2;
for (; n > 0 && p > buf; n /= 10, --digits)
*p-- = n % 10 + '0';
while (p > buf && digits-- > 0)
*p-- = pad;
p++;
_util_strftime_add(p);
} else {
int tens;
int ones = n;
tens = 0;
if ( ones >= 10 ) {
while ( ones >= 10 ) {
tens++;
ones = ones - 10;
}
*pt++ = '0'+tens;
digits--;
}
else
*pt++ = '0';
*pt++ = '0'+ones;
digits--;
while(digits--)
*pt++ = pad;
}
return;
}
#ifdef XP_UNIX
/*
* Local Thread Safe version of waitpid. This prevents the process
* from blocking in the system call.
*/
NSAPI_PUBLIC pid_t
util_waitpid(pid_t pid, int *statptr, int options)
{
pid_t rv;
for(rv = 0; !rv; PR_Sleep(500)) {
rv = waitpid(pid, statptr, options | WNOHANG);
if (rv == -1) {
if (errno == EINTR)
rv = 0; /* sleep and try again */
else
// ereport(LOG_WARN, "waitpid failed for pid %d:%s", pid, system_errmsg());
;
}
}
return rv;
}
#endif
/*
* Various reentrant routines by mikep. See util.h and systems.h
*/
/*
* These are only necessary if we turn on interrupts in NSPR
*/
#ifdef NEED_RELOCKS
#include "crit.h"
#define RE_LOCK(name) \
static CRITICAL name##_crit = 0; \
if (name##_crit == 0) name##_crit = crit_init(); \
crit_enter(name##_crit)
#define RE_UNLOCK(name) crit_exit(name##_crit)
#else
#define RE_LOCK(name) /* nada */
#define RE_UNLOCK(name) /* nil */
#endif
NSAPI_PUBLIC char *
util_strtok(register char *s,
register const char *delim,
register char **lasts)
{
#ifdef HAVE_STRTOK_R
return strtok_r(s, delim, lasts);
#else
/*
* THIS IS THE THREAD SAFE VERSION OF strtok captured from
* public NetBSD. Note that no locks are needed
*/
register char *spanp;
register int c, sc;
char *tok;
if (s == NULL && (s = *lasts) == NULL)
return (NULL);
/*
* Skip (span) leading delimiters (s += strspn(s, delim),
* sort of).
*/
cont:
c = *s++;
for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
if (c == sc)
goto cont;
}
if (c == 0) { /* no non-delimiter characters */
*lasts = NULL;
return (NULL);
}
tok = s - 1;
/*
* Scan token (scan for delimiters: s += strcspn(s, delim),
* sort of).
* Note that delim must have one NUL; we stop if we see that, too.
*/
for (;;) {
c = *s++;
spanp = (char *)delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
*lasts = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
#endif /* no strtok_r */
}
#ifndef XP_WIN32
NSAPI_PUBLIC struct passwd *
util_getpwnam(const char *name, struct passwd *result, char *buffer,
int buflen)
{
#ifdef HAVE_PW_R
#ifdef AIX
#ifdef AIX4_3
return ((int)getpwnam_r(name, result, buffer, buflen, &result) == 0 ? result :
NULL);
#else
return ((int)getpwnam_r(name, result, buffer, buflen) == 0 ? result : NULL);
#endif
#else
return getpwnam_r(name, result, buffer, buflen);
#endif /* AIX */
#else
char *lastp;
struct passwd *r;
RE_LOCK(pw);
r = getpwnam(name);
if (!r)
return r;
result->pw_gid = r->pw_gid;
result->pw_uid = r->pw_uid;
/* Hope this buffer is long enough */
if (buffer)
util_snprintf(buffer, buflen, "%s:%s:%d:%d:%s:%s:%s", r->pw_name,
r->pw_passwd,
r->pw_uid, r->pw_gid, r->pw_gecos, r->pw_dir, r->pw_shell);
RE_UNLOCK(pw);
result->pw_name = util_strtok(buffer, ":", &lastp);
result->pw_passwd = util_strtok(NULL, ":", &lastp);
(void) util_strtok(NULL, ":", &lastp);
(void) util_strtok(NULL, ":", &lastp);
result->pw_gecos = util_strtok(NULL, ":", &lastp);
result->pw_dir = util_strtok(NULL, ":", &lastp);
result->pw_shell = util_strtok(NULL, ":", &lastp);
return result;
#endif
}
#endif
NSAPI_PUBLIC struct tm *
util_localtime(const time_t *clock, struct tm *res)
{
#ifdef HAVE_TIME_R
return localtime_r(clock, res);
#else
struct tm *rv;
time_t zero = 0x7fffffff;
RE_LOCK(localtime);
RE_UNLOCK(localtime);
rv = localtime(clock);
if (!rv)
rv = localtime(&zero);
if (rv)
*res = *rv;
else
return NULL;
return res;
#endif
}
NSAPI_PUBLIC char *
util_ctime(const time_t *clock, char *buf, int buflen)
{
/*
* From cgi-src/restore.c refering to XP_WIN32:
* MLM - gross, but it works, better now FLC
*/
#if !defined(HAVE_TIME_R) || defined(XP_WIN32)
RE_LOCK(ctime);
strncpy(buf, ctime(clock), buflen);
buf[buflen - 1] = '\0';
RE_UNLOCK(ctime);
return buf;
#elif HAVE_TIME_R == 2
return ctime_r(clock, buf);
#else /* HAVE_TIME_R == 3 */
return ctime_r(clock, buf, buflen);
#endif
}
NSAPI_PUBLIC struct tm *
util_gmtime(const time_t *clock, struct tm *res)
{
#ifdef HAVE_TIME_R
return gmtime_r(clock, res);
#else
struct tm *rv;
time_t zero = 0x7fffffff;
RE_LOCK(gmtime);
rv = gmtime(clock);
RE_UNLOCK(gmtime);
if (!rv)
rv = gmtime(&zero);
if (rv)
*res = *rv;
else
return NULL;
return res;
#endif
}
NSAPI_PUBLIC char *
util_asctime(const struct tm *tm, char *buf, int buflen)
{
#if HAVE_TIME_R == 2
return asctime_r(tm, buf);
#elif HAVE_TIME_R == 3
return asctime_r(tm, buf, buflen);
#else
RE_LOCK(asctime);
strncpy(buf, asctime(tm), buflen);
buf[buflen - 1] = '\0';
RE_UNLOCK(asctime);
return buf;
#endif
}
NSAPI_PUBLIC char *
util_strerror(int errnum, char *msg, int buflen)
{
#ifdef HAVE_STRERROR_R
/* More IBM real-genius */
return ((int)strerror_r(errnum, msg, buflen) > 0) ? msg : NULL;
#else
/* RE_LOCK(strerror); I don't think this is worth the trouble */
(void)strncpy(msg, strerror(errnum), buflen);
msg[buflen - 1] = '\0';
return msg;
/* RE_UNLOCK(strerror); */
#endif
}
/* returns a malloc'd string */
static const char *
GetCurrentCharset(void)
{
static char *locale = NULL;
const char *charset;
if ( NULL == locale ) {
locale = setlocale(LC_CTYPE, ""); /* need to call this once */
}
charset = nl_langinfo( CODESET );
if ( NULL == charset || '\0' == *charset ) {
charset = UTIL_CHARSET_DEFAULT;
}
return strdup( charset );
}
#ifdef _WIN32
static char *
convertor( const char *src, int fromUtf8 )
{
return win_char_converter( src, fromUtf8 );
}
#else /* _WIN32 */
static char *
convertor( const char *src, int fromUtf8 )
{
const char *src_charset = NULL;
iconv_t convdesc;
char *outbuf, *curoutbuf;
size_t inbytesleft, outbytesleft;
src_charset = GetCurrentCharset();
if (0 == strcasecmp(src_charset, UTIL_CHARSET_UTF8))
{
outbuf = strdup(src);
if ( NULL == outbuf )
{
perror( "convert_to_utf8 - strdup" );
}
return outbuf;
}
/* Get a converter */
if (fromUtf8) {
convdesc = iconv_open( src_charset, UTIL_CHARSET_UTF8 );
} else {
convdesc = iconv_open( UTIL_CHARSET_UTF8, src_charset );
}
if ( (iconv_t)-1 == convdesc ) {
if ( errno == EINVAL ) {
fprintf( stderr, "%s: conversion from %s to %s is not supported\n",
"convertor", src_charset, UTIL_CHARSET_UTF8 );
} else {
perror( src_charset );
}
return NULL;
}
/* Allocate room for the UTF-8 equivalent (maximum expansion = 6 times) */
/* XXX is that correct? */
inbytesleft = strlen( src );
outbytesleft = 6 * inbytesleft + 1;
if ( NULL == ( outbuf = (char *)malloc( outbytesleft ))) {
perror( "convert_to_utf8 - malloc" );
iconv_close( convdesc );
return NULL;
}
curoutbuf = outbuf;
/*
* Three steps for a good conversion:
* 1) Insert the initial shift sequence if any.
* 2) Convert our characters.
* 3) Insert the closing shift sequence, if any.
*/
if ( (size_t)-1 == iconv( convdesc, NULL, NULL,
&curoutbuf, &outbytesleft ) /* initial shift seq. */
#ifdef LINUX
|| (size_t)-1 == iconv( convdesc, (char **)&src, &inbytesleft,
&curoutbuf, &outbytesleft ) /* convert our chars. */
#else
|| (size_t)-1 == iconv( convdesc, &src, &inbytesleft,
&curoutbuf, &outbytesleft ) /* convert our chars. */
#endif
|| (size_t)-1 == iconv( convdesc, NULL, NULL,
&curoutbuf, &outbytesleft )) { /* closing shift seq. */
perror( "convert_to_utf8 - iconv" );
iconv_close( convdesc );
return NULL;
}
*curoutbuf = '\0'; /* zero-terminate the resulting string */
return outbuf;
}
#endif /* else _WIN32 */
#ifdef _WIN32
/* returns a malloc'd string */
static char *
win_char_converter(const char *instr, int bFromUTF8)
{
char *outstr = NULL;
int inlen, wclen, outlen;
LPWSTR wcstr;
if (instr == NULL)
return NULL;
if ((inlen = strlen(instr)) <= 0)
return NULL;
/* output never becomes longer than input, XXXmcs: really true?
** thus we don't have to ask for the length
*/
wcstr = (LPWSTR) malloc( sizeof( WCHAR ) * (inlen+1) );
if (!wcstr)
return NULL;
wclen = MultiByteToWideChar(bFromUTF8 ? CP_UTF8 : CP_ACP, 0, instr,
inlen, wcstr, inlen);
outlen = WideCharToMultiByte(bFromUTF8 ? CP_ACP : CP_UTF8, 0, wcstr,
wclen, NULL, 0, NULL, NULL);
if (outlen > 0) {
outstr = (char *) malloc(outlen + 2);
outlen = WideCharToMultiByte(bFromUTF8 ? CP_ACP : CP_UTF8, 0, wcstr,
wclen, outstr, outlen, NULL, NULL);
if (outlen > 0)
*(outstr+outlen) = _T('\0');
else
return NULL;
}
free( wcstr );
return outstr;
}
#endif /* _WIN32 */
#ifdef __cplusplus
extern "C" {
#endif
NSAPI_PUBLIC char *
util_local_to_utf8(const char *src)
{
char *utf8;
if ( src == NULL ) { /* trivial case # 1 */
utf8 = NULL;
} else if ( *src == '\0' ) { /* trivial case # 2 */
utf8 = strdup( "" );
} else {
utf8 = convertor( src, 0 ); /* the real deal */
if ( utf8 == NULL ) {
utf8 = strdup ( src );
}
}
return utf8;
}
#ifdef __cplusplus
}
#endif
Index: Makefile
===================================================================
RCS file: /cvs/dirsec/adminserver/lib/base/Makefile,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -r1.7 -r1.8
--- Makefile 29 Sep 2005 22:12:04 -0000 1.7
+++ Makefile 24 Jul 2006 12:51:11 -0000 1.8
@@ -52,7 +52,7 @@
endif
OBJS = $(addprefix $(OBJDEST)/, \
- util.o \
+ nscputil.o \
file.o \
system.o \
nscperror.o \