povray/source/backend/parser/parsestr.cpp
2013-11-06 13:07:19 -05:00

1216 lines
23 KiB
C++

/*******************************************************************************
* parsestr.cpp
*
* This module implements parsing and conversion of string expressions.
*
* ---------------------------------------------------------------------------
* Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
* Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
*
* POV-Ray 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.
*
* POV-Ray 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/>.
* ---------------------------------------------------------------------------
* POV-Ray is based on the popular DKB raytracer version 2.12.
* DKBTrace was originally written by David K. Buck.
* DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
* ---------------------------------------------------------------------------
* $File: //depot/public/povray/3.x/source/backend/parser/parsestr.cpp $
* $Revision: #1 $
* $Change: 6069 $
* $DateTime: 2013/11/06 11:59:40 $
* $Author: chrisc $
*******************************************************************************/
#include <stdlib.h>
#include <ctype.h>
#include <boost/date_time/posix_time/posix_time.hpp>
// frame.h must always be the first POV file included (pulls in platform config)
#include "backend/frame.h"
#include "backend/parser/parse.h"
#include "pov_mem.h" // TODO
// this must be the last file included
#include "base/povdebug.h"
namespace pov
{
/*****************************************************************************
* Local variables
******************************************************************************/
const unsigned char gUTF8SequenceArray[256] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
};
const unsigned int gUTF8Offsets[6] =
{
0x00000000UL,
0x00003080UL,
0x000E2080UL,
0x03C82080UL,
0xFA082080UL,
0x82082080UL
};
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
char *Parser::Parse_C_String(bool pathname)
{
UCS2 *str = Parse_String(pathname);
char *New = UCS2_To_String(str, pathname);
POV_FREE(str);
return New;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
UCS2 *Parser::Parse_String(bool pathname, bool require)
{
UCS2 *New = NULL;
int len = 0;
EXPECT
CASE(STRING_LITERAL_TOKEN)
New = String_To_UCS2(Token.Token_String, pathname);
EXIT
END_CASE
CASE(STR_TOKEN)
New = Parse_Str(pathname);
EXIT
END_CASE
CASE(VSTR_TOKEN)
New = Parse_VStr(pathname);
EXIT
END_CASE
CASE(CONCAT_TOKEN)
New = Parse_Concat(pathname);
EXIT
END_CASE
CASE(CHR_TOKEN)
New = Parse_Chr(pathname);
EXIT
END_CASE
CASE(DATETIME_TOKEN)
New = Parse_Datetime(pathname);
EXIT
END_CASE
CASE(SUBSTR_TOKEN)
New = Parse_Substr(pathname);
EXIT
END_CASE
CASE(STRUPR_TOKEN)
New = Parse_Strupr(pathname);
EXIT
END_CASE
CASE(STRLWR_TOKEN)
New = Parse_Strlwr(pathname);
EXIT
END_CASE
CASE(STRING_ID_TOKEN)
len = UCS2_strlen(reinterpret_cast<UCS2 *>(Token.Data)) + 1;
New = reinterpret_cast<UCS2 *>(POV_MALLOC(len * sizeof(UCS2), "UCS2 String"));
POV_MEMMOVE(reinterpret_cast<void *>(New), reinterpret_cast<void *>(Token.Data), len * sizeof(UCS2));
EXIT
END_CASE
OTHERWISE
if(require)
Expectation_Error("string expression");
else
{
UNGET
EXIT
}
END_CASE
END_EXPECT
return New;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
UCS2 *Parser::Parse_Str(bool pathname)
{
char *p;
char temp3[128];
char temp4[256];
DBL val;
int l, d;
GET(LEFT_PAREN_TOKEN);
val = Parse_Float();
Parse_Comma();
l = (int)Parse_Float();
Parse_Comma();
d = (int)Parse_Float();
GET(RIGHT_PAREN_TOKEN);
p = temp3;
*p++ = '%';
if (l > 0)
{
p += sprintf(p, "%d", l);
}
else
{
if (l)
p += sprintf(p, "0%d", abs(l));
}
if (d >= 0)
p += sprintf(p, ".%d", d);
strcpy(p, "f");
// a very large floating point value (e.g. 1e251) will overflow the buffer.
// TODO: consider changing to %g rather than %f for large numbers (e.g.
// anything over 1e+64 for example). for now, we will only use %g if the
// snprintf filled the buffer.
// NB test for < 0 is because stupid windows _snprintf can return negative values.
if (((l = snprintf(temp4, sizeof(temp4) - 1, temp3, val)) >= sizeof(temp4) - 1) || (l < 0))
{
*p = 'g';
// it should not be possible to overflow with %g. but just in case ...
if (((l = snprintf(temp4, sizeof(temp4) - 1, temp3, val)) >= sizeof(temp4) - 1) || (l < 0))
strcpy(temp4, "<invalid>");
}
return String_To_UCS2(temp4, pathname);
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
UCS2 *Parser::Parse_VStr(bool pathname)
{
char *p;
char temp3[128];
char temp4[768];
int l, d, vl;
EXPRESS Express;
int Terms;
int Dim = 5;
UCS2 *str;
UCS2 *str2;
UCS2 *New;
GET(LEFT_PAREN_TOKEN);
vl = (int)Parse_Float();
Parse_Comma();
if(vl < 2)
vl = 2;
else if(vl > 5)
vl = 5;
Dim = vl;
Terms = Parse_Unknown_Vector(Express);
Parse_Comma();
str = Parse_String(pathname);
Parse_Comma();
l = (int)Parse_Float();
Parse_Comma();
d = (int)Parse_Float();
GET(RIGHT_PAREN_TOKEN);
p = temp3;
*(p++) = '%';
if (l > 0)
{
sprintf(p, "%d", l);
while (*p != '\0')
p++;
}
else
{
if (l)
{
sprintf(p, "0%d", abs(l));
while (*p != '\0')
p++;
}
}
if (d >= 0)
{
*(p++) = '.';
sprintf(p, "%d", d);
while (*(++p))
;
}
*(p++) = 'f';
*p = '\0';
sprintf(temp4, temp3, Express[X]);
New = String_To_UCS2(temp4, pathname); // add first component
for(Terms = 1; Terms < Dim; Terms++)
{
New = UCS2_strcat(New, str); // add separator
sprintf(temp4, temp3, Express[Terms]);
str2 = String_To_UCS2(temp4, pathname);
New = UCS2_strcat(New, str2); // add component
POV_FREE(str2);
}
POV_FREE(str);
return New;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
UCS2 *Parser::Parse_Concat(bool pathname)
{
UCS2 *str;
UCS2 *New;
GET(LEFT_PAREN_TOKEN);
New = Parse_String();
EXPECT
CASE(RIGHT_PAREN_TOKEN)
EXIT
END_CASE
OTHERWISE
UNGET
Parse_Comma();
str = Parse_String(pathname);
New = UCS2_strcat(New, str);
POV_FREE(str);
END_CASE
END_EXPECT
return New;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
UCS2 *Parser::Parse_Chr(bool /*pathname*/)
{
UCS2 *New;
int d;
New = reinterpret_cast<UCS2 *>(POV_MALLOC(sizeof(UCS2) * 2, "temporary string"));
d = (int)Parse_Float_Param();
if((d < 0) || (d > 65535))
Error("Value %d cannot be used in chr(...).", d);
New[0] = d;
New[1] = 0;
return New;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
#define PARSE_NOW_VAL_LENGTH 200
UCS2 *Parser::Parse_Datetime(bool pathname)
{
char *FormatStr = NULL;
bool CallFree;
int vlen = 0;
char val[PARSE_NOW_VAL_LENGTH + 1]; // Arbitrary size, usually a date format string is far less
GET(LEFT_PAREN_TOKEN);
std::time_t timestamp = floor((Parse_Float() + (365*30+7)) * 24*60*60 + 0.5);
Parse_Comma();
EXPECT
CASE(RIGHT_PAREN_TOKEN)
CallFree = false;
// we use GMT as some platforms (e.g. windows) have different ideas of what to print when handling '%z'.
FormatStr = "%Y-%m-%d %H:%M:%SZ";
EXIT
END_CASE
OTHERWISE
UNGET
CallFree = true;
FormatStr = Parse_C_String(pathname);
if (strlen(FormatStr) == 0)
{
POV_FREE(FormatStr);
Error("Empty format string.");
}
if (strlen(FormatStr) > PARSE_NOW_VAL_LENGTH)
{
POV_FREE(FormatStr);
Error("Format string too long.");
}
GET(RIGHT_PAREN_TOKEN);
EXIT
END_CASE
END_EXPECT
// NB don't wrap only the call to strftime() in the try, because visual C++ will, in release mode,
// optimize the try/catch away since it doesn't believe that the RTL can throw exceptions. since
// the windows version of POV hooks the invalid parameter handler RTL callback and throws an exception
// if it's called, they can.
try
{
std::tm t = boost::posix_time::to_tm(boost::posix_time::from_time_t(timestamp));
// TODO FIXME - we should either have this locale setting globally, or avoid it completely; in either case it shouldn't be *here*.
setlocale(LC_TIME,""); // Get the local prefered format
vlen = strftime(val, PARSE_NOW_VAL_LENGTH, FormatStr, &t);
}
catch (pov_base::Exception& e)
{
// the windows version of strftime calls the invalid parameter handler if
// it gets a bad format string. this will in turn raise an exception of type
// kParamErr. if the exception isn't that, allow normal exception processing
// to continue, otherwise we issue a more useful error message.
if ((e.codevalid() == false) || (e.code() != kParamErr))
throw;
vlen = 0;
}
if ((vlen == PARSE_NOW_VAL_LENGTH)) // on error: max for libc 4.4.1 & before
vlen = 0; // return an empty string on error (content of val[] is undefined)
val[vlen]='\0'; // whatever, that operation is now safe (and superflous except for error)
if (CallFree)
{
POV_FREE(FormatStr);
}
if (vlen == 0)
Error("Invalid formatting code in format string, or resulting string too long.");
return String_To_UCS2(val, pathname);
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
UCS2 *Parser::Parse_Substr(bool pathname)
{
UCS2 *str;
UCS2 *New;
int l, d;
GET(LEFT_PAREN_TOKEN);
str = Parse_String(pathname);
Parse_Comma();
l = (int)Parse_Float();
Parse_Comma();
d = (int)Parse_Float();
GET(RIGHT_PAREN_TOKEN);
if(((l + d - 1) > UCS2_strlen(str)) || (l < 0) || (d < 0))
Error("Illegal parameters in substr.");
New = reinterpret_cast<UCS2 *>(POV_MALLOC(sizeof(UCS2) * (d + 1), "temporary string"));
UCS2_strncpy(New, &(str[l - 1]), d);
New[d] = 0;
POV_FREE(str);
return New;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
UCS2 *Parser::Parse_Strupr(bool pathname)
{
UCS2 *New;
GET(LEFT_PAREN_TOKEN);
New = Parse_String(pathname);
UCS2_strupr(New);
GET(RIGHT_PAREN_TOKEN);
return New;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
UCS2 *Parser::Parse_Strlwr(bool pathname)
{
UCS2 *New;
GET(LEFT_PAREN_TOKEN);
New = Parse_String(pathname);
UCS2_strlwr(New);
GET(RIGHT_PAREN_TOKEN);
return New;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
UCS2 *Parser::String_To_UCS2(const char *str, bool pathname)
{
UCS2 *char_string = NULL;
UCS2 *char_array = NULL;
int char_array_size = 0;
int utf8arraysize = 0;
unsigned char *utf8array = NULL;
int index_in = 0;
int index_out = 0;
char buffer[8];
char *dummy_ptr = NULL;
int i = 0;
if(strlen(str) == 0)
{
char_string = reinterpret_cast<UCS2 *>(POV_MALLOC(sizeof(UCS2), "UCS2 String"));
char_string[0] = 0;
return char_string;
}
switch(sceneData->stringEncoding)
{
case 0: // ASCII
char_array_size = (int)strlen(str);
char_array = reinterpret_cast<UCS2 *>(POV_MALLOC(char_array_size * sizeof(UCS2), "Character Array"));
for(i = 0; i < char_array_size; i++)
{
if(sceneData->languageVersion < 350)
char_array[i] = (unsigned char)(str[i]);
else
{
char_array[i] = str[i] & 0x007F;
if(char_array[i] != str[i])
{
char_array[i] = ' ';
PossibleError("Non-ASCII character has been replaced by space character.");
}
}
}
break;
case 1: // UTF8
char_array = Convert_UTF8_To_UCS2(reinterpret_cast<const unsigned char *>(str), (int)strlen(str), &char_array_size);
break;
case 2: // System Specific
char_array = POV_CONVERT_TEXT_TO_UCS2(reinterpret_cast<const unsigned char *>(str), strlen(str), &char_array_size);
if(char_array == NULL)
Error("Cannot convert system specific text format to Unicode.");
break;
default:
Error("Unsupported text encoding format.");
break;
}
if(char_array == NULL)
Error("Cannot convert text to UCS2 format.");
char_string = reinterpret_cast<UCS2 *>(POV_MALLOC((char_array_size + 1) * sizeof(UCS2), "UCS2 String"));
for(index_in = 0, index_out = 0; index_in < char_array_size; index_in++, index_out++)
{
if((char_array[index_in] == '\\') && (pathname == false))
{
index_in++;
switch(char_array[index_in])
{
case 'a':
char_string[index_out] = 0x07;
break;
case 'b':
char_string[index_out] = 0x08;
break;
case 'f':
char_string[index_out] = 0x0c;
break;
case 'n':
char_string[index_out] = 0x0a;
break;
case 'r':
char_string[index_out] = 0x0d;
break;
case 't':
char_string[index_out] = 0x09;
break;
case 'v':
char_string[index_out] = 0x0b;
break;
case '\0':
char_string[index_out] = 0x5c;
break;
case '\'':
char_string[index_out] = 0x27;
break;
case '\\':
char_string[index_out] = '\\';
break;
case 'u':
if(index_in + 4 >= char_array_size)
Error("Unexpected end of escape sequence in text string.");
buffer[0] = char_array[++index_in];
buffer[1] = char_array[++index_in];
buffer[2] = char_array[++index_in];
buffer[3] = char_array[++index_in];
buffer[4] = 0;
char_string[index_out] = (UCS2)strtoul(buffer, &dummy_ptr, 16);
break;
default:
char_string[index_out] = char_array[index_in];
if ( char_array )
POV_FREE(char_array);
char_array = NULL;
Error( "Illegal escape sequence in string." );
break;
}
}
else
char_string[index_out] = char_array[index_in];
}
char_string[index_out] = 0;
index_out++;
char_string = reinterpret_cast<UCS2 *>(POV_REALLOC(char_string, index_out * sizeof(UCS2), "UCS2 String"));
if(char_array != NULL)
POV_FREE(char_array);
return char_string;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
char *Parser::UCS2_To_String(const UCS2 *str, bool)
{
char *str_out;
char *strp;
str_out = reinterpret_cast<char *>(POV_MALLOC(UCS2_strlen(str)+1, "C String"));
for(strp = str_out; *str != 0; str++, strp++)
{
if((*str > 127) && (sceneData->languageVersion >= 350))
*strp = ' ';
else
*strp = (char)(*str);
}
*strp = 0;
return str_out;
}
/*****************************************************************************
*
* FUNCTION
*
* Convert_UTF8_To_UCS4
*
* INPUT
*
* Array of bytes, length of this sequence
*
* OUTPUT
*
* Size of the array of UCS4s returned
*
* RETURNS
*
* Array of UCS4s (allocated with POV_MALLOC)
*
* AUTHOR
*
* DESCRIPTION
*
* Converts UTF8 to UCS4 characters.
*
* CHANGES
*
* -
*
******************************************************************************/
UCS4 *Parser::Convert_UTF8_To_UCS4(const unsigned char *text_array, int text_array_size, int *char_array_size)
{
UCS4 *char_array = NULL;
UCS4 chr;
int i, j, k, seqlen;
if((text_array == NULL) || (text_array_size == 0) || (char_array_size == NULL))
return NULL;
char_array = reinterpret_cast<UCS4 *>(POV_MALLOC(text_array_size * sizeof(UCS4), "Character Array"));
if(char_array == NULL)
throw POV_EXCEPTION_CODE(kOutOfMemoryErr);
for(i = 0, k = 0; i < text_array_size; k++, i++)
{
seqlen = gUTF8SequenceArray[text_array[i]];
chr = 0;
for(j = seqlen; j > 0; j--)
{
chr += text_array[i];
chr <<= 6;
i++;
}
chr += text_array[i];
char_array[k] = chr - gUTF8Offsets[seqlen];
}
char_array = reinterpret_cast<UCS4 *>(POV_REALLOC(char_array, k * sizeof(UCS4), "Character Array"));
*char_array_size = k;
return char_array;
}
/*****************************************************************************
*
* FUNCTION
*
* Convert_UTF8_To_UCS2
*
* INPUT
*
* Array of bytes, length of this sequence
*
* OUTPUT
*
* Size of the array of UCS2s returned
*
* RETURNS
*
* Array of UCS2s (allocated with POV_MALLOC)
*
* AUTHOR
*
* DESCRIPTION
*
* Converts UTF8 to UCS2 characters, however all surrogates are dropped.
*
* CHANGES
*
* -
*
******************************************************************************/
UCS2 *Parser::Convert_UTF8_To_UCS2(const unsigned char *text_array, int text_array_size, int *char_array_size)
{
UCS2 *char_array = NULL;
UCS4 chr;
int i, j, k, seqlen;
if((text_array == NULL) || (text_array_size == 0) || (char_array_size == NULL))
return NULL;
char_array = reinterpret_cast<UCS2 *>(POV_MALLOC(text_array_size * sizeof(UCS2), "Character Array"));
if(char_array == NULL)
throw POV_EXCEPTION_CODE(kOutOfMemoryErr);
for(i = 0, k = 0; i < text_array_size; k++, i++)
{
seqlen = gUTF8SequenceArray[text_array[i]];
chr = 0;
for(j = seqlen; j > 0; j--)
{
chr += text_array[i];
chr <<= 6;
i++;
}
chr += text_array[i];
chr -= gUTF8Offsets[seqlen];
if(chr <= 0x0000FFFFUL)
char_array[k] = chr;
else
char_array[k] = 0x0000FFFDUL;
}
char_array = reinterpret_cast<UCS2 *>(POV_REALLOC(char_array, k * sizeof(UCS2), "Character Array"));
*char_array_size = k;
return char_array;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
UCS2 *Parser::UCS2_strcat(UCS2 *s1, const UCS2 *s2)
{
int l1, l2;
l1 = UCS2_strlen(s1);
l2 = UCS2_strlen(s2);
s1 = reinterpret_cast<UCS2 *>(POV_REALLOC(s1, sizeof(UCS2) * (l1 + l2 + 1), "UCS2 String"));
UCS2_strcpy(&s1[l1], s2);
return s1;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
int Parser::UCS2_strlen(const UCS2 *str)
{
register int i;
for(i = 0; *str != 0; str++, i++) { }
return i;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
int Parser::UCS2_strcmp(const UCS2 *s1, const UCS2 *s2)
{
UCS2 t1, t2;
while((t1 = *s1++) == (t2 = *s2++))
{
if(t1 == 0)
return 0;
}
return (t1 - t2);
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Parser::UCS2_strcpy(UCS2 *s1, const UCS2 *s2)
{
for(; *s2 != 0; s1++, s2++)
*s1 = *s2;
*s1 = 0;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Parser::UCS2_strncpy(UCS2 *s1, const UCS2 *s2, int n)
{
for(; (*s2 != 0) && (n > 0); s1++, s2++, n--)
*s1 = *s2;
*s1 = 0;
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Parser::UCS2_strupr(UCS2 *str)
{
bool err = false;
while(true)
{
if (((int) *str < 0) || (*str > 127))
err = true;
else if(*str == 0)
break;
*str = toupper(*str);
str++;
}
if(err == true)
Warning(0, "Non-ASCII charcater in string, strupr may not work as expected.");
}
/*****************************************************************************
*
* FUNCTION
*
* INPUT
*
* OUTPUT
*
* RETURNS
*
* AUTHOR
*
* DESCRIPTION
*
* CHANGES
*
******************************************************************************/
void Parser::UCS2_strlwr(UCS2 *str)
{
bool err = false;
while(true)
{
if (((int) *str < 0) || (*str > 127))
err = true;
else if(*str == 0)
break;
*str = tolower(*str);
str++;
}
if(err == true)
Warning(0, "Non-ASCII charcater in string, strlwr may not work as expected.");
}
UCS2 *Parser::UCS2_strdup(const UCS2 *s)
{
UCS2 *New;
New=reinterpret_cast<UCS2 *>(POV_MALLOC((UCS2_strlen(s)+1) * sizeof(UCS2), UCS2toASCIIString(s).c_str()));
UCS2_strcpy(New,s);
return (New);
}
}