/* * NOTICE and LICENSE for Tecplot Input/Output Library (TecIO) - OpenFOAM * * Copyright (C) 1988-2009 Tecplot, Inc. All rights reserved worldwide. * * Tecplot hereby grants OpenCFD limited authority to distribute without * alteration the source code to the Tecplot Input/Output library, known * as TecIO, as part of its distribution of OpenFOAM and the * OpenFOAM_to_Tecplot converter. Users of this converter are also hereby * granted access to the TecIO source code, and may redistribute it for the * purpose of maintaining the converter. However, no authority is granted * to alter the TecIO source code in any form or manner. * * This limited grant of distribution does not supersede Tecplot, Inc.'s * copyright in TecIO. Contact Tecplot, Inc. for further information. * * Tecplot, Inc. * 3535 Factoria Blvd, Ste. 550 * Bellevue, WA 98006, USA * Phone: +1 425 653 1200 * http://www.tecplot.com/ * */ #include "stdafx.h" #include "MASTER.h" #define TECPLOTENGINEMODULE /* ****************************************************************** ****************************************************************** ******* ******** ****** (C) 1988-2008 Tecplot, Inc. ******* ******* ******** ****************************************************************** ****************************************************************** */ #define STRUTILMODULE #include "GLOBAL.h" #include "TASSERT.h" #include "Q_UNICODE.h" #if defined TECPLOTKERNEL /* CORE SOURCE CODE REMOVED */ #endif #include "ARRLIST.h" #include "STRLIST.h" #include "STRUTIL.h" #include "ALLOC.h" #include "Q_MSG.h" #include #include // ...needed to find std::tolower and std::toupper #include #include "TranslatedString.h" #if defined TECPLOTKERNEL /* CORE SOURCE CODE REMOVED */ #endif using namespace std; using namespace tecplot::strutil; #ifdef MSWIN # pragma warning (disable : 4786) /* STL warning about trucated identifiers */ #endif /* END HEADER */ /** */ #define INITIAL_FORMAT_BUFFER_SIZE 16384*3 #if defined TECPLOTKERNEL /* CORE SOURCE CODE REMOVED */ #endif static char *FormatStringBuffer = NULL; static int FormatStringBufferSize = INITIAL_FORMAT_BUFFER_SIZE; #if defined TECPLOTKERNEL /* CORE SOURCE CODE REMOVED */ #if defined MSWIN #else #endif /* !MSWIN */ #endif #if defined TECPLOTKERNEL /* CORE SOURCE CODE REMOVED */ #endif /** * This should be one of the last functions called by Tecplot while mopping up. */ void FormatStringBufferCleanup(void) { /* * NOTE: We use free instead of FREE_ARRAY for the scratch buffer because in * debug mode FREE_ARRAY uses ErrMsg which uses vFormatString causing * infinite recursion. */ if (FormatStringBuffer != NULL) free(FormatStringBuffer); FormatStringBuffer = NULL; } /** */ char *vFormatString(const char *Format, va_list Arguments) { char *Result = NULL; REQUIRE(VALID_REF(Format)); #if defined TECPLOTKERNEL /* CORE SOURCE CODE REMOVED */ #endif /* * NOTE: We use malloc instead of ALLOC_ARRAY for the scratch buffer because * in debug mode ALLOC_ARRAY uses ErrMsg which uses vFormatString * causing infinite recursion. */ if (FormatStringBuffer == NULL) FormatStringBuffer = (char *)malloc(FormatStringBufferSize); if (FormatStringBuffer != NULL) { Boolean_t TryAgain = FALSE; do { /* * Assign a value other than '\0' to the end of the buffer so that we * can determine if the buffer needs to be expanded. If after we call * vsnprintf the end of the buffer has a '\0' we need to expand it. */ FormatStringBuffer[FormatStringBufferSize - 1] = (char)!'\0'; # if defined MSWIN memset(FormatStringBuffer, 0, FormatStringBufferSize - 1); TryAgain = _vsnprintf(FormatStringBuffer, FormatStringBufferSize, Format, Arguments) == -1; # elif defined IRIX62 vsprintf(FormatStringBuffer, Format, Arguments); CHECK(strlen(FormatStringBuffer) < FormatStringBufferSize); # else vsnprintf(FormatStringBuffer, FormatStringBufferSize, Format, Arguments); # endif #ifndef MSWIN TryAgain = (FormatStringBuffer[FormatStringBufferSize - 1] == '\0'); #endif if (TryAgain) { /* * Reallocate the buffer and try again. * * NOTE: We use malloc/free instead of ALLOC/FREE_ARRAY for the * scratch buffer because in debug mode ALLOC/FREE_ARRAY * uses ErrMsg which uses vFormatString causing infinite * recursion. */ free(FormatStringBuffer); FormatStringBufferSize += MAX(1, FormatStringBufferSize / 2); FormatStringBuffer = (char *)malloc(FormatStringBufferSize); TryAgain = (FormatStringBuffer != NULL); if (!TryAgain) FormatStringBufferSize = INITIAL_FORMAT_BUFFER_SIZE; } } while (TryAgain); if (FormatStringBuffer != NULL) Result = DupString(dontTranslate(FormatStringBuffer)); } #if defined TECPLOTKERNEL /* CORE SOURCE CODE REMOVED */ #endif ENSURE(VALID_REF(Result) || Result == NULL); return Result; } /** */ char *FormatString(TranslatedString Format, ...) /* 0 or more variable arguments */ { REQUIRE(!Format.isNull()); va_list Arguments; va_start(Arguments, Format); char *Result = vFormatString(Format.c_str(), Arguments); va_end(Arguments); ENSURE(VALID_REF(Result) || Result == NULL); return Result; } /** */ int FormatString(string& Buffer, TranslatedString Format ...) /* 0 or more variable arguments */ { REQUIRE(!Format.isNull()); va_list Arguments; va_start(Arguments, Format); char *FormattedString = vFormatString(Format.c_str(), Arguments); va_end(Arguments); int Result; if (FormattedString != NULL) { Buffer.assign(FormattedString); Result = (int)Buffer.size(); FREE_ARRAY(FormattedString, "FormattedString"); } else Result = -1; ENSURE(Result == -1 || Result >= 0); return Result; } /** * Returns a duplicate of the string or NULL if sufficient memory is not * available. * * NOTE: This function was created because ResetString(...) does not * duplicate zero length strings but returns NULL instead. */ char *DupString(TranslatedString String) { REQUIRE(VALID_TRANSLATED_STRING(String)); char *Result = ALLOC_ARRAY(strlen(String.c_str()) + 1, char, "duplicate string"); if (Result != NULL) strcpy(Result, String.c_str()); ENSURE(Result == NULL || (VALID_REF(Result) && strcmp(Result, String.c_str()) == 0)); return Result; } /* * Copy up to 'Count' characters from the 'Source' string beginning at * position 'Index' to the 'Target' string. The actual number of characters * copied may be less than 'Count' if a '\0' was encountered in the * 'Source' string before 'Count' characters were copied. * * NOTE: The 'Target' and 'Source' strings may overlap. */ void CopySubString(char *Target, const char *Source, int Index, int Count) { LgIndex_t Length = 0; REQUIRE(VALID_REF(Target)); REQUIRE("Target string is sized to accommodate a string who's length " "is at least MIN(strlen(&Source[Index]), Count) characters."); REQUIRE(VALID_REF(Source)); REQUIRE(0 <= Index && Index <= (LgIndex_t)strlen(Source)); REQUIRE(Count >= 0); Length = MIN((LgIndex_t)strlen(&Source[Index]), Count); memmove(Target, &Source[Index], Length); Target[Length] = '\0'; ENSURE(VALID_REF(Target) && (LgIndex_t)strlen(Target) == Length); } #if defined TECPLOTKERNEL /* CORE SOURCE CODE REMOVED */ #endif /* TECPLOTKERNEL */ /* * Remove any leading white space from the string and return * a reference to it. NOTE: The input string is modified. */ char *StringFlushLeft(char *String) { char *Result = String; char *Start = String; REQUIRE(VALID_REF(String)); /* move the substring beginning at the first non-whitespace */ /* character to the head of the string */ while (isspace(*Start)) Start++; if (Start != String) memmove(String, Start, strlen(Start) + 1); ENSURE(VALID_REF(Result) && Result == String); return Result; } /* * Remove any trailing white space from the string and return * a reference to it. NOTE: The input string is modified. */ static char *StringFlushRight(char *String) { char *Result = String; char *End = NULL; REQUIRE(VALID_REF(String)); for (End = EndOfString(String); End != String && isspace(End[-1]); End--) End[-1] = '\0'; ENSURE(VALID_REF(Result) && Result == String); return Result; } /* * Remove any leading and trailing white space from the string * and return a reference to it. The return value is not * absolutely necessary since the input string is modified * but it is convenient sometimes. * NOTE: The input string is modified but no memory is * allocated nor deallocated. */ char *TrimLeadAndTrailSpaces(char *String) { REQUIRE((String == NULL) || VALID_REF(String)); if (String) return (StringFlushLeft(StringFlushRight(String))); else return String; } /* * If the specified string is longer than the maximum specified length * truncate it and return a reference to it. * * String * String to truncate if necessary. * MaxLength * Length at which to truncate the specified string if exceeded. * * Return * Reference to the input string. */ // Okay for UTF-8 char *StringTruncate(char *String, LgIndex_t MaxLength) { REQUIRE(VALID_REF(String)); REQUIRE(MaxLength >= 0); if ((LgIndex_t)strlen(String) > MaxLength) String[MaxLength] = '\0';/* UTF8_SetAt(String,'\0',MaxLength); */ ENSURE(VALID_REF(String)); ENSURE((LgIndex_t)strlen(String) <= MaxLength); return String; } /* * Trim and truncate the specified string such that its trimmed length * does not exceed the specified length and return a reference to it. * * String * String to trim and truncate if necessary. * MaxLength * Length at which to truncate the trimmed string if exceeded. * * Return * Reference to the input string. */ char *StringTrimAndTruncate(char *String, LgIndex_t MaxLength) { REQUIRE(VALID_REF(String)); REQUIRE(MaxLength >= 0); TrimLeadAndTrailSpaces(String); StringTruncate(String, MaxLength); ENSURE(VALID_REF(String)); ENSURE((LgIndex_t)strlen(String) <= MaxLength); return String; } /** */ #ifndef MSWIN StringList_pa LineBreakString(const char *String, UInt32_t WrapMargin) { REQUIRE(VALID_REF(String)); StringList_pa Result = StringListAlloc(); if (Result != NULL) { Boolean_t IsOk = TRUE; if (strlen(String) > WrapMargin) { char *StringCopy = DupString(dontTranslate(String)); IsOk = (StringCopy != NULL); if (IsOk) { char *CPtr = StringCopy; char *SubString = StringCopy; UInt32_t SubStringLen = 0; while (*CPtr != '\0' && IsOk) { while (*CPtr != '\0' && SubStringLen < WrapMargin) { /* look for a hard break */ if (*CPtr == '\n') { *CPtr = '\0'; /* replace the newline */ CPtr++; break; } CPtr++; SubStringLen++; } /* * If we didn't find a hard break or the end of the string * then we need to back up and find the closest space. */ if (*CPtr != '\0' && SubStringLen == WrapMargin) { /* find the closes space from the right */ if (*CPtr != ' ') { while (CPtr != SubString && *CPtr != ' ') CPtr--; if (*CPtr != ' ') { /* * Bummer, this line will exceed the wrap margin. * Search forward for the next space or newline. */ while (*CPtr != '\0' && *CPtr != ' ' && *CPtr != '\n') CPtr++; while (*CPtr != '\0' && *CPtr == ' ') CPtr++; /* skip over the white space */ } } if (*CPtr != '\0') { *CPtr = '\0'; CPtr++; } StringFlushRight(SubString); } IsOk = StringListAppendString(Result, SubString); SubString = CPtr; SubStringLen = 0; } FREE_ARRAY(StringCopy, "StringCopy"); } } else IsOk = StringListAppendString(Result, String); if (!IsOk) StringListDealloc(&Result); } ENSURE(Result == NULL || VALID_REF(Result)); return Result; } #endif #if defined TECPLOTKERNEL /* CORE SOURCE CODE REMOVED */ #endif /* TECPLOTKERNEL */ /** * Lexicographically compares, at most, the first 'Len' characters of * s1 and s2. * * param s1 * First string or NULL. * param s2 * Second string or NULL. * param Len * Maximum number of characters to compare. * return * Integer value greater than, equal to, or less than zero according * to whether the first 'Len' characters of 's1' are greater than, * equal to, or less than 's2'. */ // Okay for UTF-8 int ustrncmp(const char *s1, const char *s2, size_t Len) { REQUIRE((s1 == NULL) || VALID_REF(s1)); REQUIRE((s2 == NULL) || VALID_REF(s2)); REQUIRE(Len >= 0); char *t1; char *t2; char ct1; char ct2; size_t I = 0; if ((s1 == NULL) && (s2 == NULL)) return 0; if (s1 == NULL) return -1; else if (s2 == NULL) return 1; t1 = (char*)s1; t2 = (char*)s2; while (*t1 && *t2 && (I < Len)) { ct1 = CAPITAL(*t1); ct2 = CAPITAL(*t2); if (ct1 != ct2) return (ct1 - ct2); t1++; t2++; I++; } if ((I == Len) || ((*t1 == '\0') && (*t2 == '\0'))) return 0; else return CAPITAL(*t1) - CAPITAL(*t2); } /** * Lexicographically compares the characters of s1 and s2. * * param s1 * First string or NULL. * param s2 * Second string or NULL. * return * Integer value greater than, equal to, or less than zero according to * whether the characters of 's1' are greater than, equal to, or less * than 's2'. */ int ustrcmp(const char *s1, const char *s2) { REQUIRE((s1 == NULL) || VALID_REF(s1)); REQUIRE((s2 == NULL) || VALID_REF(s2)); return (ustrncmp(s1, s2, INT_MAX)); } #if defined TECPLOTKERNEL /* CORE SOURCE CODE REMOVED */ #if !defined NO_ASSERTS && defined DEBUG_ALLOC #endif #endif /* TECPLOTKERNEL */ /* * The problem with passing file names for release builds is that * the full path name is used (i.e., c:\user\craig\v7.5\tecplot\alloc.c) */ // Okay for UTF-8 #if !defined NO_ASSERTS Boolean_t InternalResetString(char **SBase, const char *NewString, Boolean_t IssueErrMsg, const char *FileName, int LineNumber) #else Boolean_t InternalResetString(char **SBase, const char *NewString, Boolean_t IssueErrMsg) #endif { REQUIRE(VALID_REF(SBase)); REQUIRE(*SBase == NULL || VALID_REF(*SBase)); REQUIRE(NewString == NULL || VALID_REF(NewString)); REQUIRE(IMPLICATION(VALID_REF(*SBase), *SBase != NewString)); /* Prevent calling with same string. */ REQUIRE(VALID_BOOLEAN(IssueErrMsg)); REQUIRE(VALID_NON_ZERO_LEN_STR(FileName)); REQUIRE(LineNumber >= 1); if (*SBase) { #if !defined NO_ASSERTS && defined DEBUG_ALLOC char S[80+1]; MakeDebugRecord(FileName, LineNumber, "releasing", *SBase, S, 80); FREE_ARRAY(*SBase, S); #else FREE_ARRAY(*SBase, ""); #endif } if (NewString == NULL) { *SBase = NULL; return (TRUE); } else { #if !defined NO_ASSERTS && defined DEBUG_ALLOC char S[80+1]; MakeDebugRecord(FileName, LineNumber, "duplicating", NewString, S, 80); *SBase = ALLOC_ARRAY(strlen(NewString) + 1, char, S); #else # if defined MSWIN && defined _DEBUG && !defined(MAKEARCHIVE) && !defined(NO_ASSERTS) /* Allow the MFC memory leak detection to report the leak at the * calling programs location, and not here (which is fairly useless). * But first, we have to turn off the preprocessor definition of new * and get to the original. */ # undef new *SBase = new(FileName, LineNumber) char[strlen(NewString)+1]; # define new DEBUG_NEW # else *SBase = ALLOC_ARRAY(strlen(NewString) + 1, char, ""); # endif #endif if (*SBase) { strcpy(*SBase, NewString); return (TRUE); } else { if (IssueErrMsg) ErrMsg(translate("Out of memory")); return (FALSE); } } } #if defined TECPLOTKERNEL /* CORE SOURCE CODE REMOVED */ #endif /* * Unfortunately, this routine uses the interface of DeleteStringToAdd * forcing StringToAdd to be non-const. Another copy of this routine * for const char *'s is below. Eventually we should get rid of * the two routines and DeleteStringToAdd, always using the const version * and deleting the string if necessary in the code that calls TackOnString. */ Boolean_t TackOnString(char **SBase, const char *StringToAdd, Boolean_t DeleteStringToAdd, Boolean_t ConvertNewlinesToAscii) { size_t CurLen; size_t NewLen; int NumNewlines = 0; char *NewString; const char *CPtr = StringToAdd; Boolean_t IsOk = TRUE; REQUIRE(VALID_REF(SBase)); REQUIRE((StringToAdd == NULL) || VALID_REF(StringToAdd)); REQUIRE(VALID_BOOLEAN(DeleteStringToAdd)); REQUIRE(VALID_BOOLEAN(ConvertNewlinesToAscii)); if ((StringToAdd == NULL) || (*StringToAdd == '\0')) { if (StringToAdd && (*StringToAdd == '\0') && DeleteStringToAdd) { char *TMP = (char *)StringToAdd; FREE_ARRAY(TMP, "empty string to add"); } } else { if (*SBase == NULL) CurLen = 0; else CurLen = strlen(*SBase); while (*CPtr) if (*CPtr++ == '\n') NumNewlines++; NewLen = CurLen + strlen(StringToAdd) + 1 + NumNewlines; NewString = ALLOC_ARRAY(NewLen, char, StringToAdd); if (NewString == NULL) { if (DeleteStringToAdd) { char *TMP = (char *)StringToAdd; FREE_ARRAY(TMP, StringToAdd); } IsOk = FALSE; } else { if (*SBase) { strcpy(NewString, *SBase); FREE_ARRAY(*SBase, (CurLen > 0 ? *SBase : "previous text")); } else *NewString = '\0'; { char *NPtr = EndOfString(NewString); const char *APtr = StringToAdd; while (*APtr) { if ((*APtr == '\n') && ConvertNewlinesToAscii) { *NPtr++ = '\\'; *NPtr++ = 'n'; } else *NPtr++ = *APtr; //UTF8_AssignAndIncrement(&NPtr,(char**)&APtr,TRUE,FALSE); //*NPtr++ = *APtr; APtr++; } *NPtr = '\0'; } if (DeleteStringToAdd) { char *TMP = (char *)StringToAdd; FREE_ARRAY(TMP, StringToAdd); } *SBase = NewString; } } ENSURE(VALID_BOOLEAN(IsOk)); return (IsOk); } /* * See TackOnString for discussion. */ // Okay for UTF-8 Boolean_t TackOnConstString(char **SBase, const char *StringToAdd, Boolean_t ConvertNewlinesToAscii) { size_t CurLen; size_t NewLen; int NumNewlines = 0; char *NewString; const char *CPtr = StringToAdd; Boolean_t IsOk = TRUE; REQUIRE(VALID_REF(SBase)); REQUIRE((StringToAdd == NULL) || VALID_REF(StringToAdd)); REQUIRE(VALID_BOOLEAN(ConvertNewlinesToAscii)); if ((StringToAdd != NULL) && (*StringToAdd != '\0')) { if (*SBase == NULL) CurLen = 0; else CurLen = strlen(*SBase); while (*CPtr) if (*CPtr++ == '\n') NumNewlines++; NewLen = CurLen + strlen(StringToAdd) + 1 + NumNewlines; NewString = ALLOC_ARRAY(NewLen, char, StringToAdd); if (NewString == NULL) { IsOk = FALSE; } else { if (*SBase) { strcpy(NewString, *SBase); FREE_ARRAY(*SBase, (CurLen > 0 ? *SBase : "previous text")); } else *NewString = '\0'; { char *NPtr = EndOfString(NewString); const char *APtr = StringToAdd; while (*APtr) { if ((*APtr == '\n') && ConvertNewlinesToAscii) { *NPtr++ = '\\'; *NPtr++ = 'n'; } else *NPtr++ = *APtr; // UTF8_AssignAndIncrement(&NPtr,(char**)&APtr,TRUE,FALSE); APtr++; } *NPtr = '\0'; } *SBase = NewString; } } ENSURE(VALID_BOOLEAN(IsOk)); return (IsOk); } // Okay for UTF-8 Boolean_t TackOnChar(char **SBase, char CharToAdd) { REQUIRE(VALID_REF(SBase)); char S[2]; S[0] = CharToAdd; S[1] = '\0'; return (TackOnString(SBase, S, FALSE, FALSE)); } /** * Converts all one character new line characters in the allocated string * to a two character "\n" sequence. * * param String * String to scan and convert if necessary. Note that the string will * be reallocated if any new line characters are discovered. * * return * TRUE if the request was successfull, FALSE otherwise. */ // Okay for UTF-8 Boolean_t ReplaceNewlineWithBackslashN(char **String) { size_t I; LgIndex_t NewlineCount; size_t Length; char *Replacement; REQUIRE(VALID_REF(String)); REQUIRE(VALID_REF(*String)); /* count how many new line character are present */ NewlineCount = 0; Length = strlen(*String); for (I = 0; I < Length; I++) if ((*String)[I] == '\n') NewlineCount++; if (NewlineCount != 0) { /* allocate a new string and convert */ Replacement = ALLOC_ARRAY(Length + NewlineCount + 1, char, "replacement string"); if (Replacement != NULL) { size_t J; for (I = J = 0; I < Length + 1; I++, J++) { if ((*String)[I] == '\n') { Replacement[J] = '\\'; J++; Replacement[J] = 'n'; } else { Replacement[J] = (*String)[I]; } } /* sanity check */ CHECK(I == Length + 1); CHECK(J == Length + NewlineCount + 1); } /* release the old string and record the new one */ FREE_ARRAY(*String, "original string"); *String = Replacement; } ENSURE(*String == NULL || VALID_REF(*String)); return (*String != NULL); } #if defined TECPLOTKERNEL /* CORE SOURCE CODE REMOVED */ #if defined TECPLOTKERNEL #if !defined NO_ASSERTS #endif /* !NO_ASSERTS */ #endif /*TECPLOTKERNEL*/ #endif