1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-21 10:13:43 +03:00
occt/src/Message/Message_MsgFile.cxx
dpasukhi a5a7b3185b Coding - Apply .clang-format formatting #286
Update empty method guards to new style with regex (see PR).
Used clang-format 18.1.8.
New actions to validate code formatting is added.
Update .clang-format with disabling of include sorting.
  It is temporary changes, then include will be sorted.
Apply formatting for /src and /tools folder.
The files with .hxx,.cxx,.lxx,.h,.pxx,.hpp,*.cpp extensions.
2025-01-26 00:43:57 +00:00

424 lines
14 KiB
C++

// Created on: 2001-04-26
// Created by: OCC Team
// Copyright (c) 2001-2014 OPEN CASCADE SAS
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#include <Message_MsgFile.hxx>
#include <NCollection_Buffer.hxx>
#include <NCollection_DataMap.hxx>
#include <OSD_Environment.hxx>
#include <TCollection_AsciiString.hxx>
#include <Standard_Mutex.hxx>
#include <OSD_OpenFile.hxx>
#include <stdlib.h>
#include <stdio.h>
typedef NCollection_DataMap<TCollection_AsciiString, TCollection_ExtendedString>
Message_DataMapOfExtendedString;
static Message_DataMapOfExtendedString& msgsDataMap()
{
static Message_DataMapOfExtendedString aDataMap;
return aDataMap;
}
// mutex used to prevent concurrent access to message registry
static Standard_Mutex& Message_MsgFile_Mutex()
{
static Standard_Mutex theMutex;
return theMutex;
}
typedef enum
{
MsgFile_WaitingKeyword,
MsgFile_WaitingMessage,
MsgFile_WaitingMoreMessage,
MsgFile_Indefinite
} LoadingState;
//=======================================================================
// function : Message_MsgFile
// purpose : Load file from given directories
// theDirName may be represented as list: "/dirA/dirB /dirA/dirC"
//=======================================================================
Standard_Boolean Message_MsgFile::Load(const Standard_CString theDirName,
const Standard_CString theFileName)
{
if (!theDirName || !theFileName)
return Standard_False;
Standard_Boolean ret = Standard_True;
TCollection_AsciiString aDirList(theDirName);
// Try to load from all consecutive directories in list
for (int i = 1;; i++)
{
TCollection_AsciiString aFileName = aDirList.Token(" \t\n", i);
if (aFileName.IsEmpty())
break;
#ifdef _WIN32
aFileName += '\\';
#else
aFileName += '/';
#endif
aFileName += theFileName;
if (!LoadFile(aFileName.ToCString()))
ret = Standard_False;
}
return ret;
}
//=======================================================================
// function : getString
// purpose : Takes a TCollection_ExtendedString from Ascii or Unicode
// Strings are left-trimmed; those beginning with '!' are omitted
// Called : from loadFile()
//=======================================================================
template <typename CharType>
struct TCollection_String;
template <>
struct TCollection_String<Standard_Character>
{
typedef TCollection_AsciiString type;
};
template <>
struct TCollection_String<Standard_ExtCharacter>
{
typedef TCollection_ExtendedString type;
};
template <class CharType>
static inline Standard_Boolean getString(CharType*& thePtr,
TCollection_ExtendedString& theString,
Standard_Integer& theLeftSpaces)
{
CharType* anEndPtr = thePtr;
CharType* aPtr;
Standard_Integer aLeftSpaces;
do
{
// Skip whitespaces in the beginning of the string
aPtr = anEndPtr;
aLeftSpaces = 0;
for (;;)
{
CharType aChar = *aPtr;
if (aChar == ' ')
aLeftSpaces++;
else if (aChar == '\t')
aLeftSpaces += 8;
else if (aChar == '\r' || *aPtr == '\n')
aLeftSpaces = 0;
else
break;
aPtr++;
}
// Find the end of the string
for (anEndPtr = aPtr; *anEndPtr; anEndPtr++)
if (anEndPtr[0] == '\n')
{
if (anEndPtr[-1] == '\r')
anEndPtr--;
break;
}
} while (aPtr[0] == '!');
// form the result
if (aPtr == anEndPtr)
return Standard_False;
thePtr = anEndPtr;
if (*thePtr)
*thePtr++ = '\0';
theString = typename TCollection_String<CharType>::type(aPtr);
theLeftSpaces = aLeftSpaces;
return Standard_True;
}
//=======================================================================
// function : loadFile
// purpose : Static function, fills the DataMap of Messages from Ascii or Unicode
// Called : from LoadFile()
//=======================================================================
template <class _Char>
static inline Standard_Boolean loadFile(_Char* theBuffer)
{
TCollection_AsciiString aKeyword;
TCollection_ExtendedString aMessage, aString;
LoadingState aState = MsgFile_WaitingKeyword;
_Char* sCurrentString = theBuffer;
Standard_Integer aLeftSpaces = 0, aFirstLeftSpaces = 0;
// Take strings one-by-one; comments already screened
while (::getString(sCurrentString, aString, aLeftSpaces))
{
Standard_Boolean isKeyword = (aString.Value(1) == '.');
switch (aState)
{
case MsgFile_WaitingMoreMessage:
if (isKeyword)
Message_MsgFile::AddMsg(aKeyword, aMessage); // terminate the previous one
// Pass from here to 'case MsgFile_WaitingKeyword'
else
{
// Add another line to the message already in the buffer 'aMessage'
aMessage += '\n';
aLeftSpaces -= aFirstLeftSpaces;
if (aLeftSpaces > 0)
aMessage += TCollection_ExtendedString(aLeftSpaces, ' ');
aMessage += aString;
break;
}
Standard_FALLTHROUGH
case MsgFile_WaitingMessage:
if (isKeyword == Standard_False)
{
aMessage = aString;
aFirstLeftSpaces = aLeftSpaces; // remember the starting position
aState = MsgFile_WaitingMoreMessage;
break;
}
// Pass from here to 'case MsgFile_WaitingKeyword'
Standard_FALLTHROUGH
case MsgFile_WaitingKeyword:
if (isKeyword)
{
// remove the first dot character and all subsequent spaces + right-trim
aKeyword = TCollection_AsciiString(aString.Split(1));
aKeyword.LeftAdjust();
aKeyword.RightAdjust();
aState = MsgFile_WaitingMessage;
}
break;
default:
break;
}
}
// Process the last string still remaining in the buffer
if (aState == MsgFile_WaitingMoreMessage)
Message_MsgFile::AddMsg(aKeyword, aMessage);
return Standard_True;
}
//=================================================================================================
static Standard_Integer GetFileSize(FILE* theFile)
{
if (!theFile)
return -1;
// get real file size
long nRealFileSize = 0;
if (fseek(theFile, 0, SEEK_END) != 0)
return -1;
nRealFileSize = ftell(theFile);
if (fseek(theFile, 0, SEEK_SET) != 0)
return -1;
return (Standard_Integer)nRealFileSize;
}
//=======================================================================
// function : LoadFile
// purpose : Load the list of messages from a file
//=======================================================================
Standard_Boolean Message_MsgFile::LoadFile(const Standard_CString theFileName)
{
if (theFileName == NULL || *theFileName == '\0')
return Standard_False;
// Open the file
FILE* anMsgFile = OSD_OpenFile(theFileName, "rb");
if (!anMsgFile)
return Standard_False;
const Standard_Integer aFileSize = GetFileSize(anMsgFile);
NCollection_Buffer aBuffer(NCollection_BaseAllocator::CommonBaseAllocator());
if (aFileSize <= 0 || !aBuffer.Allocate(aFileSize + 2))
{
fclose(anMsgFile);
return Standard_False;
}
char* anMsgBuffer = reinterpret_cast<char*>(aBuffer.ChangeData());
const Standard_Integer nbRead =
static_cast<Standard_Integer>(fread(anMsgBuffer, 1, aFileSize, anMsgFile));
fclose(anMsgFile);
if (nbRead != aFileSize)
return Standard_False;
anMsgBuffer[aFileSize] = 0;
anMsgBuffer[aFileSize + 1] = 0;
// Read the messages in the file and append them to the global DataMap
Standard_Boolean isLittleEndian = (anMsgBuffer[0] == '\xff' && anMsgBuffer[1] == '\xfe');
Standard_Boolean isBigEndian = (anMsgBuffer[0] == '\xfe' && anMsgBuffer[1] == '\xff');
if (isLittleEndian || isBigEndian)
{
Standard_ExtCharacter* aUnicodeBuffer =
reinterpret_cast<Standard_ExtCharacter*>(&anMsgBuffer[2]);
// Convert Unicode representation to order adopted on current platform
#if defined(__sparc) && defined(__sun)
if (isLittleEndian)
#else
if (isBigEndian)
#endif
{
// Reverse the bytes throughout the buffer
const Standard_ExtCharacter* const anEnd =
reinterpret_cast<const Standard_ExtCharacter*>(&anMsgBuffer[aFileSize]);
for (Standard_ExtCharacter* aPtr = aUnicodeBuffer; aPtr < anEnd; aPtr++)
{
unsigned short aWord = *aPtr;
*aPtr = (aWord & 0x00ff) << 8 | (aWord & 0xff00) >> 8;
}
}
return ::loadFile(aUnicodeBuffer);
}
else
return ::loadFile(anMsgBuffer);
}
//=================================================================================================
Standard_Boolean Message_MsgFile::LoadFromEnv(const Standard_CString theEnvName,
const Standard_CString theFileName,
const Standard_CString theLangExt)
{
TCollection_AsciiString aLangExt(theLangExt != NULL ? theLangExt : "");
if (aLangExt.IsEmpty())
{
OSD_Environment aLangEnv("CSF_LANGUAGE");
aLangExt = aLangEnv.Value();
if (aLangExt.IsEmpty())
{
aLangExt = "us";
}
}
TCollection_AsciiString aFilePath(theFileName);
if (theEnvName != NULL && theEnvName[0] != '\0')
{
OSD_Environment aNameEnv(theEnvName);
TCollection_AsciiString aNameEnvStr = aNameEnv.Value();
if (!aNameEnvStr.IsEmpty())
{
if (aNameEnvStr.Value(aNameEnvStr.Length()) != '/')
{
aFilePath.Insert(1, '/');
}
aFilePath.Insert(1, aNameEnvStr);
}
}
if (aLangExt.Value(1) != '.')
{
aFilePath.AssignCat('.');
}
aFilePath.AssignCat(aLangExt);
return Message_MsgFile::LoadFile(aFilePath.ToCString());
}
//=================================================================================================
Standard_Boolean Message_MsgFile::LoadFromString(const Standard_CString theContent,
const Standard_Integer theLength)
{
Standard_Integer aStringSize = theLength >= 0 ? theLength : (Standard_Integer)strlen(theContent);
NCollection_Buffer aBuffer(NCollection_BaseAllocator::CommonBaseAllocator());
if (aStringSize <= 0 || !aBuffer.Allocate(aStringSize + 2))
{
return Standard_False;
}
memcpy(aBuffer.ChangeData(), theContent, aStringSize);
aBuffer.ChangeData()[aStringSize + 0] = '\0';
aBuffer.ChangeData()[aStringSize + 1] = '\0';
char* anMsgBuffer = reinterpret_cast<char*>(aBuffer.ChangeData());
return ::loadFile(anMsgBuffer);
}
//=======================================================================
// function : AddMsg
// purpose : Add one message to the global table. Fails if the same keyword
// already exists in the table
//=======================================================================
Standard_Boolean Message_MsgFile::AddMsg(const TCollection_AsciiString& theKeyword,
const TCollection_ExtendedString& theMessage)
{
Message_DataMapOfExtendedString& aDataMap = ::msgsDataMap();
Standard_Mutex::Sentry aSentry(Message_MsgFile_Mutex());
aDataMap.Bind(theKeyword, theMessage);
return Standard_True;
}
//=======================================================================
// function : getMsg
// purpose : retrieve the message previously defined for the given keyword
//=======================================================================
const TCollection_ExtendedString& Message_MsgFile::Msg(const Standard_CString theKeyword)
{
TCollection_AsciiString aKey(theKeyword);
return Msg(aKey);
}
//=================================================================================================
Standard_Boolean Message_MsgFile::HasMsg(const TCollection_AsciiString& theKeyword)
{
Standard_Mutex::Sentry aSentry(Message_MsgFile_Mutex());
return ::msgsDataMap().IsBound(theKeyword);
}
//=======================================================================
// function : Msg
// purpose : retrieve the message previously defined for the given keyword
//=======================================================================
const TCollection_ExtendedString& Message_MsgFile::Msg(const TCollection_AsciiString& theKeyword)
{
// find message in the map
Message_DataMapOfExtendedString& aDataMap = ::msgsDataMap();
Standard_Mutex::Sentry aSentry(Message_MsgFile_Mutex());
// if message is not found, generate error message and add it to the map to minimize overhead
// on consequent calls with the same key
const TCollection_ExtendedString* aValPtr = aDataMap.Seek(theKeyword);
if (aValPtr == NULL)
{
// text of the error message can be itself defined in the map
static const TCollection_AsciiString aPrefixCode("Message_Msg_BadKeyword");
static const TCollection_ExtendedString aDefPrefix("Unknown message invoked with the keyword ");
const TCollection_ExtendedString* aPrefValPtr = aDataMap.Seek(aPrefixCode);
TCollection_AsciiString aErrorMessage = (aPrefValPtr != NULL ? *aPrefValPtr : aDefPrefix);
aErrorMessage += theKeyword;
aDataMap.Bind(theKeyword, aErrorMessage); // do not use AddMsg() here to avoid mutex deadlock
aValPtr = aDataMap.Seek(theKeyword);
}
return *aValPtr;
}