You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bforce/source/bforce/u_string.c

933 lines
19 KiB
C

/*
* binkleyforce -- unix FTN mailer project
*
* Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11
*
* 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.
*
* $Id$
*/
#ifndef TEST
#include "includes.h"
#include "confread.h"
#include "logger.h"
#include "util.h"
#else
#include <stdio.h>
#include <stdarg.h>
#define TRUE 1
#define FALSE 0
#define bool int
#define xmalloc malloc
#define xrealloc realloc
#define ASSERT
#endif
/*
* Maximum number of quoted-printable strings we will store together
*/
#define PRINTABLE_MAXITEMS 5
/*
* Cyclic buffer for quoted-printable strings
*/
static char *printable_storage[PRINTABLE_MAXITEMS];
/*
* Position of next entry to use in printable_storage[]
*/
static int printable_pos = -1;
/*****************************************************************************
* Allocate memory for the copy of a string pointed by src
*
* Arguments:
* src pointer to the null-terminated string
*
* Return value:
* Pointer to the resulting string (must be freed)
*/
char *xstrcpy(const char *src)
{
char *tmp;
if( !src )
return NULL;
tmp = xmalloc(strlen(src)+1);
strcpy(tmp, src);
return tmp;
}
/*****************************************************************************
* Append string pointed by add to the string src, allocate memory for result
*
* Arguments:
* src pointer to the null-terminated string (will be freed)
* add this one will be appended to the src
*
* Return value:
* Pointer to the resulting string (must be freed)
*/
char *xstrcat(char *src, const char *add)
{
char *tmp;
size_t size;
if( !add || *add == '\0' )
return src;
size = (src ? strlen(src) : 0) + strlen(add);
tmp = (char*)xmalloc(size+1);
if( src )
{
strcpy(tmp, src);
free(src);
} else
*tmp = '\0';
strcat(tmp, add);
return tmp;
}
/*****************************************************************************
* Copy a string to the buffer. Checks for the destination buffer overflow and
* terminating '\0' character.
*
* Arguments:
* dst pointer to the destination buffer
* src string to copy from
* len destination buffer size
*
* Return value:
* Pointer to the resulting string
*/
char *strnxcpy(char *dst, const char *src, size_t len)
{
ASSERT(src != NULL && dst != NULL && len >= 0);
dst[len - 1] = 0;
return strncpy(dst, src, len - 1);
}
/*****************************************************************************
* Add one string to the end of another. Checks for destination buffer
* overflow and terminating '\0' character.
*
* Arguments:
* dst pointer to the destination buffer (append to the string
* stored in it)
* src append this string
* len destination buffer size
*
* Return value:
* Pointer to the resulting string
*/
char *strnxcat(char *dst, const char *src, size_t len)
{
int pos;
ASSERT(src != NULL && dst != NULL && len >= 0);
pos = strlen(dst);
return strnxcpy(dst + pos, src, len - pos);
}
/*****************************************************************************
* Get next substring from the string.
*
* Arguments:
* str pointer to a null-terminated string
* next points to the pointer where you want store address of
* the next substring for next calls
* delim delimiter characters, if NULL than the isspace() call used
* to check for the delimiter characters
* quoted ignore spaces in the quoted substrings
*
* Return value:
* Pointer to the new substring or NULL if no more available
*/
char *string_token(char *str, char **next, const char *delim, int quoted)
{
char *yield;
char *p;
ASSERT(next != NULL);
yield = str ? str : *next;
if( yield )
{
if( delim && *delim )
while( *yield && strchr(delim, *yield) ) yield++;
else
while( isspace(*yield) ) yield++;
if( *yield )
{
if( quoted && *yield == '"' )
{
p = ++yield;
while( *p && *p != '"' ) p++;
}
else
{
p = yield;
if( delim && *delim )
while( *p && !strchr(delim, *p) ) p++;
else
while( *p && !isspace(*p) ) p++;
}
if( *p )
{
*p = '\0';
*next = p+1;
} else
*next = NULL;
} else
yield = *next = NULL;
}
return yield;
}
/*****************************************************************************
* Remove trailing CR and LF characters
*
* Arguments:
* str pointer to the null-terminated string
*
* Return value:
* Pointer to the string
*/
char *string_chomp(char *str)
{
char *p;
ASSERT(str != NULL);
if( str && *str )
{
p = str + strlen(str + 1);
if( *p == '\n' )
*p-- = '\0';
if( *p == '\r' && p >= str )
*p = '\0';
}
return str;
}
/*****************************************************************************
* Find the firtst occurance of substring into the string
*
* Arguments:
* substr pointer to the null-terminated substring
* string pointer to the null-terminated string
*
* Return value:
* Pointer to the first occurrence of the substring in the string,
* and NULL if substring is not found
*/
const char *string_casestr(const char *string, const char *substr)
{
size_t subln = strlen(substr);
size_t strln = strlen(string);
while( *string && strln >= subln )
{
if( !strncasecmp(substr, string, subln) )
return string;
++string;
--strln;
}
return NULL;
}
/*****************************************************************************
* Find character in the string (It is like strchr(), but case insensitive)
*
* Arguments:
* str pointer to the null-terminated string
* ch character you want to find
*
* Return value:
* Pointer to the first occurrence of the character in the string,
* and NULL if character is not found
*/
const char *string_casechr(const char *str, int ch)
{
ch = tolower(ch);
while( *str )
{
if( tolower(*str) == ch )
return str;
++str;
}
return NULL;
}
/*****************************************************************************
* Convert string to the upper case
*
* Arguments:
* str pointer to the null-terminated string
*
* Return value:
* Pointer to the string
*/
char *string_toupper(char *str)
{
char *p;
ASSERT(str != NULL);
for( p = str; *p; p++ ) *p = toupper(*p);
return(str);
}
/*****************************************************************************
* Convert string to the lower case
*
* Arguments:
* str pointer to the null-terminated string
*
* Return value:
* Pointer to the string
*/
char *string_tolower(char *str)
{
char *p;
ASSERT(str != NULL);
for( p = str; *p; p++ ) *p = tolower(*p);
return(str);
}
/*****************************************************************************
* Check wheather string doesn't contain lower case characters
*
* Arguments:
* str pointer to the null-terminated string
*
* Return value:
* Return TRUE if string conforms our requirements, and FALSE if not
*/
bool string_isupper(const char *str)
{
const char *p;
ASSERT(str != NULL);
for( p = str; *p; p++ )
{
if( isalpha(*p) && islower(*p) ) break;
}
return (*p == '\0') ? TRUE : FALSE;
}
/*****************************************************************************
* Check wheather string doesn't contain upper case characters
*
* Arguments:
* str pointer to the null-terminated string
*
* Return value:
* Return TRUE if string conforms our requirements, and FALSE if not
*/
bool string_islower(const char *str)
{
const char *p;
ASSERT(str != NULL);
for( p = str; *p; p++ )
{
if( isalpha(*p) && isupper(*p) ) break;
}
return (*p == '\0') ? TRUE : FALSE;
}
/*****************************************************************************
* Remove spaces at the end of string
*
* Arguments:
* str pointer to the null-terminated string
*
* Return value:
* Pointer to the string
*/
char *string_trimright(char *str)
{
char *p;
ASSERT(str != NULL);
if( str && *str )
{
p = str + strlen(str+1);
while( p >= str && isspace(*p) ) *p-- = '\0';
}
return str;
}
/*****************************************************************************
* Remove spaces at the begining of string
*
* Arguments:
* str pointer to the null-terminated string
*
* Return value:
* pointer to the string
*/
char *string_trimleft(char *str)
{
char *p;
ASSERT(str != NULL);
if( str && *str )
{
p = str;
while( isspace(*p) ) p++;
if( p > str )
memmove(str, p, strlen(p)+1);
}
return str;
}
/*****************************************************************************
* Remove white spaces at the begining and at the end of string
*
* Arguments:
* str pointer to the null-terminated string
*
* Return value:
* pointer to the string
*/
char *string_trimboth(char *str)
{
char *p;
ASSERT(str != NULL);
if( str && *str )
{
/* Remove leading spaces */
p = str;
while( isspace(*p) ) p++;
if( p > str )
memmove(str, p, strlen(p)+1);
/* Remove trailing spaces */
p = str + strlen(str+1);
while( p >= str && isspace(*p) ) *p-- = '\0';
}
return str;
}
/*****************************************************************************
* Quote all unprintable characters in the buffer (e.g. "\xff\xfe")
*
* Arguments:
* buffer pointer to the buffer to process
* buflen buffer size
*
* Return value:
* Pointer to the quoted-printable string (must be freed)
*/
char *string_printable_buffer(const char *buffer, size_t buflen)
{
char *dest, *p;
const char *bp;
int nonprintcount = 0;
size_t pos = 0;
for( bp = buffer, pos = 0; pos < buflen; bp++, pos++ )
{
if( !isprint((unsigned char)*bp) )
nonprintcount++;
}
dest = xmalloc(buflen + nonprintcount * 4 + 1);
if( nonprintcount == 0 )
{
memcpy(dest, buffer, buflen);
dest[buflen] = '\0';
}
else
{
p = dest;
for( pos = 0; pos < buflen; buffer++, pos++ )
{
if( !isprint((unsigned char)*buffer) )
{
sprintf(p, "\\x%02x", (unsigned char)*buffer);
p += 4;
} else
*p++ = *buffer;
}
*p = '\0';
}
return dest;
}
/*****************************************************************************
* Quote all unprintable characters in the string (e.g. "\xff\xfe")
*
* Arguments:
* str pointer to the null-terminated string
*
* Return value:
* Pointer to the quoted-printable string. Memory allocated for the
* resulting string will be freed automatically. So don't use more
* than last PRINTABLE_MAXITEMS pointers returned by this function.
*/
const char *string_printable(const char *str)
{
char *p;
const char *q;
int nonprintcount = 0;
size_t pos = 0;
size_t len = 0;
if( printable_pos == -1 )
{
memset(printable_storage, '\0', sizeof(printable_storage));
printable_pos = 0;
}
if( str == NULL ) return "(null)";
len = strlen(str);
for( q = str, pos = 0; pos < len; q++, pos++ )
{
if( iscntrl((unsigned char)*q) || !isprint((unsigned char)*q) )
nonprintcount++;
}
if( !nonprintcount )
return str;
if( printable_pos >= PRINTABLE_MAXITEMS )
printable_pos = 0;
if( printable_storage[printable_pos] )
free(printable_storage[printable_pos]);
p = printable_storage[printable_pos] = xmalloc(len + nonprintcount * 4 + 1);
for( pos = 0; pos < len; str++, pos++ )
{
if( iscntrl((unsigned char)*str) || !isprint((unsigned char)*str) )
{
sprintf(p, "\\x%02x", (unsigned char)*str);
p += 4;
} else
*p++ = *str;
}
*p = '\0';
return printable_storage[printable_pos++];
}
/*****************************************************************************
* Replace all chracters 'oldchar' by the 'newchar'
*
* Arguments:
* str pointer to the null-terminated string
* oldchar old chracter
* newchar character to put istead of 'oldchar'
*
* Return value:
* Pointer to the string
*/
char *string_replchar(char *str, char oldchar, char newchar)
{
char *p = str;
while( *p )
{
if( *p == oldchar ) *p = newchar;
++p;
}
return str;
}
/*****************************************************************************
* Devide string on substrings and put pointers to them into the
* dest[] array.
*
* Arguments:
* dest destination array where we should put substrings
* items number of entries in dest[]
* str string to parse (will be destroyed)
* separator separator character
*
* Return value:
* Number of substrings in the dest[]
*/
int string_parse(char **dest, int items, char *str, int separator)
{
int count = 0;
char *p = str;
dest[count++] = str;
while( *p && count < items )
{
if( *((unsigned char *)p) == separator )
{
*p++ = '\0';
dest[count++] = p;
} else
++p;
}
return count;
}
/*****************************************************************************
* Devide string on substrings separated by white-space characters and put
* pointers to them into the dest[] array. Also it will ignore spaces in
* quoted strings (quote characters will be removed)
*
* Arguments:
* dest destination array where we should put substrings
* items number of entries in dest[]
* str string to parse (will be destroyed)
*
* Return value:
* Number of substrings in the dest[]
*/
int string_parse_regular(char **dest, int items, char *str)
{
int count = 0;
char *p = str;
while( *p )
{
while( *p && isspace(*p) )
++p;
if( *((unsigned char *)p) == '"' && *++p )
{
dest[count++] = p;
while( *p && *((unsigned char *)p) != '"' ) p++;
}
else if( *p )
{
dest[count++] = p;
while( *p && !isspace(*p) ) p++;
}
if( *p && count < items )
*p++ = '\0';
else
break;
}
return count;
}
/*****************************************************************************
* Replace all substrings 'find' by the 'repl' in the string 'str'
*
* Arguments:
* str null-terminated string to process (will be unchanged)
* find substring to find
* repl replace substring
*
* Return value:
* Pointer to the new string (must be freed)
*/
char *string_translate(const char *str, const char *find, const char *repl)
{
size_t sz_find = strlen(find);
size_t sz_repl = strlen(repl);
size_t sz_dest = strlen(str);
char *dest, *p;
p = dest = xstrcpy(str);
if( !sz_find ) return dest;
while( *p )
{
if( memcmp(p, find, sz_find) == 0 )
{
size_t offset = p - dest;
size_t newsize = sz_dest + (sz_repl - sz_find);
if( newsize > sz_dest )
dest = xrealloc(dest, newsize+1);
if( sz_repl > sz_find )
memmove(dest + offset + (sz_repl - sz_find), dest + offset, sz_dest - offset + 1);
else if( sz_repl < sz_find )
memmove(dest + offset, dest + offset + (sz_find - sz_repl), sz_dest - offset + 1);
memcpy(dest + offset, repl, sz_repl);
sz_dest = newsize;
p = dest + offset + sz_repl;
} else
++p;
}
return dest;
}
/*****************************************************************************
* Convert size into human readable format (e.g. 100,256Kb or 20.7Mb)
*
* Arguments:
* buffer pointer to the buffer for resulting string
* size size in bytes that you want to print
*
* Return value:
* Pointer to the string
*/
char *string_humansize(char *buffer, size_t size)
{
if( size < 1024 )
sprintf(buffer, "%ldb", (long)size);
else if( size < 100*1024 )
sprintf(buffer, "%.1fK", ((double)size)/1024.0);
else if( size < 1000*1024 )
sprintf(buffer, "%ldK", (long)(size/1024));
else if( size < 100*1024*1024 )
sprintf(buffer, "%.1fM", ((double)size)/(1024.0*1024.0));
else if( size < 1000*1024*1024 )
sprintf(buffer, "%ldM", (long)(size/(1024*1024)));
else
sprintf(buffer, "%.1fG", ((double)size)/(1024.0*1024.0*1024.0));
return string_replchar(buffer, ',', '.');
}
/*****************************************************************************
* Interpret escape sequence (\xNN, \NNN, \r, \n, etc.)
*
* Arguments:
* pptr points a pointer to the first character after '\'
*
* Return value:
* Value of the escaped character
*/
int string_get_escape(char **pptr)
{
int ch = 0;
static const char *hexdigits = "0123456789abcdef";
char *p = *pptr;
if( *p == 'x' )
{
const char *q;
if( (q = string_casechr(hexdigits, *(++p))) )
{
ch = q - hexdigits;
if( (q = string_casechr(hexdigits, *(++p))) )
{
ch = ch * 16 + (q - hexdigits);
}
}
}
else if( *p == '0' || *p == '1' || *p == '2' || *p == '3' )
{
ch = *(p++) - '0';
if( isdigit(*p) && *p != '8' && *p != '9' )
{
ch = ch * 8 + (*(p++) - '0');
if( isdigit(*p) && *p != '8' && *p != '9' )
{
ch = ch * 8 + (*p - '0');
}
}
}
else switch(*p) {
case 'a':
ch = '\a'; break;
case 'b':
ch = '\b'; break;
case 'f':
ch = '\f'; break;
case 'n':
ch = '\n'; break;
case 'r':
ch = '\r'; break;
case 't':
ch = '\t'; break;
case '\\':
ch = '\\'; break;
default:
ch = *p;
}
*pptr = p + 1;
return (ch > 0) ? (ch & 0xff) : -1;
}
int string_dequote(char *dst, char *src)
{
char *d = dst;
char *s = src;
int ch;
while( *s )
{
if( s[0] == '\\' && s[1] )
{
++s;
ch = string_get_escape(&s);
if( ch != -1 )
*d++ = ch;
}
else
*d++ = *s++;
}
*d = '\0';
return 0;
}
char *string_concat(const char *str, ...)
{
va_list args;
size_t yield_len;
char *yield_ptr;
char *yield;
char *p;
/*
* Calculate total length of yielding string
*/
yield_len = strlen(str);
va_start(args, str);
while( (p = va_arg(args, char *)) )
yield_len += strlen(p);
va_end(args);
yield = xmalloc(yield_len + 1);
strncpy(yield, str, yield_len);
yield[yield_len] = '\0';
yield_ptr = yield + strlen(yield);
va_start(args, str);
while( (p = va_arg(args, char *)) )
{
strcpy(yield_ptr, p);
yield_ptr += strlen(p);
}
va_end(args);
return yield;
}
void string_bin_to_hex(char *string, const char *binptr, int binlen)
{
static const char *hexdigits = "0123456789abcdef";
int i;
for( i = 0; i < binlen; i++ )
{
*string++ = hexdigits[(*binptr >> 4) & 0x0f];
*string++ = hexdigits[(*binptr ) & 0x0f];
++binptr;
}
*string = '\0';
}
int string_hex_to_bin(char *binptr, const char *string)
{
static const char *hexdigits = "0123456789abcdef";
int len = (int)strlen(string);
int i, val;
const char *p;
char *dest = binptr;
for( i = 0; 2*i < len; i++ )
{
if( (p = string_casechr(hexdigits, *(string++))) )
{
val = (int)(p - hexdigits);
if( (p = string_casechr(hexdigits, *(string++))) )
{
val = val * 16 + (int)(p - hexdigits);
*dest++ = (unsigned char)(val & 0xff);
}
else
return 0;
}
else
return 0;
}
return (int)(dest - binptr);
}
bool string_is_empty(const char *string)
{
const char *p;
for( p = string; *p; p++ )
if( !isspace((int)(unsigned char)*p) )
return FALSE;
return TRUE;
}
#ifdef TEST
int main(void)
{
char *hexstr = "0406ff2354124e6a9b2f6ed6ff00411287";
char binbuf[64];
int binlen;
char newhex[64];
/*
* string_hex_to_bin() and string_bin_to_hex()
*/
printf("*** Checking string_hex_to_bin() and string_bin_to_hex()\n");
printf("Original string : \"%s\"\n", hexstr);
binlen = string_hex_to_bin(binbuf, hexstr);
string_bin_to_hex(newhex, binbuf, binlen);
printf("Resulting string : \"%s\"\n", newhex);
if( strcmp(hexstr, newhex) )
printf("<<< ERROR!!! >>>\n");
return 0;
}
#endif /* TEST */