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); }
UCS2 *Parser::Parse_Str(bool pathname) { char *p; char temp3[128]; char temp4[256]; DBL val; int l, d; Parse_Paren_Begin(); val = Parse_Float(); Parse_Comma(); l = (int)Parse_Float(); Parse_Comma(); d = (int)Parse_Float(); Parse_Paren_End(); 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 `snprintf` may report errors via a negative return value. if (((l = std::snprintf(temp4, sizeof(temp4), temp3, val)) >= sizeof(temp4)) || (l < 0)) { *p = 'g'; // it should not be possible to overflow with %g. but just in case ... if (((l = std::snprintf(temp4, sizeof(temp4), temp3, val)) >= sizeof(temp4)) || (l < 0)) strcpy(temp4, "<invalid>"); } return String_To_UCS2(temp4); }
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 = (char *)"%Y-%m-%d %H:%M:%SZ"; EXIT END_CASE OTHERWISE UNGET CallFree = true; FormatStr = Parse_C_String(pathname); if (FormatStr[0] == '\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); }
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; }
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; }