516 lines
8.8 KiB
C++
516 lines
8.8 KiB
C++
/*
|
|
* fptools.c, some helper functions for getcgi.c and uu(en|de)view
|
|
*
|
|
* Distributed under the terms of the GNU General Public License.
|
|
* Use and be happy.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#ifdef SYSTEM_WINDLL
|
|
#include <windows.h>
|
|
#endif
|
|
#ifdef SYSTEM_OS2
|
|
#include <os2.h>
|
|
#endif
|
|
|
|
/*
|
|
* This file provides replacements for some handy functions that aren't
|
|
* available on all systems, like most of the <string.h> functions. They
|
|
* should behave exactly as their counterparts. There are also extensions
|
|
* that aren't portable at all (like strirstr etc.).
|
|
* The proper behaviour in a configure script is as follows:
|
|
* AC_CHECK_FUNC(strrchr,AC_DEFINE(strrchr,_FP_strrchr))
|
|
* This way, the (probably less efficient) replacements will only be used
|
|
* where it is not provided by the default libraries. Be aware that this
|
|
* does not work with replacements that just shadow wrong behaviour (like
|
|
* _FP_free) or provide extended functionality (_FP_gets).
|
|
* The above is not used in the uuenview/uudeview configuration script,
|
|
* since both only use the replacement functions in non-performance-cri-
|
|
* tical sections (except for _FP_tempnam and _FP_strerror, where some
|
|
* functionality of the original would be lost).
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#ifdef STDC_HEADERS
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#endif
|
|
#ifdef HAVE_MALLOC_H
|
|
#include <malloc.h>
|
|
#endif
|
|
#ifdef HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
#ifdef HAVE_MEMORY_H
|
|
#include <memory.h>
|
|
#endif
|
|
|
|
#include <gdefs.h>
|
|
#include <gctype.h>
|
|
#include <gfilutil.h>
|
|
#include <fptools.h>
|
|
|
|
#if 0
|
|
#ifdef SYSTEM_WINDLL
|
|
BOOL _export WINAPI
|
|
DllEntryPoint (HINSTANCE hInstance, DWORD seginfo,
|
|
LPVOID lpCmdLine)
|
|
{
|
|
/* Don't do anything, so just return true */
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
char * fptools_id = "$Id$";
|
|
|
|
/*
|
|
* some versions of free can't handle a NULL pointer properly
|
|
* (ANSI says, free ignores a NULL pointer, but some machines
|
|
* prefer to SIGSEGV on it)
|
|
*/
|
|
|
|
void TOOLEXPORT
|
|
_FP_free (void *ptr)
|
|
{
|
|
if (ptr) free (ptr);
|
|
}
|
|
|
|
/*
|
|
* This is non-standard, so I'm defining my own
|
|
*/
|
|
|
|
char * TOOLEXPORT
|
|
_FP_strdup (char *string)
|
|
{
|
|
char *result;
|
|
|
|
if (string == NULL)
|
|
return NULL;
|
|
|
|
if ((result = (char *) malloc (strlen (string) + 1)) == NULL)
|
|
return NULL;
|
|
|
|
strcpy (result, string);
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* limited-length string copy. this function behaves differently from
|
|
* the original in that the dest string is always terminated with a
|
|
* NULL character.
|
|
*/
|
|
|
|
char * TOOLEXPORT
|
|
_FP_strncpy (char *dest, char *src, int length)
|
|
{
|
|
char *odest=dest;
|
|
if (src == NULL || dest == NULL || length-- <= 0)
|
|
return dest;
|
|
|
|
while (length-- && *src)
|
|
*dest++ = *src++;
|
|
|
|
*dest++ = '\0';
|
|
return odest;
|
|
}
|
|
|
|
/*
|
|
* duplicate a memory area
|
|
*/
|
|
|
|
void * TOOLEXPORT
|
|
_FP_memdup (void *ptr, int len)
|
|
{
|
|
void *result;
|
|
|
|
if (ptr == NULL)
|
|
return NULL;
|
|
|
|
if ((result = malloc (len)) == NULL)
|
|
return NULL;
|
|
|
|
memcpy (result, ptr, len);
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* case-insensitive compare
|
|
*/
|
|
|
|
int TOOLEXPORT
|
|
_FP_stricmp (char *str1, char *str2)
|
|
{
|
|
if (str1==NULL || str2==NULL)
|
|
return -1;
|
|
|
|
while (*str1) {
|
|
if (g_tolower(*str1) != g_tolower(*str2))
|
|
break;
|
|
str1++;
|
|
str2++;
|
|
}
|
|
return (g_tolower (*str1) - g_tolower (*str2));
|
|
}
|
|
|
|
int TOOLEXPORT
|
|
_FP_strnicmp (char *str1, char *str2, int count)
|
|
{
|
|
if (str1==NULL || str2==NULL)
|
|
return -1;
|
|
|
|
while (*str1 && count) {
|
|
if (g_tolower(*str1) != g_tolower(*str2))
|
|
break;
|
|
str1++;
|
|
str2++;
|
|
count--;
|
|
}
|
|
return count ? (g_tolower (*str1) - g_tolower (*str2)) : 0;
|
|
}
|
|
|
|
/*
|
|
* autoconf says this function might be a compatibility problem
|
|
*/
|
|
|
|
char * TOOLEXPORT
|
|
_FP_strstr (char *str1, char *str2)
|
|
{
|
|
char *ptr1, *ptr2;
|
|
|
|
if (str1==NULL)
|
|
return NULL;
|
|
if (str2==NULL)
|
|
return str1;
|
|
|
|
while (*(ptr1=str1)) {
|
|
for (ptr2=str2;
|
|
*ptr1 && *ptr2 && *ptr1==*ptr2;
|
|
ptr1++, ptr2++)
|
|
/* empty loop */ ;
|
|
|
|
if (*ptr2 == '\0')
|
|
return str1;
|
|
str1++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
char * TOOLEXPORT
|
|
_FP_strpbrk (char *str, char *accept)
|
|
{
|
|
char *ptr;
|
|
|
|
if (str == NULL)
|
|
return NULL;
|
|
if (accept == NULL || *accept == '\0')
|
|
return str;
|
|
|
|
for (; *str; str++)
|
|
for (ptr=accept; *ptr; ptr++)
|
|
if (*str == *ptr)
|
|
return str;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* autoconf also complains about this one
|
|
*/
|
|
|
|
char * TOOLEXPORT
|
|
_FP_strtok (char *str1, char *str2)
|
|
{
|
|
static char *optr;
|
|
char *ptr;
|
|
|
|
if (str2 == NULL)
|
|
return NULL;
|
|
|
|
if (str1) {
|
|
optr = str1;
|
|
}
|
|
else {
|
|
if (*optr == '\0')
|
|
return NULL;
|
|
}
|
|
|
|
while (*optr && strchr (str2, *optr)) /* look for beginning of token */
|
|
optr++;
|
|
|
|
if (*optr == '\0') /* no token found */
|
|
return NULL;
|
|
|
|
ptr = optr;
|
|
while (*optr && strchr (str2, *optr) == NULL) /* look for end of token */
|
|
optr++;
|
|
|
|
if (*optr) {
|
|
*optr++ = '\0';
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
/*
|
|
* case insensitive strstr.
|
|
*/
|
|
|
|
char * TOOLEXPORT
|
|
_FP_stristr (char *str1, char *str2)
|
|
{
|
|
char *ptr1, *ptr2;
|
|
|
|
if (str1==NULL)
|
|
return NULL;
|
|
if (str2==NULL)
|
|
return str1;
|
|
|
|
while (*(ptr1=str1)) {
|
|
for (ptr2=str2;
|
|
*ptr1 && *ptr2 && g_tolower(*ptr1)==g_tolower(*ptr2);
|
|
ptr1++, ptr2++)
|
|
/* empty loop */ ;
|
|
|
|
if (*ptr2 == '\0')
|
|
return str1;
|
|
str1++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Nice fake of the real (non-standard) one
|
|
*/
|
|
|
|
char * TOOLEXPORT
|
|
_FP_strrstr (char *ptr, char *str)
|
|
{
|
|
char *found=NULL, *pstr, *iter=ptr;
|
|
|
|
if (ptr==NULL || str==NULL)
|
|
return NULL;
|
|
|
|
if (*str == '\0')
|
|
return ptr;
|
|
|
|
while ((pstr = _FP_strstr (iter, str)) != NULL) {
|
|
found = pstr;
|
|
iter = pstr + 1;
|
|
}
|
|
return found;
|
|
}
|
|
|
|
char * TOOLEXPORT
|
|
_FP_strirstr (char *ptr, char *str)
|
|
{
|
|
char *found=NULL, *iter=ptr, *pstr;
|
|
|
|
if (ptr==NULL || str==NULL)
|
|
return NULL;
|
|
if (*str == '\0')
|
|
return ptr;
|
|
|
|
while ((pstr = _FP_stristr (iter, str)) != NULL) {
|
|
found = pstr;
|
|
iter = pstr + 1;
|
|
}
|
|
return found;
|
|
}
|
|
|
|
/*
|
|
* convert whole string to case
|
|
*/
|
|
|
|
char * TOOLEXPORT
|
|
_FP_stoupper (char *input)
|
|
{
|
|
char *iter = input;
|
|
|
|
if (input == NULL)
|
|
return NULL;
|
|
|
|
while (*iter) {
|
|
*iter = g_toupper (*iter);
|
|
iter++;
|
|
}
|
|
return input;
|
|
}
|
|
|
|
char * TOOLEXPORT
|
|
_FP_stolower (char *input)
|
|
{
|
|
char *iter = input;
|
|
|
|
if (input == NULL)
|
|
return NULL;
|
|
|
|
while (*iter) {
|
|
*iter = g_tolower (*iter);
|
|
iter++;
|
|
}
|
|
return input;
|
|
}
|
|
|
|
/*
|
|
* string matching with wildcards
|
|
*/
|
|
|
|
int TOOLEXPORT
|
|
_FP_strmatch (char *string, char *pattern)
|
|
{
|
|
char *p1 = string, *p2 = pattern;
|
|
|
|
if (pattern==NULL || string==NULL)
|
|
return 0;
|
|
|
|
while (*p1 && *p2) {
|
|
if (*p2 == '?') {
|
|
p1++; p2++;
|
|
}
|
|
else if (*p2 == '*') {
|
|
if (*++p2 == '\0')
|
|
return 1;
|
|
while (*p1 && *p1 != *p2)
|
|
p1++;
|
|
}
|
|
else if (*p1 == *p2) {
|
|
p1++; p2++;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
if (*p1 || *p2)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
char * TOOLEXPORT
|
|
_FP_strrchr (char *string, int tc)
|
|
{
|
|
char *ptr;
|
|
|
|
if (string == NULL)
|
|
return NULL;
|
|
|
|
ptr = string + strlen (string) - 1;
|
|
|
|
while (ptr != string && *ptr != tc)
|
|
ptr--;
|
|
|
|
if (*ptr == tc)
|
|
return ptr;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* strip directory information from a filename. Works only on DOS and
|
|
* Unix systems so far ...
|
|
*/
|
|
|
|
char * TOOLEXPORT
|
|
_FP_cutdir (char *filename)
|
|
{
|
|
char *ptr;
|
|
|
|
if (filename == NULL)
|
|
return NULL;
|
|
|
|
if ((ptr = _FP_strrchr (filename, GOLD_SLASH_CHR)) != NULL)
|
|
ptr++;
|
|
else if ((ptr = _FP_strrchr (filename, GOLD_WRONG_SLASH_CHR)) != NULL)
|
|
ptr++;
|
|
else
|
|
ptr = filename;
|
|
|
|
return ptr;
|
|
}
|
|
|
|
/*
|
|
* My own fgets function. It handles all kinds of line terminators
|
|
* properly: LF (Unix), CRLF (DOS) and CR (Mac). In all cases, the
|
|
* terminator is replaced by a single LF
|
|
*/
|
|
|
|
char * TOOLEXPORT
|
|
_FP_fgets (char *buf, int n, FILE *stream)
|
|
{
|
|
char *obp = buf;
|
|
int c;
|
|
|
|
if (feof (stream))
|
|
return NULL;
|
|
|
|
while (--n) {
|
|
if ((c = fgetc (stream)) == EOF) {
|
|
if (ferror (stream))
|
|
return NULL;
|
|
else {
|
|
if (obp == buf)
|
|
return NULL;
|
|
*buf = '\0';
|
|
return obp;
|
|
}
|
|
}
|
|
if (c == '\015') { /* CR */
|
|
/*
|
|
* Peek next character. If it's no LF, push it back.
|
|
* ungetc(EOF, stream) is handled correctly according
|
|
* to the manual page
|
|
*/
|
|
if ((c = fgetc (stream)) != '\012')
|
|
if (!feof (stream))
|
|
ungetc (c, stream);
|
|
*buf++ = '\012';
|
|
*buf = '\0';
|
|
return obp;
|
|
}
|
|
else if (c == '\012') { /* LF */
|
|
*buf++ = '\012';
|
|
*buf = '\0';
|
|
return obp;
|
|
}
|
|
/*
|
|
* just another standard character
|
|
*/
|
|
*buf++ = c;
|
|
}
|
|
/*
|
|
* n-1 characters already transferred
|
|
*/
|
|
*buf = '\0';
|
|
|
|
return obp;
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
* A replacement strerror function that just returns the error code
|
|
*/
|
|
|
|
char * TOOLEXPORT
|
|
_FP_strerror (int errcode)
|
|
{
|
|
static char number[8];
|
|
|
|
sprintf (number, "%03d", errcode);
|
|
|
|
return number;
|
|
}
|
|
|
|
/*
|
|
* tempnam is not ANSI, but tmpnam is. Ignore the prefix here.
|
|
*/
|
|
|
|
char * TOOLEXPORT
|
|
_FP_tempnam (char *dir, char *pfx)
|
|
{
|
|
return _FP_strdup (tmpnam (NULL));
|
|
}
|
|
#endif
|