/******************************************************************************
 Copyright (c) 1999-2001 Richard Woolcock

 Permission is hereby granted, free of charge, to any person obtaining a copy 
 of this software and associated documentation files (the "Software"), to deal 
 in the Software without restriction, including without limitation the rights 
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 copies of the Software, and to permit persons to whom the Software is 
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all 
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
 SOFTWARE.
 ******************************************************************************/

/******************************************************************************
 File Name        : string.c
 ******************************************************************************
 Description      : Contains the string manipulation functions.
 ******************************************************************************/

/******************************************************************************
 Required library files.
 ******************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "sockets.h"
#include "string.h"

/******************************************************************************
 Required operations.
 ******************************************************************************/

/* Function: ChopToken
 *
 * This function chops a token (a text word separated by spaces) off the front 
 * of the input string.  It is used for commands which require multiple input 
 * parameters.
 *
 * The function takes one parameter, as follows:
 *
 * pszTxt: A pointer to the string to be tokenised.
 *
 * This function returns a pointer to the first token.
 */
char *ChopToken( char **pszTxt )
{
   char *szToken; /* Pointer to the first token of pszTxt */

   /* Ignore all leading spaces */
   while ( **pszTxt == ' ' )
   {
      ++(*pszTxt);
   }

   /* Set the token to the start of the string */
   szToken = *pszTxt;

   /* Look for a space, but terminate if a NUL is reached */
   while ( **pszTxt != '\0' && **pszTxt != ' ' )
   {
      ++(*pszTxt);
   }

   /* If a space was found, chop the token off the string */
   if ( **pszTxt == ' ' )
   {
      /* Remove multiple spaces */
      while ( **pszTxt == ' ' )
      {
         *(*pszTxt)++ = '\0';
      }
   }

   /* Return the token */
   return ( szToken );
}



/* Function: StringCompare
 *
 * This function performs a string compare check to see whether the two 
 * strings match.  The check is not case-sensitive, and allows for '?' 
 * wildcards.
 *
 * The function takes two parameters, as follows:
 *
 * kszFirst:  The first string.
 * kszSecond: The second string.
 *
 * This function returns a cmp_t, which is CMP_EQUAL if the two strings match, 
 * CMP_LESS if the first string comes first (alphabetically) and CMP_GREATER if 
 * the first string comes last.
 */
cmp_t StringCompare( const char *kszFirst, const char *kszSecond )
{
   while ( tolower(*kszFirst) == tolower(*kszSecond)
      || (*kszFirst == '?' && islower(tolower(*kszSecond)) ) 
      || (*kszSecond == '?' && islower(tolower(*kszFirst)) ) )
   {
      if ( *kszFirst == '\0' )
      {
         /* The two strings match */
         return ( CMP_EQUAL );
      }

      /* Increment the pointers */
      kszFirst++;
      kszSecond++;
   }

   if ( *kszFirst < *kszSecond )
   {
      return ( CMP_LESS );
   }
   else /* *kszFirst > *kszSecond */
   {
      return ( CMP_GREATER );
   }
}



/* Function: StringPrefix
 *
 * This function performs a string prefix check to see whether the "whole" 
 * string starts with the "part" string.  The check is not case-sensitive, 
 * and allows for '?' wildcards.
 *
 * The function takes two parameters, as follows:
 *
 * szPart:  The substring (to be looked for at the start of the whole string).
 * szWhole: The whole string (which should start with the substring).
 *
 * This function returns a bool, which is TRUE if the "whole" string starts 
 * with the "part" string and FALSE if not.
 */
bool StringPrefix( char *szPart, char *szWhole )
{
   do /* Loop through the characters in the 'whole' and 'part' strings */
   {
      /* Check if part and whole match up, with '?' as a wildcard */
      if ( tolower(*szPart) != tolower(*szWhole) && *szPart != '?' )
      {
         return ( FALSE );
      }
   }
   while ( *++szPart && *++szWhole ); /* Until one string is empty */

   if ( *szPart != '\0' ) /* If the 'part string' is empty, the input is bad */
   {
      return ( FALSE ); 
   }

   return ( TRUE );
}



/* Function: StringInfix
 *
 * This function performs a string infix check to see whether the "whole" 
 * string contains the "part" string.  The check is not case-sensitive, 
 * and allows for '?' wildcards.
 *
 * The function takes two parameters, as follows:
 *
 * szPart:  The substring (to be looked for within the whole string).
 * szWhole: The whole string (which should be somewhere within the substring).
 *
 * This function returns a bool, which is TRUE if the "whole" string contains 
 * the "part" string and FALSE if not.
 */
bool StringInfix( char *szPart, char *szWhole )
{
   do /* Loop through the characters in the 'whole' string */
   {
      /* Perform a prefix check at this position in the 'whole' string */
      if ( StringPrefix( szPart, szWhole ) )
      {
         return ( TRUE );
      }
   }
   while ( *szWhole++ ); /* Until the whole string runs of of characters */

   return ( FALSE );
}



/* Function: StringPostfix
 *
 * This function performs a string prefix check to see whether the "whole" 
 * string ends with the "part" string.
 *
 * The function takes two parameters, as follows:
 *
 * szPart:  The substring (to be looked for at the end of the whole string).
 * szWhole: The whole string (which should end with the substring).
 *
 * This function returns a bool, which is TRUE if the "whole" string ends 
 * with the "part" string and FALSE if not.  The check is not case-sensitive, 
 * and allows for '?' wildcards.
 */
bool StringPostfix( char *szPart, char *szWhole )
{
   int iWholeLength = strlen( szWhole );
   int iPartLength  = strlen( szPart );

   /* Make sure the string isn't too short to check for */
   if ( iWholeLength < iPartLength )
   {
      return ( FALSE );
   }

   /* Position the whole pointer to check the last <part> characters */
   szWhole += ( iWholeLength - iPartLength );

   do /* Loop through the characters in the 'whole' and 'part' strings */
   {
      /* Check if part and whole match up, with '?' as a wildcard */
      if ( tolower(*szPart) != tolower(*szWhole) && *szPart != '?' )
      {
         return ( FALSE );
      }
   }
   while ( *++szPart && *++szWhole ); /* Until one string is empty */

   if ( *szPart != '\0' ) /* If the 'part string' is empty, the input is bad */
   {
      return ( FALSE );
   }

   return ( TRUE );
}



/* Function: StringAlpha
 *
 * This function checks whether a string contains purely alphabetical 
 * characters.
 *
 * The function takes one parameter, as follows:
 *
 * szTxt: The string to be checked.
 *
 * This function returns a bool, which is TRUE if the string only contains 
 * alphabetical characters and FALSE if not.
 */
bool StringAlpha( char *szTxt )
{
   /* Loop through the string */
   while ( *szTxt != '\0' )
   {
      /* If a non-alphabetical character is found, return FALSE */
      if ( !isalpha(*szTxt) )
      {
         return ( FALSE );
      }
      szTxt++;
   }

   /* No non-alphabetical characters were found */
   return ( TRUE );
}



/* Function: GetBar
 *
 * This function returns a pointer to a string containing a line of text.  The 
 * line may contain text in the centre.
 *
 * The function takes one parameter, as follows:
 *
 * szTxt: The text to be placed in the centre of the line.
 *
 * This function returns a pointer to a string which contains the line.
 */
char *GetBar( char *szTxt )
{
   static char s_a_chBar[128];  /* Buffer to store text bar */
   int iLength;                 /* Length of the text */
   int iLineStart;              /* Start of text line */
   int iLineEnd;                /* End of text line */
   int i;                       /* Loop counter */

   if ( szTxt == NULL )
   {
      /* If szTxt is NULL then draw a normal line */
      return ( "-------------------------------------------------------------------------------\n\r" );
   }

   /* Calculate the length of the text and initialise the line start/end */
   iLength = strlen(szTxt);
   iLineStart = 38 - ((iLength+1) >> 1);
   iLineEnd  = iLength + iLineStart + 4;

   /* If the text is too big, just display it as is */
   if ( iLength > 70 )
   {
      return ( szTxt );
   }

   /* Set the left half of the bar to spaces */
   for ( i = 0; i < iLineStart; i++ )
   {
      s_a_chBar[i] = '-';
   }

   /* Terminate the bar string so that strcat can be used to add the word */
   s_a_chBar[iLineStart] = '\0';

   /* Add the text, surrounded by < > */
   strcat( s_a_chBar, "< " );
   strcat( s_a_chBar, szTxt );
   strcat( s_a_chBar, " >" );

   for ( i = iLineEnd; i < 79; i++ )
   {
      s_a_chBar[i] = '-';
   }

   /* Terminate the string and add a newline on the end */
   s_a_chBar[79] = '\0';
   strcat( s_a_chBar, "\n\r" );

   /* Loop through the text bar */
   for ( i = 0; s_a_chBar[i]; i++ )
   {
      /* Check if the current character is a lowercase letter */
      if ( islower(s_a_chBar[i]) )
      {
         /* Change all lowercase letters to uppercase */
         s_a_chBar[i] = toupper(s_a_chBar[i]);
      }
   }

   /* Return the text bar */
   return ( s_a_chBar );
}