#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <stdarg.h>
#include "logger.h"
#include "pldstr.h"
/*-----------------------------------------------------------------\
Function Name : *PLD_strstr
Returns Type : char
----Parameter List
1. char *haystack,
2. char *needle,
3. int insensitive,
------------------
Exit Codes :
Side Effects :
--------------------------------------------------------------------
Comments:
--------------------------------------------------------------------
Changes:
\------------------------------------------------------------------*/
char *PLD_strstr(char *haystack, char *needle, int insensitive)
{
char *hs, *ne;
char *result;
// LOGGER_log("%s:%d:\nHS=%s\nNE=%s\nIS=%d\n",FL, haystack, needle, insensitive );
if (insensitive > 0)
{
hs = strdup(haystack);
PLD_strlower(hs);
ne = strdup(needle);
PLD_strlower(ne);
} else {
hs = haystack;
ne = needle;
}
result = strstr(hs, ne);
// if (result) LOGGER_log("%s:%d:HIT: %s",FL, result);
// else LOGGER_log("%s:%d:MISS (looking for %s|%s)",FL, needle,ne);
if ((result != NULL)&&(insensitive > 0))
{
result = result -hs +haystack;
free(hs);
free(ne);
// LOGGER_log("%s:%d:HIT - %s",FL, result );
}
return result;
}
/*------------------------------------------------------------------------
Procedure: PLD_strncpy ID:1
Purpose: Copy characters from 'src' to 'dst', writing not more than 'len'
characters to the destination, including the terminating \0.
Thus, for any effective copying, len must be > 1.
Input: char *dst: Destination string
char *src: Source string
size_t len: length of string
Output: Returns a pointer to the destination string.
Errors:
------------------------------------------------------------------------*/
char *PLD_strncpy (char *dst, const char *src, size_t len)
{
// Thanks go to 'defrost' of #c for providing the replacement
// code which you now see here. It covers the errors better
// than my own previous code.
// If we have no buffer space, then it's futile attempting
// to copy anything, just return NULL
if (len==0) return NULL;
// Providing our destination pointer isn't NULL, we can
// commence copying data across
if (dst)
{
char *dp = dst;
// If our source string exists, start moving it to the
// destination string character at a time.
if (src)
{
char *sp = (char *)src;
while ((--len)&&(*sp)) { *dp=*sp; dp++; sp++; }
}
*dp='\0';
}
return dst;
}
/*------------------------------------------------------------------------
Procedure: PLD_strncat ID:1
Purpose: Buffer size limited string concat function for two strings.
Input: char *dst: Destination string
char *src: Source string
size_t len: Destination string buffer size - total string size cannot exceed this
Output:
Errors: If the length of both strings in total is greater than the available buffer space
in *dst, we copy the maximum possible amount of chars from *src such that
buffer does not overflow. A suffixed '\0' will always be appended.
------------------------------------------------------------------------*/
char *PLD_strncat( char *dst, const char *src, size_t len )
{
char *dp = dst;
const char *sp = src;
size_t cc;
if (len == 0) return dst;
len--;
// Locate the end of the current string.
cc = 0;
while ((*dp)&&(cc < len)) { dp++; cc++; }
// If we have no more buffer space, then return the destination
if (cc >= len) return dst;
// While we have more source, and there's more char space left in the buffer
while ((*sp)&&(cc < len))
{
cc++;
*dp = *sp;
dp++;
sp++;
}
// Terminate dst, as a gaurantee of string ending.
*dp = '\0';
return dst;
}
/*------------------------------------------------------------------------
Procedure: PLD_strncate ID:1
Purpose: Catencates a source string to the destination string starting from a given
endpoint. This allows for faster catencation of strings by avoiding the
computation required to locate the endpoint of the destination string.
Input: char *dst: Destination string
char *src: Source string
size_t len: Destination buffer size
char *endpoint: Endpoint of destination string, location from where new
string will be appended
Output:
Errors:
------------------------------------------------------------------------*/
char *PLD_strncate( char *dst, const char *src, size_t len, char *endpoint )
{
char *dp = dst;
const char *sp = src;
size_t cc = 0;
if (len == 0) return dst;
len--;
// If endpoint does not relate correctly, then force manual detection
// of the endpoint.
if ((!endpoint)||(endpoint == dst)||((endpoint -dst +1)>(int)len))
{
// Locate the end of the current string.
cc = 0;
while ((*dp != '\0')&&(cc < len)) { dp++; cc++; }
}
else {
cc = endpoint -dst +1;
dp = endpoint;
}
// If we have no more buffer space, then return the destination
if (cc >= len) return dst;
// While we have more source, and there's more char space left in the buffer
while ((*sp)&&(cc < len))
{
cc++;
*dp = *sp;
dp++;
sp++;
}
// Terminate dst, as a gaurantee of string ending.
*dp = '\0';
return dst;
}
/*------------------------------------------------------------------------
Procedure: XAM_strncasecmp ID:1
Purpose: Portable version of strncasecmp(), this may be removed in later
versions as the strncase* type functions are more widely
implemented
Input:
Output:
Errors:
------------------------------------------------------------------------*/
int PLD_strncasecmp( char *s1, char *s2, int n )
{
char *ds1 = s1, *ds2 = s2;
char c1, c2;
int result = 0;
while(n > 0)
{
c1 = tolower(*ds1);
c2 = tolower(*ds2);
if (c1 == c2)
{
n--;
ds1++;
ds2++;
}
else
{
result = c2 - c1;
n = 0;
}
}
return result;
}
/*------------------------------------------------------------------------
Procedure: XAM_strtok ID:1
Purpose: A thread safe version of strtok()
Input:
Output:
Errors:
------------------------------------------------------------------------*/
char *PLD_strtok( struct PLD_strtok *st, char *line, char *delimeters )
{
char *stop;
char *dc;
char *result = NULL;
if ( line )
{
st->start = line;
}
//Strip off any leading delimeters
dc = delimeters;
while ((st->start)&&(*dc != '\0'))
{
if (*dc == *(st->start))
{
st->start++;
dc = delimeters;
}
else dc++;
}
// Where we are left, is the start of our token.
result = st->start;
if ((st->start)&&(st->start != '\0'))
{
stop = strpbrk( st->start, delimeters ); /* locate our next delimeter */
// If we found a delimeter, then that is good. We must now break the string here
// and don't forget to store the character which we stopped on. Very useful bit
// of information for programs which process expressions.
if (stop)
{
// Store our delimeter.
st->delimeter = *stop;
// Terminate our token.
*stop = '\0';
// Because we're emulating strtok() behaviour here, we have to
// absorb all the concurrent delimeters, that is, unless we
// reach the end of the string, we cannot return a string with
// no chars.
stop++;
dc = delimeters;
while (*dc != '\0')
{
if (*dc == *stop)
{
stop++;
dc = delimeters;
}
else dc++;
} // While
if (*stop == '\0') st->start = NULL;
else st->start = stop;
}
else {
st->start = NULL;
st->delimeter = '\0';
}
}
else {
st->start = NULL;
result = NULL;
}
return result;
}
/*------------------------------------------------------------------------
Procedure: PLD_strlower ID:1
Purpose: Converts a string to lowercase
Input: char *convertme : string to convert
Output:
Errors:
------------------------------------------------------------------------*/
int PLD_strlower( unsigned char *convertme )
{
// Updates:
// 09-11-2002 - changed from 'char *' to 'unsigned char *' to deal with
// non-ASCII characters ( ie, french ). Pointed out by Emmanuel Collignon
char *c = convertme;
while ( *c != '\0') {*c = tolower((int)*c); c++;}
return 0;
}
/*-----------------------------------------------------------------\
Function Name : *PLD_strreplace
Returns Type : char
----Parameter List
1. char *source, Original buffer, \0 terminated
2. char *searchfor, String sequence to search for
3. char *replacewith, String sequence to replace 'searchfor' with
4. int replacenumber , How many times to replace 'searchfor', 0 == unlimited
------------------
Exit Codes : Returns a pointer to the new buffer space. The original
buffer will still remain intact - ensure that the calling
program free()'s the original buffer if it's no longer
needed
Side Effects :
--------------------------------------------------------------------
Comments:
Start out with static text matching - upgrade to regex later.
--------------------------------------------------------------------
Changes:
\------------------------------------------------------------------*/
char *PLD_strreplace_general( struct PLD_strreplace *replace_details )
{
char *new_buffer=NULL;
char *source_end;
char *segment_start, *segment_end, *segment_p;
char *new_p;
char *preexist_location=NULL;
char *postexist_location=NULL;
int replace_count=0;
int size_required;
int size_difference;
int source_length;
int searchfor_length;
int replacewith_length;
int segment_ok;
if (replace_details->source == NULL) return NULL;
source_length = strlen( replace_details->source );
source_end = replace_details->source +source_length;
searchfor_length = strlen(replace_details->searchfor);
replacewith_length = strlen(replace_details->replacewith);
size_difference = replacewith_length -searchfor_length;
size_required = source_length;
replace_count = replace_details->replacenumber;
if ((replace_details->preexist != NULL)&&(strlen(replace_details->preexist) < 1)) replace_details->preexist = NULL;
if ((replace_details->postexist != NULL)&&(strlen(replace_details->postexist) < 1)) replace_details->postexist = NULL;
// If we have a 'pre-exist' request, then we need to check this out first
// because if the pre-exist string cannot be found, then there's very
// little point us continuing on in our search ( because without the
// preexist string existing, we are thus not qualified to replace anything )
if (replace_details->preexist != NULL)
{
preexist_location = PLD_strstr(replace_details->source, replace_details->preexist, replace_details->insensitive);
if (preexist_location == NULL)
{
return replace_details->source;
}
}
// Determine if initial POSTexist tests will pass, if we don't pick up
// anything here, then there's no point in continuing either
if (replace_details->postexist != NULL)
{
char *p = replace_details->source;
postexist_location = NULL;
do {
p = PLD_strstr(p, replace_details->postexist, replace_details->insensitive);
if (p != NULL)
{
postexist_location = p;
p = p +strlen(replace_details->postexist);
}
} while (p != NULL);
if (postexist_location == NULL)
{
return replace_details->source;
}
}
// Step 1 - determine the MAXIMUM number of times we might have to replace this string ( or the limit
// set by replacenumber
//
// Note - we only need this number if the string we're going to be inserting into the
// source is larger than the one we're replacing - this is so that we can ensure that
// we have sufficient memory available in the buffer.
if (size_difference > 0)
{
if (replace_count == 0)
{
char *p, *q;
p = replace_details->source;
q = PLD_strstr(p, replace_details->searchfor, replace_details->insensitive);
while (q != NULL)
{
replace_count++;
//size_required += size_difference;
p = q +searchfor_length;
q = PLD_strstr(p, replace_details->searchfor, replace_details->insensitive);
}
}
size_required = source_length +(size_difference *replace_count) +1;
} else size_required = source_length +1;
// Allocate the memory required to hold the new string [at least], check to see that
// all went well, if not, then return an error
new_buffer = malloc( sizeof(char) *size_required);
if (new_buffer == NULL)
{
LOGGER_log("%s:%d:PLD_strreplace:ERROR: Cannot allocate %d bytes of memory to perform replacement operation", FL, size_required);
return replace_details->source;
}
// Our segment must always start at the beginning of the source,
// on the other hand, the segment_end can be anything from the
// next byte to NULL ( which is specially treated to mean to
// the end of the source )
segment_start = replace_details->source;
// Locate the first segment
segment_ok = 0;
segment_end = PLD_strstr(replace_details->source, replace_details->searchfor, replace_details->insensitive);
// Determine if the first segment is valid in the presence of the
// pre-exist and post-exist requirements
while ((segment_end != NULL)&&(segment_ok == 0)\
&&((replace_details->preexist != NULL)||(replace_details->postexist != NULL)))
{
int pre_ok = 0;
int post_ok = 0;
// The PREexist test assumes a couple of factors - please ensure these are
// relevant if you change any code prior to this point.
//
// 1. preexist_location has already been computed and is not NULL
//
// 2. By relative position, the first preexist_location will be a valid location
// on which to validate for ALL replacements beyond that point, thus, we
// never actually have to recompute preexist_location again.
//
// 3. Conversely, the last computed postexist_location is valid for all
// matches before it
//
if (preexist_location == NULL) pre_ok = 1;
else if (preexist_location < segment_end){ pre_ok = 1;}
if (postexist_location == NULL) post_ok = 1;
else if (postexist_location > segment_end){ post_ok = 1;}
if ((pre_ok == 0)||(post_ok == 0)) { segment_end = PLD_strstr(segment_end +searchfor_length, replace_details->searchfor, replace_details->insensitive); }
else segment_ok = 1;
}
segment_p = segment_start;
new_p = new_buffer;
while (segment_start != NULL)
{
int replacewith_count;
char *replacewith_p;
if (segment_end == NULL) segment_end = source_end;
replace_count--;
// Perform the segment copy
segment_p = segment_start;
while ((segment_p < segment_end)&&(size_required > 0))
{
*new_p = *segment_p;
new_p++;
segment_p++;
size_required--;
}
// Perform the string replacement
if (segment_end < source_end)
{
replacewith_count = replacewith_length;
replacewith_p = replace_details->replacewith;
while ((replacewith_count--)&&(size_required > 0))
{
*new_p = *replacewith_p;
new_p++;
replacewith_p++;
size_required--;
}
}
if (size_required < 1 )
{
LOGGER_log("%s:%d:PLD_strreplace_general: Allocated memory ran out while replacing '%s' with '%s'",FL, replace_details->searchfor, replace_details->replacewith);
*new_p='\0';
break;
}
// Find the next segment
segment_start = segment_end +searchfor_length;
// If we've reached the end of the number of replacements we're supposed
// to do, then we prepare the termination of the while loop by setting
// our segment end to the end of the source.
//
// NOTE: Remember that the replace_count is pre-decremented at the start
// of the while loop, so, if the caller requested '0' replacements
// this will now be -1, thus, it won't get terminated from this == 0
// match. Just thought you'd like to be reminded of that incase you
// were wondering "Huh? this would terminate an unlimited replacement"
if (replace_count == 0)
{
segment_end = NULL;
} else {
// If our new segment to copy starts after the
// end of the source, then we actually have
// nothing else to copy, thus, we prepare the
// segment_start varible to cause the while loop
// to terminate.
//
// Otherwise, we try and locate the next segment
// ending point, and set the starting point to
// be on the 'other side' of the 'searchfor' string
// which we found in the last search.
//
if (segment_start > source_end)
{
segment_start = NULL;
} else {
// Try find the next segment
segment_ok = 0;
segment_end = PLD_strstr(segment_end +searchfor_length, replace_details->searchfor, replace_details->insensitive);
// If we have a pre/post-exist requirement, then enter into this
// series of tests. NOTE - at least one of the pre or post tests
// must fire to give an meaningful result - else we'll end up with
// a loop which simply goes to the end of the searchspace buffer
while ((segment_end != NULL)&&(segment_ok == 0)\
&&((replace_details->preexist != NULL)||(replace_details->postexist != NULL)))
{
int pre_ok = 0;
int post_ok = 0;
// The PREexist test assumes a couple of factors - please ensure these are
// relevant if you change any code prior to this point.
//
// 1. preexist_location has already been computed and is not NULL
//
// 2. By relative position, the first preexist_location will be a valid location
// on which to validate for ALL replacements beyond that point, thus, we
// never actually have to recompute preexist_location again.
//
// 3. Conversely, the last computed postexist_location is valid for all
// matches before it
//
if (preexist_location == NULL) pre_ok = 1;
else if (preexist_location < segment_end){ pre_ok = 1;}
if (postexist_location == NULL) post_ok = 1;
else if (postexist_location > segment_end){ post_ok = 1;}
if ((pre_ok == 0)||(post_ok == 0)) { segment_end = PLD_strstr(segment_end +searchfor_length, replace_details->searchfor, replace_details->insensitive); }
else segment_ok = 1;
}
} // If-else segment_start > source_end
}
}
*new_p = '\0';
if (replace_details->source != NULL) free (replace_details->source);
replace_details->source = new_buffer;
return new_buffer;
}
/*-----------------------------------------------------------------\
Function Name : *PLD_strreplace
Returns Type : char
----Parameter List
1. char **source,
2. char *searchfor,
3. char *replacewith,
4. int replacenumber ,
------------------
Exit Codes :
Side Effects :
--------------------------------------------------------------------
Comments:
--------------------------------------------------------------------
Changes:
\------------------------------------------------------------------*/
char *PLD_strreplace( char **source, char *searchfor, char *replacewith, int replacenumber )
{
struct PLD_strreplace replace_details;
char *tmp_source;
replace_details.source = *source;
replace_details.searchfor = searchfor;
replace_details.replacewith = replacewith;
replace_details.replacenumber = replacenumber;
replace_details.preexist = NULL;
replace_details.postexist = NULL;
replace_details.insensitive = 0;
tmp_source = PLD_strreplace_general( &replace_details );
if (tmp_source != *source) *source = tmp_source;
return *source;
}
/*-----------------------------------------------------------------\
Function Name : *PLD_dprintf
Returns Type : char
----Parameter List
1. const char *format,
2. ...,
------------------
Exit Codes :
Side Effects :
--------------------------------------------------------------------
Comments:
This is a dynamic string allocation function, not as fast as some
other methods, but it works across the board with both glibc 2.0
and 2.1 series.
--------------------------------------------------------------------
Changes:
\------------------------------------------------------------------*/
char *PLD_dprintf(const char *format, ...)
{
int n, size = 1024; // Assume we don't need more than 1K to start with
char *p;
va_list ap;
// Attempt to allocate and then check
p = malloc(size *sizeof(char));
if (p == NULL) return NULL;
while (1)
{
// Attempt to print out string out into the allocated space
va_start(ap, format);
n = vsnprintf (p, size, format, ap);
va_end(ap);
// If things went well, then return the new string
if ((n > -1) && (n < size)) return p;
// If things didn't go well, then we have to allocate more space
// based on which glibc we're using ( fortunately, the return codes
// tell us which glibc is being used! *phew*
//
// If n > -1, then we're being told precisely how much space we need
// else (older glibc) we have to just guess again ...
if (n > -1) size = n+1; // Allocate precisely what is needed
else size *= 2; // Double the amount allocated, note, we could just increase by 1K, but if we have a long string, we'd end up using a lot of realloc's
// We could just realloc 'blind', but that'd be wrong and potentially cause a DoS, so
// instead, we'll be good and first attempt to realloc to a temp variable then, if all
// is well, we go ahead and update
if (1)
{
char *tmp_p;
tmp_p = realloc(p, size);
if (tmp_p == NULL){ if (p != NULL) free(p); return NULL; }
else p = tmp_p;
}
}
}
//-----------------END.
syntax highlighted by Code2HTML, v. 0.9.1