2014-12-01 23:55:08 +01:00
// swad_string.c: string processing
/*
SWAD ( Shared Workspace At a Distance ) ,
is a web platform developed at the University of Granada ( Spain ) ,
and used to support university teaching .
This file is part of SWAD core .
2015-01-01 14:34:06 +01:00
Copyright ( C ) 1999 - 2015 Antonio Ca <EFBFBD> as Vargas
2014-12-01 23:55:08 +01:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation , either version 3 of the
License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU Affero General Public License for more details .
You should have received a copy of the GNU Affero General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
# include <linux/stddef.h> // For NULL
# include <ctype.h> // For isprint, isspace, etc.
# include <locale.h> // For setlocale
2015-03-11 14:35:33 +01:00
# include <math.h> // For log10, floor, ceil, modf, sqrt...
2014-12-01 23:55:08 +01:00
# include <stdlib.h> // For malloc and free
# include <string.h> // For string functions
# include "swad_global.h"
# include "swad_ID.h"
# include "swad_parameter.h"
# include "swad_string.h"
/*****************************************************************************/
/******************** Global variables from other modules ********************/
/*****************************************************************************/
extern struct Globals Gbl ; // Declaration in swad.c
/*****************************************************************************/
/****************************** Internal types *******************************/
/*****************************************************************************/
/*****************************************************************************/
/*************************** Internal prototypes *****************************/
/*****************************************************************************/
static unsigned Str_GetNextASCIICharFromStr ( const char * Ptr , char * Ch ) ;
static int Str_ReadCharAndSkipComments ( FILE * FileSrc , Str_SkipHTMLComments_t SkipHTMLComments ) ;
static int Str_ReadCharAndSkipCommentsWriting ( FILE * FileSrc , FILE * FileTgt , Str_SkipHTMLComments_t SkipHTMLComments ) ;
static int Str_ReadCharAndSkipCommentsBackward ( FILE * FileSrc , Str_SkipHTMLComments_t SkipHTMLComments ) ;
/*****************************************************************************/
/**************************** Internal constants *****************************/
/*****************************************************************************/
/***** Conversion to Base64URL *****/
// base64url is described in document http://tools.ietf.org/html/rfc4648.
// It uses '-' and '_' because they are safe for URL/parameters (without enconding) and for filenames.
const char Str_BIN_TO_BASE64URL [ 64 ] =
{ ' A ' , ' B ' , ' C ' , ' D ' , ' E ' , ' F ' , ' G ' , ' H ' , ' I ' , ' J ' , ' K ' , ' L ' , ' M ' , ' N ' , ' O ' , ' P ' , ' Q ' , ' R ' , ' S ' , ' T ' , ' U ' , ' V ' , ' W ' , ' X ' , ' Y ' , ' Z ' ,
' a ' , ' b ' , ' c ' , ' d ' , ' e ' , ' f ' , ' g ' , ' h ' , ' i ' , ' j ' , ' k ' , ' l ' , ' m ' , ' n ' , ' o ' , ' p ' , ' q ' , ' r ' , ' s ' , ' t ' , ' u ' , ' v ' , ' w ' , ' x ' , ' y ' , ' z ' ,
' 0 ' , ' 1 ' , ' 2 ' , ' 3 ' , ' 4 ' , ' 5 ' , ' 6 ' , ' 7 ' , ' 8 ' , ' 9 ' , ' - ' , ' _ ' } ;
static const char Str_LF [ 2 ] = { 10 , 0 } ;
static const char Str_CR [ 2 ] = { 13 , 0 } ;
/*****************************************************************************/
/****************************** Internal types *******************************/
/*****************************************************************************/
/*****************************************************************************/
/************************* Insert links in URLs ******************************/
/*****************************************************************************/
/*
Insertion example :
In the web http : //www.ugr.es/ or in http://swad.ugr.es/ you can find the info.
In the web < a href = " http://www.ugr.es/ " target = " _blank " > http : //www.ugr.es/</a> or in <a href="http://www.ugr.es/" target="_blank">http://swad.ugr.es/</a> you can find the info.
*/
# define LINK1 "<a href=\""
# define LINK2 "\" target=\"_blank\">"
# define LINK3 "< / a>"
# define MAX_URLS_IN_TEXT 1000
# define MAX_BYTES_LIMITED_URL 1024 // Max. number of bytes of the URL shown on screen
void Str_InsertLinkInURLs ( char * Txt , unsigned long MaxLength , size_t MaxCharsURLOnScreen )
{
unsigned long TxtLength = strlen ( Txt ) ;
unsigned LinkLength1 = strlen ( LINK1 ) ;
unsigned LinkLength2 = strlen ( LINK2 ) ;
unsigned LinkLength3 = strlen ( LINK3 ) ;
unsigned LinkTotalLength = LinkLength1 + LinkLength2 + LinkLength3 ;
char * PtrSrc , * PtrDst ;
bool URLStartFound ;
int NumURLs = 0 , NumURL ;
struct
{
char * PtrStart ;
char * PtrEnd ;
size_t NumActualBytes ; // Actual length of the link
} URL [ MAX_URLS_IN_TEXT ] ;
size_t URLLengthOnScreenTotal = 0 ;
size_t Length , i ;
size_t NumChars1 , NumChars2 ;
size_t NumBytesToCopy ;
size_t NumBytesToShow ; // Length of the link displayed on screen (may be shorter than actual length)
char LimitedURL [ MAX_BYTES_LIMITED_URL + 1 ] ;
char Ch ;
/***** Find starts and ends of URLs *****/
for ( PtrSrc = Txt ;
* PtrSrc ; )
if ( tolower ( ( int ) * PtrSrc ) = = ( int ) ' h ' )
{
URLStartFound = false ;
URL [ NumURLs ] . PtrStart = PtrSrc ;
if ( tolower ( ( int ) * + + PtrSrc ) = = ( int ) ' t ' ) // ht...
{
if ( tolower ( ( int ) * + + PtrSrc ) = = ( int ) ' t ' ) // htt...
{
if ( tolower ( ( int ) * + + PtrSrc ) = = ( int ) ' p ' ) // http...
{
PtrSrc + + ;
if ( * PtrSrc = = ' : ' ) // http:...
{
if ( * + + PtrSrc = = ' / ' ) // http:/...
if ( * + + PtrSrc = = ' / ' ) // http://...
URLStartFound = true ;
}
else if ( tolower ( ( int ) * PtrSrc ) = = ( int ) ' s ' ) // https...
{
if ( * + + PtrSrc = = ' : ' ) // https:...
{
if ( * + + PtrSrc = = ' / ' ) // https:/...
if ( * + + PtrSrc = = ' / ' ) // https://...
URLStartFound = true ;
}
}
}
}
}
if ( URLStartFound )
{
/* Find URL end */
PtrSrc + + ; // Points to first character after http:// or https://
for ( ; ; )
{
NumChars1 = Str_GetNextASCIICharFromStr ( PtrSrc , & Ch ) ;
PtrSrc + = NumChars1 ;
if ( ( Ch > = 0 & & Ch < = 32 ) | | Ch = = ' < ' | | Ch = = ' " ' )
{
URL [ NumURLs ] . PtrEnd = PtrSrc - NumChars1 - 1 ;
break ;
}
else if ( Ch = = ' , ' | | Ch = = ' . ' | | Ch = = ' ; ' | | Ch = = ' : ' | | Ch = = ' ) ' | | Ch = = ' ] ' | | Ch = = ' } ' )
{
NumChars2 = Str_GetNextASCIICharFromStr ( PtrSrc , & Ch ) ;
PtrSrc + = NumChars2 ;
if ( ( Ch > = 0 & & Ch < = 32 ) | | Ch = = ' < ' | | Ch = = ' " ' )
{
URL [ NumURLs ] . PtrEnd = PtrSrc - NumChars2 - NumChars1 - 1 ;
break ;
}
}
}
/* Calculate length of this URL */
URL [ NumURLs ] . NumActualBytes = ( size_t ) ( URL [ NumURLs ] . PtrEnd - URL [ NumURLs ] . PtrStart ) + 1 ;
if ( URL [ NumURLs ] . NumActualBytes < = MaxCharsURLOnScreen )
URLLengthOnScreenTotal + = URL [ NumURLs ] . NumActualBytes ;
else // If URL is too long to be displayed ==> short it
{
/* Make a copy of this URL */
NumBytesToCopy = ( URL [ NumURLs ] . NumActualBytes < MAX_BYTES_LIMITED_URL ) ? URL [ NumURLs ] . NumActualBytes :
MAX_BYTES_LIMITED_URL ;
strncpy ( LimitedURL , URL [ NumURLs ] . PtrStart , NumBytesToCopy ) ;
LimitedURL [ NumBytesToCopy ] = ' \0 ' ;
/* Limit the number of characters on screen of the copy, and calculate its length in bytes */
URLLengthOnScreenTotal + = Str_LimitLengthHTMLStr ( LimitedURL , MaxCharsURLOnScreen ) ;
}
/* Increment number of found URLs */
if ( + + NumURLs = = MAX_URLS_IN_TEXT )
break ;
}
}
else // Character != 'h'
PtrSrc + + ;
if ( NumURLs ) // If there are one or more URLs in text
{
/***** Insert links from end to start of text, only if there is enough space available in text *****/
if ( TxtLength + URLLengthOnScreenTotal + LinkTotalLength * NumURLs < = MaxLength )
for ( NumURL = NumURLs - 1 ;
NumURL > = 0 ;
NumURL - - )
{
/* Step 1: Move forward the text after the URL (it's mandatory to do the copy in reverse order to avoid overwriting source) */
for ( i = 0 ,
PtrSrc = ( NumURL = = NumURLs - 1 ) ? Txt + TxtLength :
URL [ NumURL + 1 ] . PtrStart - 1 ,
PtrDst = PtrSrc + URLLengthOnScreenTotal + LinkTotalLength * ( NumURL + 1 ) ,
Length = PtrSrc - URL [ NumURL ] . PtrEnd ;
i < Length ;
i + + )
* PtrDst - - = * PtrSrc - - ;
/* Step 2: Insert LINK3 */
for ( i = 0 , PtrSrc = LINK3 + LinkLength3 - 1 ;
i < LinkLength3 ;
i + + )
* PtrDst - - = * PtrSrc - - ;
/* Step 3: Move forward the URL to be shown on screen */
if ( URL [ NumURL ] . NumActualBytes < = MaxCharsURLOnScreen )
{
NumBytesToShow = URL [ NumURL ] . NumActualBytes ;
PtrSrc = URL [ NumURL ] . PtrEnd ; // PtrSrc must point to end of complete URL
}
else // If URL is too long to be displayed ==> short it
{
/* Make a copy of this URL */
NumBytesToCopy = ( URL [ NumURL ] . NumActualBytes < MAX_BYTES_LIMITED_URL ) ? URL [ NumURL ] . NumActualBytes :
MAX_BYTES_LIMITED_URL ;
strncpy ( LimitedURL , URL [ NumURL ] . PtrStart , NumBytesToCopy ) ;
LimitedURL [ NumBytesToCopy ] = ' \0 ' ;
/* Limit the length of the copy */
NumBytesToShow = Str_LimitLengthHTMLStr ( LimitedURL , MaxCharsURLOnScreen ) ;
/* PtrSrc must point to end of limited URL */
PtrSrc = LimitedURL + NumBytesToShow - 1 ;
}
for ( i = 0 ;
i < NumBytesToShow ;
i + + )
* PtrDst - - = * PtrSrc - - ;
/* Step 4: Insert LINK2 */
for ( i = 0 , PtrSrc = LINK2 + LinkLength2 - 1 ;
i < LinkLength2 ;
i + + )
* PtrDst - - = * PtrSrc - - ;
/* Step 5: Insert URL into directive A (it's mandatory to do the copy in reverse order to avoid overwriting source URL) */
for ( i = 0 , PtrSrc = URL [ NumURL ] . PtrEnd ;
i < URL [ NumURL ] . NumActualBytes ;
i + + )
* PtrDst - - = * PtrSrc - - ;
/* Step 6: Insert LINK1 */
for ( i = 0 , PtrSrc = LINK1 + LinkLength1 - 1 ;
i < LinkLength1 ;
i + + )
* PtrDst - - = * PtrSrc - - ;
URLLengthOnScreenTotal - = NumBytesToShow ;
}
}
}
/*****************************************************************************/
/** Get next ASCII character from a string converting &#number; to character */
/*****************************************************************************/
// Returns number of char analyzed
static unsigned Str_GetNextASCIICharFromStr ( const char * Ptr , char * Ch )
{
unsigned NumChars ;
unsigned Num ;
if ( * Ptr = = ' \0 ' )
{
* Ch = ' \0 ' ;
return 0 ;
}
else if ( * Ptr = = ' & ' ) / / It ' s a & # num ; character ?
{
Ptr + + ;
if ( * Ptr = = ' # ' )
{
Ptr + + ;
for ( NumChars = 2 , Num = 0 ;
* Ptr > = ' 0 ' & & * Ptr < = ' 9 ' ;
Ptr + + , NumChars + + )
if ( Num < 256 ) // To avoid overflow
Num = Num * 10 + ( unsigned ) ( * Ptr - ' 0 ' ) ;
if ( * Ptr = = ' ; ' ) // &#num; found
{
NumChars + + ;
switch ( Num )
{
case 32 : * Ch = ' ' ; return NumChars ;
case 33 : * Ch = ' ! ' ; return NumChars ;
case 34 : * Ch = ' \" ' ; return NumChars ;
case 35 : * Ch = ' # ' ; return NumChars ;
case 36 : * Ch = ' $ ' ; return NumChars ;
case 37 : * Ch = ' % ' ; return NumChars ;
case 38 : * Ch = ' & ' ; return NumChars ;
case 39 : * Ch = ' \' ' ; return NumChars ;
case 40 : * Ch = ' ( ' ; return NumChars ;
case 41 : * Ch = ' ) ' ; return NumChars ;
case 42 : * Ch = ' * ' ; return NumChars ;
case 43 : * Ch = ' + ' ; return NumChars ;
case 44 : * Ch = ' , ' ; return NumChars ;
case 45 : * Ch = ' - ' ; return NumChars ;
case 46 : * Ch = ' . ' ; return NumChars ;
case 47 : * Ch = ' / ' ; return NumChars ;
case 58 : * Ch = ' : ' ; return NumChars ;
case 59 : * Ch = ' ; ' ; return NumChars ;
case 60 : * Ch = ' ' ; return NumChars ; // '<'
case 61 : * Ch = ' = ' ; return NumChars ;
case 62 : * Ch = ' ' ; return NumChars ; // '>'
case 63 : * Ch = ' ? ' ; return NumChars ;
case 64 : * Ch = ' @ ' ; return NumChars ;
case 91 : * Ch = ' [ ' ; return NumChars ;
case 92 : * Ch = ' \\ ' ; return NumChars ;
case 93 : * Ch = ' ] ' ; return NumChars ;
case 94 : * Ch = ' ^ ' ; return NumChars ;
case 95 : * Ch = ' _ ' ; return NumChars ;
case 96 : * Ch = ' ` ' ; return NumChars ;
case 123 : * Ch = ' { ' ; return NumChars ;
case 124 : * Ch = ' | ' ; return NumChars ;
case 125 : * Ch = ' } ' ; return NumChars ;
case 126 : * Ch = ' ~ ' ; return NumChars ;
default : * Ch = ' ' ; return NumChars ; // Unknown character
}
}
else
{
* Ch = * Ptr ;
return NumChars ;
}
}
else
{
* Ch = * Ptr ;
return 2 ;
}
}
else
{
* Ch = * Ptr ;
return 1 ;
}
}
/*****************************************************************************/
/*************** Limit number of chars on screen of a string *****************/
/*****************************************************************************/
// Returns length of resulting string in bytes (a special char counts for several bytes)
size_t Str_LimitLengthHTMLStr ( char * Str , size_t MaxCharsOnScreen )
{
char * Ptr ;
size_t NumCharsOnScreen ;
size_t Length ;
if ( MaxCharsOnScreen < 3 )
MaxCharsOnScreen = 3 ; // Length of "..."
/***** Calculate length counting "&...;" as one character *****/
for ( Ptr = Str , NumCharsOnScreen = 0 , Length = 0 ;
* Ptr ;
Ptr + + , NumCharsOnScreen + + , Length + + )
if ( * Ptr = = ' & ' ) // Special character
for ( Ptr + + , Length + + ;
* Ptr & & * Ptr ! = ' ; ' ;
Ptr + + , Length + + ) ; // While not end of special character
if ( NumCharsOnScreen < = MaxCharsOnScreen ) // Don't limit string
return Length ;
/***** Limit length of string *****/
for ( Ptr = Str , NumCharsOnScreen = 0 , Length = 0 ;
* Ptr ;
Ptr + + , NumCharsOnScreen + + , Length + + )
{
if ( NumCharsOnScreen = = MaxCharsOnScreen - 3 )
{
* Ptr + + = ' . ' ;
* Ptr + + = ' . ' ;
* Ptr + + = ' . ' ;
* Ptr = ' \0 ' ; // ...limit length...
Length + = 3 ;
break ;
}
if ( * Ptr = = ' & ' ) // Special character
for ( Ptr + + , Length + + ;
* Ptr & & * Ptr ! = ' ; ' ;
Ptr + + , Length + + ) ; // While not end of special character
else if ( * Ptr = = ' < ' ) // HTML entity
for ( Ptr + + , Length + + ;
* Ptr & & * Ptr ! = ' > ' ;
Ptr + + , Length + + ) ; // While not end of HTML entity
}
return Length ;
}
/*****************************************************************************/
/**************** Check if a URL adreess looks as** valid ********************/
/*****************************************************************************/
/*
bool Str_URLLooksValid ( const char * URL )
{
* * * * * If it ' s a NULL pointer * * * * *
if ( ! URL )
return false ;
* * * * * If it ' s the empty string * * * * *
if ( ! URL [ 0 ] )
return false ;
* * * * * Check if start by http : // or https:// *****
if ( ! strncasecmp ( URL , " http:// " , 7 ) | | ! strncasecmp ( URL , " https:// " , 8 ) )
return ( bool ) ( strchr ( URL , ( int ) ' . ' ) ! = NULL ) ; // There is any . in the URL
else // There's no http:// nor https://
return false ;
}
*/
/*****************************************************************************/
/***** Convert a string to title: first uppercase and the rest lowercase *****/
/*****************************************************************************/
void Str_ConvertToTitleType ( char * Str )
{
char Ch , * Ptr , * Ptr2 ;
int LengthStr ;
bool FirstLetter = true ;
for ( Ptr = Str ;
* Ptr ;
Ptr + + )
{
Ch = * Ptr ;
if ( isspace ( ( int ) Ch ) | |
2015-03-20 14:30:28 +01:00
Ch = = ' \xA0 ' | | // Unicode translation for
2014-12-01 23:55:08 +01:00
Ch = = ' - ' | |
Ch = = ' ( ' | |
Ch = = ' ) ' | |
Ch = = ' , ' | |
Ch = = ' ; ' | |
Ch = = ' . ' | |
Ch = = ' : ' | |
Ch = = ' <EFBFBD> ' | |
Ch = = ' <EFBFBD> ' )
FirstLetter = true ;
else
{
if ( FirstLetter )
{
/* Check if it's "de", "del", "la", "y" */ // This should be internationalized!!!!!
for ( Ptr2 = Ptr , LengthStr = 0 ;
* Ptr2 ;
Ptr2 + + , LengthStr + + )
2015-03-20 14:30:28 +01:00
if ( isspace ( ( int ) * Ptr2 ) | |
* Ptr2 = = ' \xA0 ' ) // Unicode translation for
2014-12-01 23:55:08 +01:00
break ;
if ( LengthStr = = 1 )
{
if ( ! strncasecmp ( Ptr , " y " , 1 ) )
FirstLetter = false ;
}
else if ( LengthStr = = 2 )
{
if ( ! strncasecmp ( Ptr , " de " , 2 ) )
FirstLetter = false ;
else if ( ! strncasecmp ( Ptr , " la " , 2 ) )
FirstLetter = false ;
}
else if ( LengthStr = = 3 )
if ( ! strncasecmp ( Ptr , " del " , 3 ) )
FirstLetter = false ;
}
if ( FirstLetter )
{
* Ptr = Str_ConvertToUpperLetter ( * Ptr ) ;
FirstLetter = false ;
}
else
* Ptr = Str_ConvertToLowerLetter ( * Ptr ) ;
}
}
}
/*****************************************************************************/
/*** Changes a string to made it comparable with others (removing tildes) ****/
/*****************************************************************************/
void Str_ConvertToComparable ( char * Str )
{
char * Ptr ;
for ( Ptr = Str ;
* Ptr ;
Ptr + + )
{
* Ptr = Str_ConvertToLowerLetter ( * Ptr ) ;
switch ( * Ptr )
{
case ' <EFBFBD> ' : * Ptr = ' a ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' e ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' i ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' o ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' u ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' a ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' e ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' i ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' o ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' u ' ; break ;
}
}
}
/*****************************************************************************/
/********************** Convert a string to uppercase ************************/
/*****************************************************************************/
char * Str_ConvertToUpperText ( char * Str )
{
char * Ptr ;
for ( Ptr = Str ;
* Ptr ;
Ptr + + )
* Ptr = Str_ConvertToUpperLetter ( * Ptr ) ;
return Str ;
}
/*****************************************************************************/
/********************** Convert a string to lowercase ************************/
/*****************************************************************************/
char * Str_ConvertToLowerText ( char * Str )
{
char * Ptr ;
for ( Ptr = Str ;
* Ptr ;
Ptr + + )
* Ptr = Str_ConvertToLowerLetter ( * Ptr ) ;
return Str ;
}
/*****************************************************************************/
/*********************** Convert a character to uppercase ********************/
/*****************************************************************************/
char Str_ConvertToUpperLetter ( char Ch )
{
switch ( Ch )
{
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
default : return ( char ) toupper ( ( int ) Ch ) ;
}
}
/*****************************************************************************/
/*********************** Convert a character to lowercase ********************/
/*****************************************************************************/
char Str_ConvertToLowerLetter ( char Ch )
{
switch ( Ch )
{
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
case ' <EFBFBD> ' : return ' <EFBFBD> ' ;
default : return ( char ) tolower ( ( int ) Ch ) ;
}
}
2015-03-11 14:35:33 +01:00
/*****************************************************************************/
/******** Write a number in floating point with the correct accuracy *********/
/*****************************************************************************/
void Str_WriteFloatNum ( float Number )
{
double IntegerPart ;
double FractionaryPart ;
char * Format ;
FractionaryPart = modf ( ( double ) Number , & IntegerPart ) ;
if ( FractionaryPart = = 0.0 )
fprintf ( Gbl . F . Out , " %.0f " , IntegerPart ) ;
else
{
if ( IntegerPart ! = 0.0 | | FractionaryPart > = 0.1 )
Format = " %.2f " ;
else if ( FractionaryPart > = 0.01 )
Format = " %.3f " ;
else if ( FractionaryPart > = 0.001 )
Format = " %.4f " ;
else if ( FractionaryPart > = 0.0001 )
Format = " %.5f " ;
else if ( FractionaryPart > = 0.00001 )
Format = " %.6f " ;
else if ( FractionaryPart > = 0.000001 )
Format = " %.7f " ;
else
Format = " %e " ;
fprintf ( Gbl . F . Out , Format , Number ) ;
}
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/********** Convert a string that holds a number in floating comma ***********/
/********** to another in floating point changing commas to points ***********/
/*****************************************************************************/
void Str_ConvertStrFloatCommaToStrFloatPoint ( char * Str )
{
for ( ;
* Str ;
Str + + )
if ( * Str = = ' , ' )
* Str = ' . ' ;
}
/*****************************************************************************/
/************** Read a number in floating point from a string ****************/
/*****************************************************************************/
float Str_GetFloatNumFromStr ( const char * Str )
{
float Num ;
if ( Str )
{
2014-12-21 19:43:39 +01:00
setlocale ( LC_NUMERIC , " en_US.utf8 " ) ; // To get the decimal point
2014-12-01 23:55:08 +01:00
if ( sscanf ( Str , " %f " , & Num ) ! = 1 )
Lay_ShowErrorAndExit ( " Bad floating point format. " ) ;
2014-12-21 19:43:39 +01:00
setlocale ( LC_NUMERIC , " es_ES.utf8 " ) ;
2014-12-01 23:55:08 +01:00
}
else // Str == NULL
Num = 0.0 ;
return Num ;
}
/*****************************************************************************/
/*************** Add a string to a Query, changing ' for ' ***************/
/*****************************************************************************/
void Str_AddStrToQuery ( char * Query , const char * Str , size_t SizeOfQuery )
{
size_t LengthOfQuery = strlen ( Query ) ;
size_t SizeOfQuery_6 = SizeOfQuery - 6 ;
size_t SizeOfQuery_2 = SizeOfQuery - 2 ;
// Query can not have a ' character
for ( ;
* Str ;
Str + + )
if ( * Str = = ' \' ' ) // It's a ' ...
{
if ( LengthOfQuery > SizeOfQuery_6 )
break ;
Query [ LengthOfQuery + + ] = ' & ' ;
Query [ LengthOfQuery + + ] = ' # ' ;
Query [ LengthOfQuery + + ] = ' 3 ' ;
Query [ LengthOfQuery + + ] = ' 9 ' ;
Query [ LengthOfQuery + + ] = ' ; ' ; // ...add the HTML special character '
}
else // It's another character...
{
if ( LengthOfQuery > SizeOfQuery_2 )
break ;
Query [ LengthOfQuery + + ] = * Str ; // ...add the character without changes
}
Query [ LengthOfQuery ] = ' \0 ' ;
}
/*****************************************************************************/
/******************** Change the format of a string **************************/
/*****************************************************************************/
/*
ChangeFrom can be :
Str_FROM_FORM
Str_FROM_TEXT
Str_FROM_HTML
ChangeTo can be :
Str_DONT_CHANGE
Str_TO_TEXT
2015-04-07 21:44:24 +02:00
Str_TO_MARKDOWN
2014-12-01 23:55:08 +01:00
Str_TO_HTML
Str_TO_RIGOROUS_HTML
For example the string " Nueva++de+San+Ant%F3n "
is converted to :
" Nueva de San Ant<6E> n " if ChangeTo = = Str_TO_RIGOROUS_HTML
" Nueva de San Ant<6E> n " if ChangeTo = = Str_TO_HTML
" Nueva de San Ant<6E> n " if ChangeTo = = Str_TO_TEXT
*/
void Str_ChangeFormat ( Str_ChangeFrom_t ChangeFrom , Str_ChangeTo_t ChangeTo ,
char * Str , size_t MaxLengthStr , bool RemoveLeadingAndTrailingSpaces )
{
char * StrDst ;
char * PtrSrc ;
char * PtrDst ;
unsigned int SpecialChar ;
size_t LengthSpecStrSrc = 0 ;
size_t LengthSpecStrDst ;
unsigned long LengthStrDst = 0 ;
unsigned NumSpacesTab ;
unsigned i ;
unsigned NumPrintableCharsFromReturn = 0 ; // To substitute tabs for spaces
bool IsSpecialChar = false ;
bool ThereIsSpaceChar = true ; // Indicates if the character before was a space. Set to true to respect the initial spaces.
char StrSpecialChar [ 256 ] ;
/*
2015-02-01 20:17:24 +01:00
if ( Gbl . Usrs . Me . LoggedRole = = Rol_ROLE_SYS_ADM )
2014-12-01 23:55:08 +01:00
{
sprintf ( Gbl . Message , " Str_ChangeFormat ("%s") " , Str ) ;
Lay_ShowAlert ( Lay_INFO , Gbl . Message ) ;
}
*/
if ( ChangeTo ! = Str_DONT_CHANGE )
{
/***** Allocate memory for a destination string where to do the changes *****/
if ( ( StrDst = ( char * ) malloc ( MaxLengthStr ) ) = = NULL )
Lay_ShowErrorAndExit ( " Not enough memory to change the format of a string. " ) ;
/***** Make the change *****/
for ( PtrSrc = Str , PtrDst = StrDst ;
* PtrSrc ; )
{
switch ( ChangeFrom )
{
case Str_FROM_FORM :
switch ( ( unsigned char ) * PtrSrc )
{
case ' + ' : /***** Change every '+' to a space *****/
IsSpecialChar = true ;
LengthSpecStrSrc = 1 ;
SpecialChar = 0x20 ;
break ;
case ' % ' : /***** Change "%XX" --> "&#decimal_number;" *****/
IsSpecialChar = true ;
sscanf ( PtrSrc + 1 , " %2X " , & SpecialChar ) ;
LengthSpecStrSrc = 3 ;
break ;
case ' \' ' : /***** Change "'" --> "'" to avoid SQL code injection *****/
IsSpecialChar = true ;
LengthSpecStrSrc = 1 ;
SpecialChar = 0x27 ;
break ;
2015-04-07 21:44:24 +02:00
case ' \\ ' :
IsSpecialChar = true ;
LengthSpecStrSrc = 1 ;
SpecialChar = 0x5C ;
break ;
2014-12-01 23:55:08 +01:00
default :
IsSpecialChar = false ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
}
break ;
case Str_FROM_HTML :
case Str_FROM_TEXT :
switch ( ( unsigned char ) * PtrSrc )
{
case 0x20 : /***** Change every ' ' to a space *****/
IsSpecialChar = true ;
LengthSpecStrSrc = 1 ;
SpecialChar = 0x20 ;
break ;
case ' \' ' : /***** Change "'" --> "'" to avoid SQL code injection *****/
IsSpecialChar = true ;
LengthSpecStrSrc = 1 ;
SpecialChar = 0x27 ;
break ;
2015-04-07 21:44:24 +02:00
case ' \\ ' :
IsSpecialChar = true ;
LengthSpecStrSrc = 1 ;
SpecialChar = 0x5C ;
break ;
2014-12-01 23:55:08 +01:00
default :
if ( ( unsigned char ) * PtrSrc < 0x20 )
{
IsSpecialChar = true ;
LengthSpecStrSrc = 1 ;
SpecialChar = ( unsigned int ) ( unsigned char ) * PtrSrc ;
}
else
{
IsSpecialChar = false ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
}
break ;
}
break ;
}
if ( IsSpecialChar )
{
switch ( SpecialChar )
{
case 0x09 : /* Tab */
if ( ChangeTo = = Str_TO_RIGOROUS_HTML )
{
/* Change tab to spaces (so many spaces as left until the next multiple of 8) */
StrSpecialChar [ 0 ] = ' \0 ' ;
NumSpacesTab = 8 - NumPrintableCharsFromReturn % 8 ;
// Insert a space to separate former string from
// This space is not printed on screen in HTML,
// but it is necessary to mark the end of a possible previous URL
strcat ( StrSpecialChar ,
ThereIsSpaceChar ? " " :
" " ) ; // The first space
for ( i = 1 ;
i < NumSpacesTab ;
i + + ) // Rest of spaces, except the first
strcat ( StrSpecialChar , " " ) ; // Add a space
NumPrintableCharsFromReturn + = NumSpacesTab ;
}
else
strcpy ( StrSpecialChar , " \t " ) ;
ThereIsSpaceChar = true ;
break ;
case 0x0A : /* \n */
strcpy ( StrSpecialChar ,
ChangeTo = = Str_TO_RIGOROUS_HTML ? " <br /> " :
Str_LF ) ;
NumPrintableCharsFromReturn = 0 ;
ThereIsSpaceChar = true ;
break ;
case 0x0D : /* "%0D" --> "" */
strcpy ( StrSpecialChar ,
ChangeTo = = Str_TO_RIGOROUS_HTML ? " " :
Str_CR ) ;
NumPrintableCharsFromReturn = 0 ;
ThereIsSpaceChar = true ;
break ;
case 0x20 : /* Space */
strcpy ( StrSpecialChar ,
( ChangeTo = = Str_TO_RIGOROUS_HTML & & ThereIsSpaceChar ) ? " " :
" " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = true ;
break ;
case 0x22 : /* "%22" --> """ (double comilla) */
2015-04-07 21:44:24 +02:00
if ( ChangeTo = = Str_TO_MARKDOWN )
{ // Escape sequence for database, two characters
StrSpecialChar [ 0 ] = ' \\ ' ; // 1. An inverted bar
StrSpecialChar [ 1 ] = ' \" ' ; // 2. A double comilla
StrSpecialChar [ 2 ] = ' \0 ' ; // End of string
}
else
sprintf ( StrSpecialChar , " " " ) ; // Double comilla is stored as HTML code to avoid problems when displaying it
2014-12-01 23:55:08 +01:00
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0x23 : /* "%23" --> "#" */
strcpy ( StrSpecialChar , " # " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0x26 : /* "%26" --> "&" (&) */
strcpy ( StrSpecialChar , " & " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0x27 : /* "%27" --> "'" (single comilla) */
2015-04-07 21:44:24 +02:00
if ( ChangeTo = = Str_TO_MARKDOWN )
{ // Escape sequence for database, two characters
StrSpecialChar [ 0 ] = ' \\ ' ; // 1. An inverted bar
StrSpecialChar [ 1 ] = ' \' ' ; // 2. A single comilla
StrSpecialChar [ 2 ] = ' \0 ' ; // End of string
}
else
sprintf ( StrSpecialChar , " ' " ) ; // Single comilla is stored as HTML code to avoid problem when querying database (SQL code injection)
2014-12-01 23:55:08 +01:00
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0x2C : /* "%2C" --> "," */
strcpy ( StrSpecialChar , " , " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0x2F : /* "%2F" --> "/" */
strcpy ( StrSpecialChar , " / " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0x3A : /* "%3A" --> ":" */
strcpy ( StrSpecialChar , " : " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0x3B : /* "%3B" --> ";" */
strcpy ( StrSpecialChar , " ; " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0x3C : /* "%3C" --> "<" (<) */
2015-04-07 21:44:24 +02:00
if ( ChangeTo = = Str_TO_MARKDOWN )
strcpy ( StrSpecialChar , " < " ) ;
else
strcpy ( StrSpecialChar , " < " ) ; // "<" is stored as HTML code to avoid problems when displaying it
2014-12-01 23:55:08 +01:00
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0x3E : /* "%3E" --> ">" (>) */
2015-04-07 21:44:24 +02:00
if ( ChangeTo = = Str_TO_MARKDOWN )
strcpy ( StrSpecialChar , " > " ) ;
else
strcpy ( StrSpecialChar , " > " ) ; // ">" is stored as HTML code to avoid problems when displaying it
2014-12-01 23:55:08 +01:00
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0x3F : /* "%3F" --> "?" */
strcpy ( StrSpecialChar , " ? " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
2015-04-07 21:44:24 +02:00
case 0x5C : /* "%5C" --> "\" (\) */
if ( ChangeTo = = Str_TO_MARKDOWN )
{ // Escape sequence for database, two characters
StrSpecialChar [ 0 ] = ' \\ ' ; // 1. An inverted bar
StrSpecialChar [ 1 ] = ' \\ ' ; // 2. An inverted bar
StrSpecialChar [ 2 ] = ' \0 ' ; // End of string
}
else
strcpy ( StrSpecialChar , " \ " ) ; // "\" is stored as HTML code to avoid problems when displaying it
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
2014-12-01 23:55:08 +01:00
case 0xC1 : /* "%C1" --> "<22> " */
strcpy ( StrSpecialChar , " <EFBFBD> " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0xC9 : /* "%C9" --> "<22> " */
strcpy ( StrSpecialChar , " <EFBFBD> " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0xCD : /* "%CD" --> "<22> " */
strcpy ( StrSpecialChar , " <EFBFBD> " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0xD3 : /* "%D3" --> "<22> " */
strcpy ( StrSpecialChar , " <EFBFBD> " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0xDA : /* "%DA" --> "<22> " */
strcpy ( StrSpecialChar , " <EFBFBD> " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0xD1 : /* "%D1" --> "<22> " */
strcpy ( StrSpecialChar , " <EFBFBD> " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0xC7 : /* "%C7" --> "<22> " */
strcpy ( StrSpecialChar , " <EFBFBD> " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0xE1 : /* "%E1" --> "<22> " */
strcpy ( StrSpecialChar , " <EFBFBD> " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0xE9 : /* "%E9" --> "<22> " */
strcpy ( StrSpecialChar , " <EFBFBD> " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0xED : /* "%ED" --> "<22> " */
strcpy ( StrSpecialChar , " <EFBFBD> " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0xF3 : /* "%F3" --> "<22> " */
strcpy ( StrSpecialChar , " <EFBFBD> " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0xFA : /* "%FA" --> "<22> " */
strcpy ( StrSpecialChar , " <EFBFBD> " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0xF1 : /* "%F1" --> "<22> " */
strcpy ( StrSpecialChar , " <EFBFBD> " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
case 0xE7 : /* "%E7" --> "<22> " */
strcpy ( StrSpecialChar , " <EFBFBD> " ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
default : /* The rest of special chars are stored as special code */
sprintf ( StrSpecialChar ,
2015-04-07 21:44:24 +02:00
( ChangeTo = = Str_TO_TEXT | |
ChangeTo = = Str_TO_MARKDOWN ) ? " %c " :
" &#%u; " ,
2014-12-01 23:55:08 +01:00
SpecialChar ) ;
NumPrintableCharsFromReturn + + ;
ThereIsSpaceChar = false ;
break ;
}
/* Compute length of destination special char */
LengthSpecStrDst = strlen ( StrSpecialChar ) ;
/* Check new length of destination string after the copy */
if ( LengthStrDst + LengthSpecStrDst > MaxLengthStr )
Lay_ShowErrorAndExit ( " Space allocated to string is full. " ) ;
/* Copy to appropiate place the special character string */
strncpy ( PtrDst , StrSpecialChar , LengthSpecStrDst ) ;
/* Increment pointer to character after ';' */
PtrSrc + = LengthSpecStrSrc ;
PtrDst + = LengthSpecStrDst ;
/* Increment length of destination string */
LengthStrDst + = LengthSpecStrDst ;
}
else // Not a special char ==> copy char from source to destination
{
/* Check new length of destination string after the copy */
if ( LengthStrDst > = MaxLengthStr )
Lay_ShowErrorAndExit ( " Space allocated to string is full. " ) ;
/* Copy char from source to destination and increment pointers */
* PtrDst + + = * PtrSrc + + ;
/* Increment length of destination string */
LengthStrDst + + ;
}
}
/***** Copy destination string with changes to source string *****/
strncpy ( Str , StrDst , LengthStrDst ) ; // Str <-- StrDst
Str [ LengthStrDst ] = ' \0 ' ;
/***** Free memory used for the destination string *****/
free ( ( void * ) StrDst ) ;
}
if ( RemoveLeadingAndTrailingSpaces )
{
/***** Remove leading spaces *****/
Str_RemoveLeadingSpacesHTML ( Str ) ;
/***** Remove trailing spaces *****/
Str_RemoveTrailingSpacesHTML ( Str ) ;
}
}
/*****************************************************************************/
/****************** Remove the spaces iniciales of a string ******************/
/*****************************************************************************/
void Str_RemoveLeadingSpacesHTML ( char * Str )
{
char * Ptr ;
/***** Find the first character no space from left to right *****/
for ( Ptr = Str ;
* Ptr ;
Ptr + + )
{
/* If it's space ==> continue in the loop */
2015-03-20 14:30:28 +01:00
if ( isspace ( ( int ) * Ptr ) | |
* Ptr = = ' \xA0 ' ) // Unicode translation for
2014-12-01 23:55:08 +01:00
continue ;
/* Check forward if it's a <br> or <br /> */
if ( * Ptr = = ' < ' )
{
Ptr + + ;
if ( tolower ( ( int ) * Ptr ) ! = ' b ' )
{
Ptr - - ;
break ;
}
if ( ! * Ptr )
break ;
Ptr + + ;
if ( tolower ( ( int ) * Ptr ) ! = ' r ' )
{
Ptr - = 2 ;
break ;
}
if ( ! * Ptr )
break ;
Ptr + + ;
if ( * Ptr = = ' > ' )
continue ; // It's <br>
if ( * Ptr ! = ' ' )
{
Ptr - = 3 ;
break ;
}
if ( ! * Ptr )
break ;
Ptr + + ;
if ( * Ptr ! = ' / ' )
{
Ptr - = 4 ;
break ;
}
if ( ! * Ptr )
break ;
Ptr + + ;
if ( * Ptr ! = ' > ' )
{
Ptr - = 5 ;
break ;
}
continue ; // It's <br />
}
/* Check forward if it's */
if ( * Ptr = = ' & ' )
{
Ptr + + ;
if ( tolower ( ( int ) * Ptr ) ! = ' n ' )
{
Ptr - - ;
break ;
}
if ( ! * Ptr )
break ;
Ptr + + ;
if ( tolower ( ( int ) * Ptr ) ! = ' b ' )
{
Ptr - = 2 ;
break ;
}
if ( ! * Ptr )
break ;
Ptr + + ;
if ( tolower ( ( int ) * Ptr ) ! = ' s ' )
{
Ptr - = 3 ;
break ;
}
if ( ! * Ptr )
break ;
Ptr + + ;
if ( tolower ( ( int ) * Ptr ) ! = ' p ' )
{
Ptr - = 4 ;
break ;
}
if ( ! * Ptr )
break ;
Ptr + + ;
if ( * Ptr ! = ' ; ' )
{
Ptr - = 5 ;
break ;
}
/* It's */
continue ;
}
/* It's not space */
break ;
}
/***** Ptr is the first character no space *****/
if ( Ptr ! = Str )
{
/* Copy string pointed by Ptr to Str.
Do not use strcpy because according to strcpy manual :
" The source and destination strings should not overlap,
as the behavior is undefined " */
while ( * Ptr )
* Str + + = * Ptr + + ;
* Str = ' \0 ' ;
}
}
/*****************************************************************************/
/******************* Remove the trailing spaces of a string ******************/
/*****************************************************************************/
void Str_RemoveTrailingSpacesHTML ( char * Str )
{
char * Ptr ;
/* Find the first not space character starting at the end */
for ( Ptr = Str + strlen ( Str ) - 1 ;
Ptr > = Str ;
Ptr - - )
{
/* If it's space ==> continue in the loop */
2015-03-20 14:30:28 +01:00
if ( isspace ( ( int ) * Ptr ) | |
* Ptr = = ' \xA0 ' ) // Unicode translation for
2014-12-01 23:55:08 +01:00
continue ;
/* Check backward if it's <br> or <br /> */
if ( * Ptr = = ' > ' )
{
if ( Ptr = = Str )
break ;
Ptr - - ;
if ( * Ptr = = ' / ' ) // Possible <br />
{
if ( Ptr = = Str )
break ;
Ptr - - ;
if ( * Ptr ! = ' ' )
{
Ptr + = 2 ;
break ;
}
if ( Ptr = = Str )
break ;
Ptr - - ;
if ( tolower ( ( int ) * Ptr ) ! = ' r ' )
{
Ptr + = 3 ;
break ;
}
if ( Ptr = = Str )
break ;
Ptr - - ;
if ( tolower ( ( int ) * Ptr ) ! = ' b ' )
{
Ptr + = 4 ;
break ;
}
if ( Ptr = = Str )
break ;
Ptr - - ;
if ( * Ptr ! = ' < ' )
{
Ptr + = 5 ;
break ;
}
/* It's <br /> */
continue ;
}
else // Possible <br>
{
if ( tolower ( ( int ) * Ptr ) ! = ' r ' )
{
Ptr + + ;
break ;
}
if ( Ptr = = Str )
break ;
Ptr - - ;
if ( tolower ( ( int ) * Ptr ) ! = ' b ' )
{
Ptr + = 2 ;
break ;
}
if ( Ptr = = Str )
break ;
Ptr - - ;
if ( * Ptr ! = ' < ' )
{
Ptr + = 3 ;
break ;
}
/* It's <br> */
continue ;
}
}
/* Check backward if it's */
if ( * Ptr = = ' ; ' )
{
if ( Ptr = = Str )
break ;
Ptr - - ;
if ( tolower ( ( int ) * Ptr ) ! = ' p ' )
{
Ptr + + ;
break ;
}
if ( Ptr = = Str )
break ;
Ptr - - ;
if ( tolower ( ( int ) * Ptr ) ! = ' s ' )
{
Ptr + = 2 ;
break ;
}
if ( Ptr = = Str )
break ;
Ptr - - ;
if ( tolower ( ( int ) * Ptr ) ! = ' b ' )
{
Ptr + = 3 ;
break ;
}
if ( Ptr = = Str )
break ;
Ptr - - ;
if ( tolower ( ( int ) * Ptr ) ! = ' n ' )
{
Ptr + = 4 ;
break ;
}
if ( Ptr = = Str )
break ;
Ptr - - ;
if ( * Ptr ! = ' & ' )
{
Ptr + = 5 ;
break ;
}
/* It's */
continue ;
}
/* It's not space */
break ;
}
* ( Ptr + 1 ) = ' \0 ' ;
}
/*****************************************************************************/
2015-10-07 19:55:13 +02:00
/********* Remove the leading zeros ('0', not '\0') from a string ************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
void Str_RemoveLeadingZeros ( char * Str )
{
2015-10-07 19:55:13 +02:00
size_t NumLeadingZeros ;
2014-12-01 23:55:08 +01:00
2015-10-07 19:55:13 +02:00
if ( Str )
if ( Str [ 0 ] )
{
NumLeadingZeros = strspn ( Str , " 0 " ) ;
if ( NumLeadingZeros )
// Do not use strcpy / memcpy because the strings overlap
memmove ( Str , & Str [ NumLeadingZeros ] ,
strlen ( Str ) - NumLeadingZeros + 1 ) ;
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/***************** Delete @'s at the start of a string ***********************/
/*****************************************************************************/
2015-10-07 19:55:13 +02:00
# include "swad_database.h"
2014-12-01 23:55:08 +01:00
void Str_RemoveLeadingArrobas ( char * Str )
{
2015-10-07 19:55:13 +02:00
size_t NumLeadingArrobas ;
2014-12-01 23:55:08 +01:00
2015-10-07 19:55:13 +02:00
if ( Str )
if ( Str [ 0 ] )
{
NumLeadingArrobas = strspn ( Str , " @ " ) ;
if ( NumLeadingArrobas )
// Do not use strcpy / memcpy because the strings overlap
memmove ( Str , & Str [ NumLeadingArrobas ] ,
strlen ( Str ) - NumLeadingArrobas + 1 ) ;
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*************** Find string in a HTML file skipping comments ****************/
/*****************************************************************************/
/*
Search ( case insensitive ) the string Str in HTML file FileSrc , skipping comments .
Returns true if found .
Returns false if not found .
*/
bool Str_FindStrInFile ( FILE * FileSrc , const char * Str , Str_SkipHTMLComments_t SkipHTMLComments )
{
int i ;
int Length = strlen ( Str ) ;
int Ch ;
long CurPos ;
for ( ; ; )
{
/* Skip possible comments */
if ( ( Ch = Str_ReadCharAndSkipComments ( FileSrc , SkipHTMLComments ) ) = = EOF ) // Set pointer to '<' if not comment, or to first character after comment if comment
return false ;
CurPos = ftell ( FileSrc ) ;
if ( Str_ConvertToLowerLetter ( ( char ) Ch ) = = Str_ConvertToLowerLetter ( Str [ 0 ] ) ) // First char found
{
for ( i = 1 ;
i < Length ;
i + + )
{
/* Skip possible comments */
if ( ( Ch = Str_ReadCharAndSkipComments ( FileSrc , SkipHTMLComments ) ) = = EOF ) // Set pointer to '<' if not comment, or to first character after comment if comment
return false ;
if ( Str_ConvertToLowerLetter ( ( char ) Ch ) ! = Str_ConvertToLowerLetter ( Str [ i ] ) )
break ;
}
if ( i = = Length ) // Found!
return true ;
else // Not found, continue on next character
fseek ( FileSrc , CurPos , SEEK_SET ) ;
}
}
return false ; // Not reached
}
/*****************************************************************************/
/******************* Search a string in a file backward **********************/
/*****************************************************************************/
/* The file queda posicionado in:
If found - - > in the character anterior to the first of the string
If no found - - > to the principio of the file */
bool Str_FindStrInFileBack ( FILE * FileSrc , const char * Str , Str_SkipHTMLComments_t SkipHTMLComments )
{
int i ;
int Length = strlen ( Str ) ;
int Ch ;
int ChFinal ;
long CurPos ;
ChFinal = Str_ConvertToLowerLetter ( Str [ Length - 1 ] ) ;
if ( fseek ( FileSrc , - 1L , SEEK_CUR ) ) // Go to the previous character
return false ;
for ( ; ; )
{
if ( ( Ch = Str_ReadCharAndSkipCommentsBackward ( FileSrc , SkipHTMLComments ) ) = = EOF ) // Set pointer to '>' if not comment, or to character before start of comment if comment
return false ;
CurPos = ftell ( FileSrc ) ;
if ( Str_ConvertToLowerLetter ( ( char ) Ch ) = = ( char ) ChFinal )
{
for ( i = Length - 2 ;
i > = 0 ;
i - - )
{
if ( fseek ( FileSrc , - 2L , SEEK_CUR ) )
return false ;
if ( ( Ch = Str_ReadCharAndSkipCommentsBackward ( FileSrc , SkipHTMLComments ) ) = = EOF ) // Set pointer to '>' if not comment, or to character before start of comment if comment
return false ;
if ( Str_ConvertToLowerLetter ( ( char ) Ch ) ! = Str_ConvertToLowerLetter ( Str [ i ] ) )
break ;
}
if ( i < 0 ) // Found!
{
fseek ( FileSrc , - 1L , SEEK_CUR ) ; // Move to start of found string in FileSrc
return true ;
}
else // Not found, continue on next character
fseek ( FileSrc , CurPos , SEEK_SET ) ;
}
if ( fseek ( FileSrc , - 2L , SEEK_CUR ) ) // Move to previous character
return false ;
}
return false ; // Not reached
}
/*****************************************************************************/
/************* Search a string in a file writing in FileTgt ******************/
/*****************************************************************************/
/*
Search in the file FileSrc the string Str without distinguish uppercase from
lowercase . Write in FileTgt what is read from the file FileSrc .
*/
bool Str_WriteUntilStrFoundInFileIncludingStr ( FILE * FileTgt , FILE * FileSrc , const char * Str , Str_SkipHTMLComments_t SkipHTMLComments )
{
int i ;
int StrLength = strlen ( Str ) ;
int Ch ;
long CurPos1 , CurPos2 ;
for ( ; ; )
{
/* Skip possible comments */
if ( ( Ch = Str_ReadCharAndSkipCommentsWriting ( FileSrc , FileTgt , SkipHTMLComments ) ) = = EOF ) // Set pointer to '<' if not comment, or to first character after comment if comment
return false ;
CurPos1 = ftell ( FileSrc ) ;
fputc ( Ch , FileTgt ) ;
if ( Str_ConvertToLowerLetter ( ( char ) Ch ) = = Str_ConvertToLowerLetter ( Str [ 0 ] ) ) // Found first character
{
for ( i = 1 ;
i < StrLength ;
i + + )
{
/* Skip possible comments */
if ( ( Ch = Str_ReadCharAndSkipComments ( FileSrc , SkipHTMLComments ) ) = = EOF ) // Set pointer to '<' if not comment, or to first character after comment if comment
return false ;
if ( Str_ConvertToLowerLetter ( ( char ) Ch ) ! = Str_ConvertToLowerLetter ( Str [ i ] ) )
break ;
}
if ( i = = StrLength ) // Found!
{
CurPos2 = ftell ( FileSrc ) ;
fseek ( FileSrc , CurPos1 , SEEK_SET ) ;
while ( ftell ( FileSrc ) < CurPos2 )
{
Ch = fgetc ( FileSrc ) ;
fputc ( Ch , FileTgt ) ;
}
return true ;
}
else // Not found, continue on next character
fseek ( FileSrc , CurPos1 , SEEK_SET ) ;
}
}
return false ; // Not reached
}
/*****************************************************************************/
/*********************** Skip HTML comments in FileSrc ***********************/
/*****************************************************************************/
// Set pointer to '<' if not comment, or to first character after comment if comment
// Returns last char read after comments
static int Str_ReadCharAndSkipComments ( FILE * FileSrc , Str_SkipHTMLComments_t SkipHTMLComments )
{
int Ch ;
char StrAux [ 1 + 1 ] ; /* To check "!--" string */
Ch = fgetc ( FileSrc ) ;
if ( SkipHTMLComments )
while ( Ch = = ( int ) ' < ' )
{
/***** Check if "<!--" *****/
if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 1 ) , " ! " ) )
{
Str_FindStrInFileBack ( FileSrc , " < " , Str_NO_SKIP_HTML_COMMENTS ) ; // Not a comment. Return to start of directive
return fgetc ( FileSrc ) ;
}
if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 1 ) , " - " ) )
{
Str_FindStrInFileBack ( FileSrc , " < " , Str_NO_SKIP_HTML_COMMENTS ) ; // Not a comment. Return to start of directive
return fgetc ( FileSrc ) ;
}
if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 1 ) , " - " ) )
{
Str_FindStrInFileBack ( FileSrc , " < " , Str_NO_SKIP_HTML_COMMENTS ) ; // Not a comment. Return to start of directive
return fgetc ( FileSrc ) ;
}
/***** It's a comment ==> skip comment *****/
Str_FindStrInFile ( FileSrc , " --> " , Str_NO_SKIP_HTML_COMMENTS ) ;
/***** Get next character *****/
Ch = fgetc ( FileSrc ) ;
}
return Ch ;
}
/*****************************************************************************/
/************* Skip HTML comments in FileSrc writing into FileTgt ************/
/*****************************************************************************/
// Set pointer to '<' if not comment, or to first character after comment if comment
// Returns last char read after comments
static int Str_ReadCharAndSkipCommentsWriting ( FILE * FileSrc , FILE * FileTgt , Str_SkipHTMLComments_t SkipHTMLComments )
{
int Ch ;
char StrAux [ 1 + 1 ] ; /* To check "!--" string */
Ch = fgetc ( FileSrc ) ;
if ( SkipHTMLComments )
while ( Ch = = ( int ) ' < ' )
{
/***** Check if "<!--" *****/
if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 1 ) , " ! " ) )
{
Str_FindStrInFileBack ( FileSrc , " < " , Str_NO_SKIP_HTML_COMMENTS ) ; // Not a comment. Return to start of directive
return fgetc ( FileSrc ) ;
}
if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 1 ) , " - " ) )
{
Str_FindStrInFileBack ( FileSrc , " < " , Str_NO_SKIP_HTML_COMMENTS ) ; // Not a comment. Return to start of directive
return fgetc ( FileSrc ) ;
}
if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 1 ) , " - " ) )
{
Str_FindStrInFileBack ( FileSrc , " < " , Str_NO_SKIP_HTML_COMMENTS ) ; // Not a comment. Return to start of directive
return fgetc ( FileSrc ) ;
}
/***** It's a comment ==> skip comment *****/
Str_FindStrInFileBack ( FileSrc , " < " , Str_NO_SKIP_HTML_COMMENTS ) ; // Return to start of comment
Str_WriteUntilStrFoundInFileIncludingStr ( FileTgt , FileSrc , " --> " , Str_NO_SKIP_HTML_COMMENTS ) ; // Skip comment in search, and write it to FileTgt
/***** Get next character *****/
Ch = fgetc ( FileSrc ) ;
}
return Ch ;
}
/*****************************************************************************/
/******************************* Skip a comment ******************************/
/*****************************************************************************/
// Set pointer to '>' if not comment, or to character previous to start of comment if comment
// Returns char preceeding comments, of EOF if start of file reached
static int Str_ReadCharAndSkipCommentsBackward ( FILE * FileSrc , Str_SkipHTMLComments_t SkipHTMLComments )
{
int Ch ;
char StrAux [ 3 + 1 ] ; /* To check "--" string */
Ch = fgetc ( FileSrc ) ;
if ( SkipHTMLComments )
while ( Ch = = ( int ) ' > ' )
{
/* Check if "-->" */
// Now: "<!--example of comment-->..."
// ^
if ( fseek ( FileSrc , - 3L , SEEK_CUR ) ) // Go to start of possible "-->" */
return EOF ;
// Now: "<!--example of comment-->..."
// ^
if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 3 ) , " --> " ) ) // Not a comment
return ' > ' ;
/***** It's a comment end *****/
Str_FindStrInFileBack ( FileSrc , " <!-- " , Str_NO_SKIP_HTML_COMMENTS ) ; // Skip comment backwards
if ( fseek ( FileSrc , - 1L , SEEK_CUR ) ) // Return to character previous to '<'
return EOF ;
/***** Get character previous to '<' *****/
Ch = fgetc ( FileSrc ) ;
}
return Ch ;
}
/*****************************************************************************/
/****** Scan next string in file FileSrc until find </td> *******/
2015-02-27 13:12:57 +01:00
/****** ( skipping comments <!--...--> and directives <...> ) *******/
2014-12-01 23:55:08 +01:00
/****** and write string into Str (MaxLength characters as much) *******/
/*****************************************************************************/
char * Str_GetCellFromHTMLTableSkipComments ( FILE * FileSrc , char * Str , int MaxLength )
{
long CurPos ;
long PosNextTR ;
long PosTD ;
int i = 0 ;
int Ch ;
2015-02-27 13:12:57 +01:00
bool SpaceFound ;
2014-12-01 23:55:08 +01:00
char StrAux [ 1 + 1 ] ; // To find next "/td>" or "nbsp;"
Str [ 0 ] = ' \0 ' ;
/***** Find next <td ...> inside current row (before next <tr) *****/
CurPos = ftell ( FileSrc ) ;
Str_FindStrInFile ( FileSrc , " <tr " , Str_NO_SKIP_HTML_COMMENTS ) ;
PosNextTR = ftell ( FileSrc ) - 3 ;
fseek ( FileSrc , CurPos , SEEK_SET ) ;
Str_FindStrInFile ( FileSrc , " <td " , Str_NO_SKIP_HTML_COMMENTS ) ;
PosTD = ftell ( FileSrc ) ;
if ( PosTD > PosNextTR )
{
// <td not found in this row ==> leave current position unchanged
fseek ( FileSrc , CurPos , SEEK_SET ) ;
return Str ;
}
Str_FindStrInFile ( FileSrc , " > " , Str_NO_SKIP_HTML_COMMENTS ) ;
for ( ; ; )
{
if ( ( Ch = Str_ReadCharAndSkipComments ( FileSrc , Str_SKIP_HTML_COMMENTS ) ) = = EOF ) // Set pointer to '<' if not comment, or to first character after comment if comment
break ;
/***** Skip directives except </td> *****/
if ( Ch = = ( int ) ' < ' ) // Start of directive, not a comment
{
/* Check if it's </td> */
if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 1 ) , " / " ) )
{ // It's not </
Str_FindStrInFileBack ( FileSrc , " < " , Str_NO_SKIP_HTML_COMMENTS ) ; // Skip directive backward
Str_FindStrInFile ( FileSrc , " > " , Str_NO_SKIP_HTML_COMMENTS ) ;
continue ;
}
if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 1 ) , " t " ) )
{ // It's not </t
Str_FindStrInFileBack ( FileSrc , " < " , Str_NO_SKIP_HTML_COMMENTS ) ; // Skip directive backward
Str_FindStrInFile ( FileSrc , " > " , Str_NO_SKIP_HTML_COMMENTS ) ;
continue ;
}
if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 1 ) , " d " ) )
{ // It's not </td
Str_FindStrInFileBack ( FileSrc , " < " , Str_NO_SKIP_HTML_COMMENTS ) ; // Skip directive backward
Str_FindStrInFile ( FileSrc , " > " , Str_NO_SKIP_HTML_COMMENTS ) ;
continue ;
}
if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 1 ) , " > " ) )
{ // It's not </td>
Str_FindStrInFileBack ( FileSrc , " < " , Str_NO_SKIP_HTML_COMMENTS ) ; // Skip directive backward
Str_FindStrInFile ( FileSrc , " > " , Str_NO_SKIP_HTML_COMMENTS ) ;
continue ;
}
break ; // If it's </td>
}
2015-02-27 13:12:57 +01:00
SpaceFound = false ;
2014-12-01 23:55:08 +01:00
/***** Skip *****/
if ( Ch = = ( int ) ' & ' )
{
/* Ver if no it's */
if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 1 ) , " n " ) )
{ // It's not &n
Str_FindStrInFileBack ( FileSrc , " & " , Str_NO_SKIP_HTML_COMMENTS ) ; // Back until &
Str_FindStrInFile ( FileSrc , " & " , Str_NO_SKIP_HTML_COMMENTS ) ; // Skip &
}
else if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 1 ) , " b " ) )
{ // It's not &nb
Str_FindStrInFileBack ( FileSrc , " & " , Str_NO_SKIP_HTML_COMMENTS ) ; // Back until &
Str_FindStrInFile ( FileSrc , " & " , Str_NO_SKIP_HTML_COMMENTS ) ; // Skip &
}
else if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 1 ) , " s " ) )
{ // It's not &nbs
Str_FindStrInFileBack ( FileSrc , " & " , Str_NO_SKIP_HTML_COMMENTS ) ; // Back until &
Str_FindStrInFile ( FileSrc , " & " , Str_NO_SKIP_HTML_COMMENTS ) ; // Skip &
}
else if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 1 ) , " p " ) )
{ // It's not  
Str_FindStrInFileBack ( FileSrc , " & " , Str_NO_SKIP_HTML_COMMENTS ) ; // Back until &
Str_FindStrInFile ( FileSrc , " & " , Str_NO_SKIP_HTML_COMMENTS ) ; // Skip &
}
else if ( strcasecmp ( Str_GetNextStrFromFileConvertingToLower ( FileSrc , StrAux , 1 ) , " ; " ))
{ // It's not
Str_FindStrInFileBack ( FileSrc , " & " , Str_NO_SKIP_HTML_COMMENTS ) ; // Back until &
Str_FindStrInFile ( FileSrc , " & " , Str_NO_SKIP_HTML_COMMENTS ) ; // Skip &
}
else // It's
2015-02-27 13:12:57 +01:00
SpaceFound = true ;
2014-12-01 23:55:08 +01:00
}
/***** Skip spaces *****/
2015-03-20 14:30:28 +01:00
if ( isspace ( Ch ) | |
Ch = = 0xA0 ) // Unicode translation for
2015-02-27 13:12:57 +01:00
SpaceFound = true ;
if ( SpaceFound )
Ch = ( int ) ' ' ;
2014-12-01 23:55:08 +01:00
2015-02-27 13:12:57 +01:00
if ( i < MaxLength )
2014-12-01 23:55:08 +01:00
Str [ i + + ] = ( char ) Ch ;
}
Str [ i ] = ' \0 ' ;
return Str ;
}
/*****************************************************************************/
/******************* Read the next N characters in a string ******************/
/*****************************************************************************/
/*
Read from the file FileSrc the next N characters converting them
to lowercase and store them in Str . Return a pointer to the string .
*/
char * Str_GetNextStrFromFileConvertingToLower ( FILE * FileSrc , char * Str , int N )
{
int i , Ch ;
for ( i = 0 ;
i < N ;
i + + )
{
if ( ( Ch = fgetc ( FileSrc ) ) = = EOF )
break ;
Str [ i ] = Str_ConvertToLowerLetter ( ( char ) Ch ) ;
}
Str [ i ] = ' \0 ' ;
return Str ;
}
/*****************************************************************************/
/********** Get from StrSrc into StrDst the next string until space **********/
/*****************************************************************************/
// Modifies *StrSrc
void Str_GetNextStringUntilSpace ( const char * * StrSrc , char * StrDst , size_t MaxLength )
{
size_t i = 0 ;
int Ch ;
/***** Skip leading spaces *****/
do
{
if ( ( Ch = ( int ) * * StrSrc ) ! = 0 )
( * StrSrc ) + + ;
}
2015-03-20 14:30:28 +01:00
while ( isspace ( Ch ) | |
Ch = = 0xA0 ) ; // Unicode translation for
2014-12-01 23:55:08 +01:00
/***** Copy string while non-space characters *****/
2015-03-20 14:30:28 +01:00
while ( Ch & &
! ( isspace ( Ch ) | |
Ch = = 0xA0 ) ) // Unicode translation for
2014-12-01 23:55:08 +01:00
{
if ( i < MaxLength )
StrDst [ i + + ] = ( char ) Ch ;
if ( ( Ch = ( int ) * * StrSrc ) ! = 0 )
( * StrSrc ) + + ;
}
StrDst [ i ] = ' \0 ' ;
}
/*****************************************************************************/
/******* Get from StrSrc into StrDst the next string until separator *********/
/*****************************************************************************/
// Modifies *StrSrc
void Str_GetNextStringUntilSeparator ( const char * * StrSrc , char * StrDst , size_t MaxLength )
{
size_t i = 0 ;
int Ch ;
/***** Skip separators *****/
do
{
if ( ( Ch = ( int ) * * StrSrc ) ! = 0 )
( * StrSrc ) + + ;
}
2015-03-20 14:30:28 +01:00
while ( isspace ( Ch ) | |
Ch = = 0xA0 | | // Unicode translation for
Ch = = ( int ) ' , ' | |
Ch = = ( int ) ' ; ' ) ;
2014-12-01 23:55:08 +01:00
/***** Copy string while no separator found *****/
2015-03-20 14:30:28 +01:00
while ( Ch & &
! ( isspace ( Ch ) | |
Ch = = 0xA0 | | // Unicode translation for
Ch = = ( int ) ' , ' | |
Ch = = ( int ) ' ; ' ) )
2014-12-01 23:55:08 +01:00
{
if ( i < MaxLength )
StrDst [ i + + ] = ( char ) Ch ;
if ( ( Ch = ( int ) * * StrSrc ) ! = 0 )
( * StrSrc ) + + ;
}
StrDst [ i ] = ' \0 ' ;
}
/*****************************************************************************/
/********** Get from file FileSrc the next string until separator ************/
/*****************************************************************************/
void Str_GetNextStringFromFileUntilSeparator ( FILE * FileSrc , char * StrDst )
{
int i = 0 ;
int Ch ;
/***** Skip separators *****/
do
Ch = fgetc ( FileSrc ) ;
2015-03-20 14:30:28 +01:00
while ( Ch ! = EOF & &
( isspace ( Ch ) | |
Ch = = 0xA0 | | // Unicode translation for
Ch = = ( int ) ' , ' | |
Ch = = ( int ) ' ; ' ) ) ; // Skip spaces, puntuaci<63> n, etc.
2014-12-01 23:55:08 +01:00
/***** Copy string while no separator found *****/
2015-03-20 14:30:28 +01:00
while ( Ch ! = EOF & &
! ( isspace ( Ch ) | |
Ch = = 0xA0 | | // Unicode translation for
Ch = = ( int ) ' , ' | |
Ch = = ( int ) ' ; ' ) )
2014-12-01 23:55:08 +01:00
{
if ( i < ID_MAX_LENGTH_USR_ID )
StrDst [ i + + ] = ( char ) Ch ;
Ch = fgetc ( FileSrc ) ;
}
StrDst [ i ] = ' \0 ' ;
}
/*****************************************************************************/
/********** Get from StrSrc into StrDst the next string until comma **********/
/*****************************************************************************/
// Modifies *StrSrc
// Leading spaces are not copied
// Trailing spaces are removed at end
void Str_GetNextStringUntilComma ( const char * * StrSrc , char * StrDst , size_t MaxLength )
{
int Ch ;
char * Ptr ;
size_t i = 0 ;
/***** Skip leading spaces and ',' *****/
Ch = ( int ) * * StrSrc ;
2015-03-20 14:30:28 +01:00
while ( isspace ( Ch ) | |
Ch = = 0xA0 | | // Unicode translation for
Ch = = ( int ) ' , ' )
2014-12-01 23:55:08 +01:00
{
( * StrSrc ) + + ;
Ch = ( int ) * * StrSrc ;
}
/***** Copy string until ',' or end *****/
Ptr = StrDst ;
while ( Ch & & Ch ! = ( int ) ' , ' )
{
if ( i < MaxLength )
{
* Ptr + + = ( char ) Ch ;
i + + ;
}
( * StrSrc ) + + ;
Ch = ( int ) * * StrSrc ;
}
/***** Remove trailing spaces *****/
for ( Ptr - - ;
Ptr > = * StrSrc ;
Ptr - - )
2015-03-20 14:30:28 +01:00
if ( ! ( isspace ( ( int ) * Ptr ) | |
* Ptr = = ' \xA0 ' ) ) // Unicode translation for
2014-12-01 23:55:08 +01:00
break ;
* ( Ptr + 1 ) = ' \0 ' ;
}
/*****************************************************************************/
/********** Replace special characters in a string for HTML codes ************/
/*****************************************************************************/
void Str_ReplaceSpecialCharByCodes ( char * Str , unsigned long MaxLengthStr )
{
char * Ptr , * PtrSrc , * PtrDst , * PtrEndStr ;
int LengthSpecStrDst ;
unsigned long LengthStrDst = 0 ;
char StrSpecialChar [ 256 ] ;
/***** Make the conversion *****/
for ( Ptr = Str ;
* Ptr ; )
{
if ( * Ptr > = 32 & & * Ptr < = 126 ) // If character is printable in english ==> is OK; else ==> convert to code
{
LengthStrDst + + ;
Ptr + + ;
}
else
{
sprintf ( StrSpecialChar , " &#%u; " , ( unsigned char ) * Ptr ) ;
PtrEndStr = Str + strlen ( Str ) ;
LengthSpecStrDst = strlen ( StrSpecialChar ) ;
LengthStrDst + = LengthSpecStrDst ;
if ( LengthStrDst > MaxLengthStr )
Lay_ShowErrorAndExit ( " Not enough memory to convert the format of a string. " ) ;
for ( PtrSrc = PtrEndStr ,
PtrDst = PtrSrc + LengthSpecStrDst - 1 ;
PtrSrc > = Ptr + 1 ;
* PtrDst - - = * PtrSrc - - ) ; /* Copy backward from '\0' (included) */
/* Copy to appropiate place the special character string */
strncpy ( Ptr , StrSpecialChar , LengthSpecStrDst ) ;
/* Increment pointer to character after ';' */
Ptr + = LengthSpecStrDst ;
}
}
}
/*****************************************************************************/
/***************** Replace several spaces of a string for one ****************/
/*****************************************************************************/
void Str_ReplaceSeveralSpacesForOne ( char * Str )
{
char * PtrSrc , * PtrDst ;
bool PreviousWasSpace = false ;
/***** Do the replacing *****/
for ( PtrDst = PtrSrc = Str ;
* PtrSrc ; )
2015-03-20 14:30:28 +01:00
if ( isspace ( ( int ) * PtrSrc ) | |
* PtrSrc = = ' \xA0 ' ) // Unicode translation for
2014-12-01 23:55:08 +01:00
{
if ( ! PreviousWasSpace )
* PtrDst + + = ' ' ;
PreviousWasSpace = true ;
PtrSrc + + ;
}
else
{
PreviousWasSpace = false ;
* PtrDst + + = * PtrSrc + + ;
}
* PtrDst = ' \0 ' ;
}
/*****************************************************************************/
/************* Copy a string to another changing ' ' to '%20' ****************/
/*****************************************************************************/
void Str_CopyStrChangingSpaces ( const char * StringWithSpaces , char * StringWithoutSpaces , unsigned MaxLength )
{
const char * PtrSrc ;
char * PtrDst ;
unsigned Length = 0 ;
for ( PtrSrc = StringWithSpaces , PtrDst = StringWithoutSpaces ;
* PtrSrc & & Length < = MaxLength ;
PtrSrc + + )
if ( * PtrSrc = = ' ' )
{
Length + = 3 ;
if ( Length < = MaxLength )
{
* PtrDst + + = ' % ' ;
* PtrDst + + = ' 2 ' ;
* PtrDst + + = ' 0 ' ;
}
}
else
{
Length + + ;
if ( Length < = MaxLength )
* PtrDst + + = * PtrSrc ;
}
* PtrDst = ' \0 ' ;
if ( Length > MaxLength )
Lay_ShowErrorAndExit ( " Path is too long. " ) ;
}
/*****************************************************************************/
/* Convert string with a code (of group type, group, degree, etc.) to long **/
/*****************************************************************************/
// Return -1L if code not found in Str
long Str_ConvertStrCodToLongCod ( const char * Str )
{
long Code ;
if ( Str [ 0 ] = = ' \0 ' )
return - 1L ;
if ( sscanf ( Str , " %ld " , & Code ) ! = 1 )
return - 1L ;
return Code ;
}
/*****************************************************************************/
/**** Compute length of root (all except extension) of the name of a file ****/
/*****************************************************************************/
int Str_GetLengthRootFileName ( const char * FileName )
{
return strlen ( FileName ) - strlen ( strrchr ( FileName , ( int ) ' . ' ) ) ;
}
/*****************************************************************************/
/************** Get the name of a file from a complete path ******************/
/*****************************************************************************/
// Split a full path in path (without ending '/' ) and a file name
// PathWithoutFileName must have space for at least PATH_MAX+1 bytes
// FileName must have space for at least NAME_MAX+1 bytes
void Str_SplitFullPathIntoPathAndFileName ( const char * FullPath ,
char * PathWithoutFileName ,
char * FileName )
{
const char * PtrFileName ;
size_t LengthUntilFileName ;
/***** Find the start of filename *****/
if ( ( PtrFileName = strrchr ( FullPath , ( int ) ' / ' ) ) ! = NULL )
PtrFileName + + ;
else if ( ( PtrFileName = strrchr ( FullPath , ( int ) ' \\ ' ) ) ! = NULL )
PtrFileName + + ;
else
PtrFileName = FullPath ;
/***** Get PathWithoutFileName *****/
LengthUntilFileName = ( size_t ) ( PtrFileName - FullPath ) ; // Last slash included
if ( LengthUntilFileName > 1 )
{
if ( LengthUntilFileName > PATH_MAX )
{
strncpy ( PathWithoutFileName , FullPath , PATH_MAX ) ;
PathWithoutFileName [ PATH_MAX ] = ' \0 ' ;
}
else
{
strncpy ( PathWithoutFileName , FullPath , LengthUntilFileName - 1 ) ; // Do not copy ending slash
PathWithoutFileName [ LengthUntilFileName - 1 ] = ' \0 ' ;
}
}
else
PathWithoutFileName [ 0 ] = ' \0 ' ;
/***** Get FileName *****/
strncpy ( FileName , PtrFileName , NAME_MAX ) ;
FileName [ NAME_MAX ] = ' \0 ' ;
}
/*****************************************************************************/
/************** Check if the extension of a file is .Extension ***************/
/*****************************************************************************/
// Return true if FileName ends by .Extension
// Else return false
bool Str_FileIs ( const char * FileName , const char * Extension )
{
int i , j ;
/***** Only extensiones of 5 or less characters are valid. For example "zip", "html", "mhtml" *****/
if ( strlen ( Extension ) > 5 )
return false ;
/***** Check the extension *****/
for ( i = strlen ( FileName ) - 1 , j = strlen ( Extension ) - 1 ;
i > 0 & & j > = 0 ;
i - - , j - - )
if ( Str_ConvertToLowerLetter ( FileName [ i ] ) ! = Str_ConvertToLowerLetter ( Extension [ j ] ) )
return false ;
if ( j > = 0 ) /* If all the characters of the extension have not been checked
due to the name of the file is too short */
return false ;
/***** Check the dot before the extension *****/
return ( FileName [ i ] = = ' . ' ) ;
}
/*****************************************************************************/
/**************** Check if the extension of a file is .html ******************/
/*****************************************************************************/
// Return true if FileName ends by .htm or .html
// Else return false
bool Str_FileIsHTML ( const char * FileName )
{
if ( Str_FileIs ( FileName , " htm " ) )
return true ;
return Str_FileIs ( FileName , " html " ) ;
}
/*****************************************************************************/
/********************* Check if Path1 starts by Path2 ************************/
/*****************************************************************************/
bool Str_Path1BeginsByPath2 ( const char * Path1 , const char * Path2 )
{
/* The string Path1 must start by the complete string Path2 */
while ( * Path2 )
if ( * Path2 + + ! = * Path1 + + )
return false ;
/* The string Path1 starts by the complete string Path2 */
/* Check that the next character of Path1 is '\0' or '/' */
return ( bool ) ( * Path1 = = ' \0 ' | | * Path1 = = ' / ' ) ;
}
/*****************************************************************************/
/** Skip spaces in a file seeking it before of reading the first non-blank ***/
/*****************************************************************************/
void Str_SkipSpacesInFile ( FILE * FileSrc )
{
int Ch ;
while ( ( Ch = fgetc ( FileSrc ) ) ! = EOF )
2015-03-20 14:30:28 +01:00
if ( ! ( isspace ( Ch ) | |
Ch = = 0xA0 ) ) // Unicode translation for
2014-12-01 23:55:08 +01:00
{
fseek ( FileSrc , - 1L , SEEK_CUR ) ;
break ;
}
}
/*****************************************************************************/
/***************** Write a string to a file changing *************************/
/***************** <br> or <br /> for return *************************/
/***************** and for space *************************/
/*****************************************************************************/
void Str_FilePrintStrChangingBRToRetAndNBSPToSpace ( FILE * FileTgt , const char * Str )
{
while ( * Str )
{
/* Is ? */
if ( * Str = = ' & ' )
{
if ( * ( Str + 1 ) = = ' N ' | | * ( Str + 1 ) = = ' n ' )
if ( * ( Str + 2 ) = = ' B ' | | * ( Str + 2 ) = = ' b ' )
if ( * ( Str + 3 ) = = ' S ' | | * ( Str + 3 ) = = ' s ' )
if ( * ( Str + 4 ) = = ' P ' | | * ( Str + 4 ) = = ' p ' )
if ( * ( Str + 5 ) = = ' ; ' )
{
fputc ( ( int ) ' ' , FileTgt ) ;
Str + = 6 ;
continue ;
}
}
/* Is <br> or <br />? */
else if ( * Str = = ' < ' )
{
if ( * ( Str + 1 ) = = ' B ' | | * ( Str + 1 ) = = ' b ' )
if ( * ( Str + 2 ) = = ' R ' | | * ( Str + 2 ) = = ' r ' )
{
if ( * ( Str + 3 ) = = ' > ' )
{
fputc ( ( int ) ' \n ' , FileTgt ) ;
Str + = 4 ;
continue ;
}
else if ( * ( Str + 3 ) = = ' ' )
{
if ( * ( Str + 4 ) = = ' / ' )
if ( * ( Str + 5 ) = = ' > ' )
{
fputc ( ( int ) ' \n ' , FileTgt ) ;
Str + = 6 ;
continue ;
}
}
}
}
fputc ( ( int ) * Str , FileTgt ) ;
Str + + ;
}
}
/*****************************************************************************/
/*************** Search a string in a file and/or in a string ****************/
/*****************************************************************************/
/*
Search in the file FileSrc the string StrDelimit .
Write in the file FileTgt and / or StrDst the characters read from FileSrc , not including StrDelimit ! .
FileTgt and StrDst can be NULL if you don ' t want to use them .
If StrDelimit is found , return 1.
If what is read exceed MaxLength , abort and return 0.
If StrDelimit is not found , return - 1.
*/
# define MAX_LENGTH_STR_DELIMIT 100
int Str_ReceiveFileUntilDelimitStr ( FILE * FileSrc , FILE * FileTgt , char * StrDst , const char * StrDelimit , unsigned long long MaxLength )
{
int NumBytesIdentical , // Number of characters identical in each iteration of the loop
NumBytesReadButNoWritten = 0 , // Number of characters read from the source file
// and not written in the destination file
LengthStrDelimit = strlen ( StrDelimit ) ;
int Buffer [ MAX_LENGTH_STR_DELIMIT + 1 ] ;
unsigned long long LengthDst = 0 ;
int StartIndex = 0 , i ;
char * Ptr ; // Pointer used to go through StrDst writing characters
if ( ! LengthStrDelimit )
{
if ( StrDst ! = NULL )
* StrDst = ' \0 ' ;
return 1 ;
}
if ( strlen ( StrDelimit ) > MAX_LENGTH_STR_DELIMIT )
Lay_ShowErrorAndExit ( " Delimiter string too large. " ) ;
Ptr = StrDst ;
for ( ; ; )
{
if ( ! NumBytesReadButNoWritten )
{ // Read next character
Buffer [ StartIndex ] = fgetc ( FileSrc ) ;
if ( feof ( FileSrc ) )
{
if ( StrDst ! = NULL )
* Ptr = ' \0 ' ;
return - 1 ;
}
NumBytesReadButNoWritten + + ;
}
if ( Buffer [ StartIndex ] = = ( int ) StrDelimit [ 0 ] ) // First character identical
{
for ( NumBytesIdentical = 1 , i = ( StartIndex + 1 ) % LengthStrDelimit ;
NumBytesIdentical < LengthStrDelimit ;
NumBytesIdentical + + , i = ( i + 1 ) % LengthStrDelimit )
{
if ( NumBytesReadButNoWritten = = NumBytesIdentical ) // Next character identical
{
Buffer [ i ] = fgetc ( FileSrc ) ; // Read next character
if ( feof ( FileSrc ) )
{
if ( StrDst ! = NULL )
* Ptr = ' \0 ' ;
return - 1 ;
}
NumBytesReadButNoWritten + + ;
}
if ( Buffer [ i ] ! = ( int ) StrDelimit [ NumBytesIdentical ] ) // Next different character
break ;
}
if ( NumBytesIdentical = = LengthStrDelimit ) // Str found
{
if ( StrDst ! = NULL )
* Ptr = ' \0 ' ;
return 1 ;
}
}
if ( LengthDst = = MaxLength )
{
if ( StrDst ! = NULL )
* Ptr = ' \0 ' ;
return 0 ;
}
if ( FileTgt ! = NULL )
fputc ( Buffer [ StartIndex ] , FileTgt ) ; // Add the first character to the destination file
if ( StrDst ! = NULL )
* Ptr + + = ( char ) Buffer [ StartIndex ] ;
LengthDst + + ;
NumBytesReadButNoWritten - - ;
StartIndex = ( StartIndex + 1 ) % LengthStrDelimit ;
}
return 0 ; // Not reached
}
/*****************************************************************************/
/****** Convert invalid characters in a file name to valid characters ********/
/*****************************************************************************/
// Return true if the name of the file o folder is valid
// If the name is not valid, Gbl.Message will contain feedback text
// File names with heading and trailing spaces are allowed
bool Str_ConvertFilFolLnkNameToValid ( char * FileName )
{
extern const char * Txt_UPLOAD_FILE_X_invalid_name_NO_HTML ;
extern const char * Txt_UPLOAD_FILE_X_invalid_name ;
extern const char * Txt_UPLOAD_FILE_Invalid_name_NO_HTML ;
extern const char * Txt_UPLOAD_FILE_Invalid_name ;
char * Ptr ;
unsigned NumAlfanum = 0 ;
unsigned NumSpaces = 0 ;
unsigned NumPoints = 0 ;
bool FileNameIsOK = false ;
Ptr = FileName ;
if ( * Ptr ) // FileName is not empty
{
for ( ;
* Ptr ;
Ptr + + )
{
if ( * Ptr = = ' ' )
{
NumPoints = 0 ;
if ( + + NumSpaces > 1 )
{
* Ptr = ' _ ' ;
NumAlfanum + + ;
NumSpaces = NumPoints = 0 ;
}
}
else if ( * Ptr = = ' . ' )
{
if ( + + NumPoints > 1 ) // Don't allow ".."
{
* Ptr = ' _ ' ;
NumAlfanum + + ;
NumSpaces = NumPoints = 0 ;
}
}
else
{
switch ( * Ptr )
{
case ' <EFBFBD> ' : * Ptr = ' a ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' e ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' i ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' o ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' u ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' n ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' a ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' e ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' i ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' o ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' u ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' c ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' A ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' E ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' I ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' O ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' U ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' N ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' A ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' E ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' I ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' O ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' U ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' C ' ; break ;
}
if ( ( * Ptr > = ' a ' & & * Ptr < = ' z ' ) | |
( * Ptr > = ' A ' & & * Ptr < = ' Z ' ) | |
( * Ptr > = ' 0 ' & & * Ptr < = ' 9 ' ) | |
* Ptr = = ' _ ' | |
* Ptr = = ' - ' )
{
NumAlfanum + + ;
NumSpaces = NumPoints = 0 ;
}
else
{
* Ptr = ' _ ' ;
NumAlfanum + + ;
NumSpaces = NumPoints = 0 ;
}
}
}
if ( NumAlfanum )
FileNameIsOK = true ;
else
sprintf ( Gbl . Message ,
Gbl . FileBrowser . UploadingWithDropzone ? Txt_UPLOAD_FILE_X_invalid_name_NO_HTML :
Txt_UPLOAD_FILE_X_invalid_name ,
FileName ) ;
}
else // FileName is empty
strcpy ( Gbl . Message ,
Gbl . FileBrowser . UploadingWithDropzone ? Txt_UPLOAD_FILE_Invalid_name_NO_HTML :
Txt_UPLOAD_FILE_Invalid_name ) ;
return FileNameIsOK ;
}
/*****************************************************************************/
/************ Convert a string to a valid name of file or folder *************/
/*****************************************************************************/
void Str_ConvertToValidFileName ( char * Str )
{
char * Ptr ;
for ( Ptr = Str ;
* Ptr ;
Ptr + + )
{
if ( ( * Ptr > = ' a ' & & * Ptr < = ' z ' ) | |
( * Ptr > = ' A ' & & * Ptr < = ' Z ' ) | |
( * Ptr > = ' 0 ' & & * Ptr < = ' 9 ' ) | |
* Ptr = = ' _ ' | |
* Ptr = = ' - ' )
continue ;
2015-04-14 19:38:00 +02:00
if ( isspace ( ( int ) * Ptr ) | |
* Ptr = = ' \xA0 ' )
* Ptr = ' _ ' ;
else
switch ( * Ptr )
{
case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : * Ptr = ' a ' ; break ;
case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : * Ptr = ' e ' ; break ;
case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : * Ptr = ' i ' ; break ;
case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : * Ptr = ' o ' ; break ;
case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : * Ptr = ' u ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' n ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' c ' ; break ;
case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : * Ptr = ' A ' ; break ;
case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : * Ptr = ' E ' ; break ;
case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : * Ptr = ' I ' ; break ;
case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : * Ptr = ' O ' ; break ;
case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : case ' <EFBFBD> ' : * Ptr = ' U ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' N ' ; break ;
case ' <EFBFBD> ' : * Ptr = ' C ' ; break ;
default : * Ptr = ' - ' ; break ;
}
2014-12-01 23:55:08 +01:00
}
}
/*****************************************************************************/
/********** Write a quantity of bytes as bytes, KiB, MiB, GiB or TiB *********/
/*****************************************************************************/
# define Ki 1024.0
# define Mi 1048576.0
# define Gi 1073741824.0
# define Ti 1099511627776.0
void Str_WriteSizeInBytesBrief ( double SizeInBytes )
{
if ( SizeInBytes < Ki )
fprintf ( Gbl . F . Out , " %.0f B " ,
SizeInBytes ) ;
else if ( SizeInBytes < Mi )
fprintf ( Gbl . F . Out , " %.0f KiB " ,
SizeInBytes / Ki ) ;
else if ( SizeInBytes < Gi )
fprintf ( Gbl . F . Out , " %.0f MiB " ,
SizeInBytes / Mi ) ;
else if ( SizeInBytes < Ti )
fprintf ( Gbl . F . Out , " %.0f GiB " ,
SizeInBytes / Gi ) ;
else
fprintf ( Gbl . F . Out , " %.0f TiB " ,
SizeInBytes / Ti ) ;
}
void Str_WriteSizeInBytesFull ( double SizeInBytes )
{
if ( SizeInBytes < Ki )
fprintf ( Gbl . F . Out , " %.0f B " ,
SizeInBytes ) ;
else if ( SizeInBytes < Mi )
fprintf ( Gbl . F . Out , " %.1f KiB " ,
SizeInBytes / Ki ) ;
else if ( SizeInBytes < Gi )
fprintf ( Gbl . F . Out , " %.1f MiB " ,
SizeInBytes / Mi ) ;
else if ( SizeInBytes < Ti )
fprintf ( Gbl . F . Out , " %.1f GiB " ,
SizeInBytes / Gi ) ;
else
fprintf ( Gbl . F . Out , " %.1f TiB " ,
SizeInBytes / Ti ) ;
}
/*****************************************************************************/
/******************* Create a random alphanumeric string *********************/
/*****************************************************************************/
# define NUM_ALPHANUM_CHARS (10+26+26)
void Str_CreateRandomAlphanumStr ( char * Str , size_t Length )
{
static const char CharTable [ NUM_ALPHANUM_CHARS ] =
{ ' 0 ' , ' 1 ' , ' 2 ' , ' 3 ' , ' 4 ' , ' 5 ' , ' 6 ' , ' 7 ' , ' 8 ' , ' 9 ' ,
' A ' , ' B ' , ' C ' , ' D ' , ' E ' , ' F ' , ' G ' , ' H ' , ' I ' , ' J ' , ' K ' , ' L ' , ' M ' , ' N ' , ' O ' , ' P ' , ' Q ' , ' R ' , ' S ' , ' T ' , ' U ' , ' V ' , ' W ' , ' X ' , ' Y ' , ' Z ' ,
' a ' , ' b ' , ' c ' , ' d ' , ' e ' , ' f ' , ' g ' , ' h ' , ' i ' , ' j ' , ' k ' , ' l ' , ' m ' , ' n ' , ' o ' , ' p ' , ' q ' , ' r ' , ' s ' , ' t ' , ' u ' , ' v ' , ' w ' , ' x ' , ' y ' , ' z '
} ;
size_t i ;
/***** Set random chars in string *****/
for ( i = 0 ;
i < Length ;
i + + )
Str [ i ] = CharTable [ ( unsigned ) ( ( ( float ) rand ( ) * ( float ) ( NUM_ALPHANUM_CHARS - 1 ) ) / ( float ) RAND_MAX + 0.5 ) ] ;
Str [ Length ] = ' \0 ' ;
}
/*****************************************************************************/
/********************** Get mailbox from e-mail address **********************/
/*****************************************************************************/
void Str_GetMailBox ( const char * Email , char * MailBox , size_t MaxLength )
{
const char * Ptr ;
MailBox [ 0 ] = ' \0 ' ; // Return empty mailbox on error
if ( ( Ptr = strchr ( Email , ( int ) ' @ ' ) ) ) // Find first '@' in address
if ( Ptr ! = Email ) // '@' is not the first character in Email
{
Ptr + + ; // Skip '@'
if ( strchr ( Ptr , ( int ) ' @ ' ) = = NULL ) // No more '@' found
{
strncpy ( MailBox , Ptr , MaxLength ) ;
MailBox [ MaxLength ] = ' \0 ' ;
}
}
}