Skip to content

Commit

Permalink
Add TextLoadFile derivation rule
Browse files Browse the repository at this point in the history
Nouvele regle de derivation TextLoadFile
- input: un nom de fichier
- output: une variable Text avec le contenu du fichier
- comportement precis
  - il ne se passe rien s'il n'y a pas de nom de fichier specifie
  - on gere les fichiers avec URI, si les drivers sont installés
  - le contenu est traite comme quand il sera ecrit dans un fichier tabule en sortie
    - le champ est trime a droite et gauche
    - les caracteres fin de ligne sont transforme en blancs
    - son contenu est limite a la taille max des Text (1000000 de caracteres)
      - y compris en tenant compte des eventuels double-quotes dans le cas de text cntenant le separateur de champ
  - les erreurs de lectures sont traites comme des warning pour informer l'utilisateur, sans etre bloquant
- impacts
  - KWDRKWDRTextLoadFile: nouvelle classe dans le fichier KWDRRuleLibrairy/KWDTText
  - Global::Set|GetErrorAsWarningMode
    - parametrage d'un mode de gestion des erreur comme des warning
    - active temporairement dans la classe KWDRKWDRTextLoadFile
  • Loading branch information
marcboulle committed Dec 4, 2023
1 parent b49f428 commit 3d4cda6
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 4 deletions.
140 changes: 140 additions & 0 deletions src/Learning/KWDRRuleLibrary/KWDRText.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

void KWDRRegisterTextRules()
{
KWDerivationRule::RegisterDerivationRule(new KWDRTextLoadFile);
KWDerivationRule::RegisterDerivationRule(new KWDRTextLength);
KWDerivationRule::RegisterDerivationRule(new KWDRTextLeft);
KWDerivationRule::RegisterDerivationRule(new KWDRTextRight);
Expand All @@ -31,6 +32,145 @@ void KWDRRegisterTextRules()

//////////////////////////////////////////////////////////////////////////////////////

KWDRTextLoadFile::KWDRTextLoadFile()
{
SetName("TextLoadFile");
SetLabel("Load the content of a file into a text value");
SetType(KWType::Text);
SetOperandNumber(1);
GetFirstOperand()->SetType(KWType::Symbol);
}

KWDRTextLoadFile::~KWDRTextLoadFile() {}

KWDerivationRule* KWDRTextLoadFile::Create() const
{
return new KWDRTextLoadFile;
}

Symbol KWDRTextLoadFile::ComputeTextResult(const KWObject* kwoObject) const
{
Symbol sLoadedText;
ALString sPathFileName;
InputBufferedFile inputFile;
boolean bOk;
longint lBeginPos;
const CharVector* cvFileCache;
char* sHugeBuffer;
int nTextLength;
int nDoubleQuoteNumber;
int nStart;
int nStop;
char c;
int i;
ALString sTmp;

require(IsCompiled());

// Lecture du fichier si un path est specifie
sPathFileName = GetFirstOperand()->GetSymbolValue(kwoObject);
if (sPathFileName != "")
{
// On traite teporairement les error en warning, pour prevenir l'utilisateur d'un probleme
// sans que cela ne soit bloquant
Global::SetErrorAsWarningMode(true);

// Parametrage du fichier, avec la taille maximum possible pour un champ de type Text
inputFile.SetFileName(sPathFileName);
inputFile.SetUTF8BomManagement(false);
inputFile.SetBufferSize(InputBufferedFile::nMaxFieldSize);

// Lecture d'un fichier
bOk = inputFile.Open();
if (bOk)
{
// Lecture
lBeginPos = 0;
bOk = inputFile.FillBytes(lBeginPos);

// Remplissage d'un buffer de grande taille
// Permet de stocker tout le contenu du fichier en un seul blob memoire alloue efficacement
// afin de se preparer en le stocker sous forme de Symbol
if (bOk)
{
// Recherche d'un gros blob memoire en le terminaux par une fin de chaine de caracteres
nTextLength = inputFile.GetCurrentBufferSize();
sHugeBuffer = GetHugeBuffer(nTextLength + 1);
sHugeBuffer[nTextLength] = '\0';

// Acces aux methodes de bas niveau du fichier pour transferer directement le contenu
// du cache du fichier vers le buffer
cvFileCache = inputFile.GetCache();
assert(inputFile.GetBufferStartInCache() == 0);
nDoubleQuoteNumber = 0;
for (i = 0; i < nTextLength; i++)
{
c = cvFileCache->GetAt(i);

// Comptage des double-quotes de la chaine pour ne pas depasser la taille limite des Text
if (sHugeBuffer[i] == '"')
nDoubleQuoteNumber++;

// On remplace par des blancs les caracteres posant des problemes a l'ecriture d'un text
// sous la forme d'un champ d'une base de donnees
if (c == '\0' or c == '\n' or c == '\r')
c = ' ';
sHugeBuffer[i] = c;
}

// On supprime les blancs en debut et fin de la chaine pour que le champ Text
// soit exactement le meme que celui qui serait relu depuis un fichier tabulaire,
// dont les champs sont "trimes" (cf. InputBufferedFile::GetNextField)

// Supression des blancs en fin
nStart = 0;
while (nStart < nTextLength)
{
if (iswspace(sHugeBuffer[nStart]))
nStart++;
else
break;
}
nTextLength -= nStart;

// S'il y a risque de depassement de la taille limites des Text en doublant les doubles quotes
// et en inserant la valeur entre 2 doubles-quote (cas ou la valeur contient le separateur
// de champ des fichiers tabulaires), on diminue la taille du texte en proportion
if (nTextLength + 2 + nDoubleQuoteNumber > InputBufferedFile::nMaxFieldSize)
nTextLength = InputBufferedFile::nMaxFieldSize - (2 + nDoubleQuoteNumber);

// Supression des blancs en fin
nStop = nStart + nTextLength - 1;
while (nStop >= nStart)
{
if (iswspace(sHugeBuffer[nStop]))
nStop--;
else
break;
}
nStop++;
sHugeBuffer[nStop] = '\0';
nTextLength = nStop - nStart;

// Transformation du buffer en Symbol
sLoadedText = Symbol(&sHugeBuffer[nStart], nTextLength);
}

// Fermeture du fichier
inputFile.Close();
}

// Si erreur, emission d'un warning permettant de localiser l'enreigistrement
if (not bOk)
AddWarning(sTmp + "Enable to load text file in record " +
LongintToReadableString(kwoObject->GetCreationIndex()));

// Restittion du mode standard de traitement des erreurs
Global::SetErrorAsWarningMode(false);
}
return sLoadedText;
}

KWDRTextLength::KWDRTextLength()
{
TransformSymbolToTextRule();
Expand Down
25 changes: 25 additions & 0 deletions src/Learning/KWDRRuleLibrary/KWDRText.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
// Toutes les regles de KWDRString sont implementees de facon generique en sous-classes
// de la classe KWDRStringRule, ce qui permet de redefinir tres simplement chaque
// regle correspondante pour le type Text
// Seul la regle KWDRTextLoadFile est specifique au type Text

class KWDRTextLoadFile;
class KWDRTextLength;
class KWDRTextLeft;
class KWDRTextRight;
Expand All @@ -42,10 +44,33 @@ class KWDRTextHash;
class KWDRTextEncrypt;

#include "KWDRString.h"
#include "InputBufferedFile.h"
#include "HugeBuffer.h"

// Enregistrement de ces regles
void KWDRRegisterTextRules();

////////////////////////////////////////////////////////////////////////////
// Classe KWDRTextLoadFile
// Chargement d'un fichier sous forme d'une variable Text
// Le fichier peut etre local ou avoir un nom ayant une URI
// Le chargement se fait a concurrence de la taille max d'une variable de type Text
// Les caractere '\0', '\r' et '\n' sont remplace par des blancs pour ne pas poser
// de probleme quand on ecrit les base en sortie
class KWDRTextLoadFile : public KWDerivationRule
{
public:
// Constructeur
KWDRTextLoadFile();
~KWDRTextLoadFile();

// Creation
KWDerivationRule* Create() const override;

// Calcul de l'attribut derive
Symbol ComputeTextResult(const KWObject* kwoObject) const override;
};

////////////////////////////////////////////////////////////////////////////
// Classe KWDRTextLength
class KWDRTextLength : public KWDRLength
Expand Down
2 changes: 1 addition & 1 deletion src/Learning/MODL/MODL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ int main(int argc, char** argv)
// Choix du repertoire de lancement pour le debugage sous Windows (a commenter apres fin du debug)
// SetWindowsDebugDir("Standard", "IrisLight");
// SetWindowsDebugDir("Standard", "Iris2D");
SetWindowsDebugDir("z_Work", "IrisLight");
SetWindowsDebugDir("TextVariables", "TextLoadFile");

// Parametrage des logs memoires depuis les variables d'environnement, pris en compte dans KWLearningProject
// KhiopsMemStatsLogFileName, KhiopsMemStatsLogFrequency, KhiopsMemStatsLogToCollect
Expand Down
23 changes: 21 additions & 2 deletions src/Norm/base/Ermgt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,15 @@ void Global::AddWarning(const ALString& sCategoryValue, const ALString& sLocalis

void Global::AddError(const ALString& sCategoryValue, const ALString& sLocalisationValue, const ALString& sLabelValue)
{
bIsAtLeastOneError = true;
AddErrorObjectValued(Error::GravityError, sCategoryValue, sLocalisationValue, sLabelValue);
// Traitement de l'erreur comme un warning
if (GetErrorAsWarningMode())
AddWarning(sCategoryValue, sLocalisationValue, sLabelValue);
// Traitement standard de l'erreur
else
{
bIsAtLeastOneError = true;
AddErrorObjectValued(Error::GravityError, sCategoryValue, sLocalisationValue, sLabelValue);
}
}

void Global::AddFatalError(const ALString& sCategoryValue, const ALString& sLocalisationValue,
Expand Down Expand Up @@ -264,6 +271,16 @@ boolean Global::GetSilentMode()
return bSilentMode;
}

void Global::SetErrorAsWarningMode(boolean bValue)
{
bErrorAsWarningMode = bValue;
}

boolean Global::GetErrorAsWarningMode()
{
return bErrorAsWarningMode;
}

// Les erreurs de l'allocateur sont redirigees sur la gestion centralisee des erreurs
static int GlobalMemSetAllocErrorHandler()
{
Expand Down Expand Up @@ -364,6 +381,8 @@ longint Global::lErrorFlowErrorNumber = 0;

boolean Global::bSilentMode = false;

boolean Global::bErrorAsWarningMode = false;

ALString Global::sErrorLogFileName;

fstream Global::fstError;
Expand Down
9 changes: 9 additions & 0 deletions src/Norm/base/Ermgt.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ class Global : public SystemObject
static void SetSilentMode(boolean bValue);
static boolean GetSilentMode();

// Traitement des erreur comme des warning
// Par defaut: false
// Dans ce mode, les erreurs ne sont emises sous sorme de warning
static void SetErrorAsWarningMode(boolean bValue);
static boolean GetErrorAsWarningMode();

// Gestion d'un fichier de log des erreurs
// Par defaut: aucun
// Quand on precise un fichier de log des erreurs, toute
Expand Down Expand Up @@ -177,6 +183,9 @@ class Global : public SystemObject
// Mode silencieux
static boolean bSilentMode;

// Mode du traitement des erreurs comme des warning
static boolean bErrorAsWarningMode;

// Gestion du fichier d'erreur
static ALString sErrorLogFileName;
static fstream fstError;
Expand Down
2 changes: 1 addition & 1 deletion src/Norm/base/InputBufferedFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ boolean InputBufferedFile::GetNextField(char*& sField, int& nFieldLength, int& n
// Supression des blancs en fin (TrimRight)
// Attention: on utilise iswspace et non isspace, systematiquement dans tous les sources
// Une tentative de passage a isspace a entraine une degradation des performances de presque 25%
// dans un traitement complet impliquant des lecture de fichier
// dans un traitement complet impliquant des lectures de fichier
i--;
while (i >= 0)
{
Expand Down

0 comments on commit 3d4cda6

Please sign in to comment.