summaryrefslogtreecommitdiffstats
path: root/lib/base/util.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/base/util.cpp')
-rw-r--r--lib/base/util.cpp1449
1 files changed, 1449 insertions, 0 deletions
diff --git a/lib/base/util.cpp b/lib/base/util.cpp
new file mode 100644
index 00000000..55d6ca56
--- /dev/null
+++ b/lib/base/util.cpp
@@ -0,0 +1,1449 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * util.c: A hodge podge of utility functions and standard functions which
+ * are unavailable on certain systems
+ *
+ * Rob McCool
+ */
+
+#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"
+#include "base/ereport.h"
+
+
+#ifdef XP_UNIX
+#include <sys/types.h>
+#endif /* WIN32 */
+
+/* ----------------------------- 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) {
+ i = filebuf_getc(buf);
+ switch(i) {
+ 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] == '-') {
+ sscanf(ims, "%s %d:%d:%d", t, &h, &m, &s);
+ 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)) {
+ sscanf(ims,"%s %d %d:%d:%d %*s %d", t, &d, &h, &m, &s, &y);
+ mnum = _mstr2num(t);
+ }
+ /* RFC 822 */
+ else {
+ sscanf(ims, "%d %s %d %d:%d:%d", &d, t, &y, &h, &m, &s);
+ 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[] = "@(#)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
+#if OSVERSION >= 4320
+ return ((int)getpwnam_r(name, result, buffer, buflen, 0) == 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
+}
+
+
+
+/* ------------------------------- OLD CODE ------------------------------- */
+
+
+#if 0
+
+NSAPI_PUBLIC int util_vsnprintf(char *s, int n, register char *fmt,
+ va_list args)
+{
+ register int pos = 0, max = (n > 2 ? n-2 : -1), boundson;
+ register char c, *t;
+
+ if((max == -1) && (n != -1))
+ goto punt;
+
+ boundson = (n != -1);
+ while(*fmt) {
+ if(boundson && (pos > max))
+ break;
+ c = *fmt++;
+ switch(c) {
+ case '%':
+ switch(*fmt++) {
+ case 'd':
+ if(boundson && ((pos + 10) > max))
+ goto punt;
+ pos += util_itoa(va_arg(args, int), &s[pos]);
+ break;
+ case 's':
+ t = va_arg(args, char *);
+ while(*t) {
+ s[pos++] = *t++;
+ if(boundson && (pos > max))
+ goto punt;
+ }
+ break;
+ case 'c':
+ s[pos++] = (char) va_arg(args, int);
+ break;
+ case '%':
+ s[pos++] = '%';
+ break;
+ }
+ break;
+ case '\\':
+ if( (s[pos++] = *fmt) )
+ ++fmt;
+ break;
+ default:
+ s[pos++] = c;
+ }
+ }
+ punt:
+ s[pos] = '\0';
+
+ va_end(args);
+ return pos;
+}
+
+NSAPI_PUBLIC int util_snprintf(char *s, int n, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ return util_vsnprintf(s, n, fmt, args);
+}
+
+NSAPI_PUBLIC int util_vsprintf(char *s, register char *fmt, va_list args)
+{
+ return util_vsnprintf(s, -1, fmt, args);
+}
+
+NSAPI_PUBLIC int util_sprintf(char *s, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ return util_vsnprintf(s, -1, fmt, args);
+}
+#endif