Logo Search packages:      
Sourcecode: p3scan version File versions  Download package

pldstr.c

#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;
      int 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;
      int 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)>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

      unsigned char *c = convertme;

      while ( *c != '\0') {*c = tolower(*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.

Generated by  Doxygen 1.6.0   Back to index