<commit_before>// @(#)root/rint:$Name:  $:$Id: TRint.cxx,v 1.41 2004/08/07 23:49:31 rdm Exp $
// Author: Rene Brun   17/02/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Rint                                                                 //
//                                                                      //
// Rint is the ROOT Interactive Interface. It allows interactive access //
// to the ROOT system via the CINT C/C++ interpreter.                   //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TROOT.h"
#include "TClass.h"
#include "TVirtualX.h"
#include "Getline.h"
#include "TStyle.h"
#include "TObjectTable.h"
#include "TClassTable.h"
#include "TStopwatch.h"
#include "TBenchmark.h"
#include "TRint.h"
#include "TSystem.h"
#include "TEnv.h"
#include "TSysEvtHandler.h"
#include "TError.h"
#include "TException.h"
#include "TInterpreter.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TFile.h"
#include "TMapFile.h"
#include "TTabCom.h"
#include "TError.h"

#ifdef R__UNIX
#include <signal.h>

extern "C" {
   extern int G__get_security_error();
   extern int G__genericerror(const char* msg);
}
#endif

static Int_t key_pressed(Int_t key) { gApplication->KeyPressed(key); return 0; }

//----- Interrupt signal handler -----------------------------------------------
//______________________________________________________________________________
class TInterruptHandler : public TSignalHandler {
public:
   TInterruptHandler() : TSignalHandler(kSigInterrupt, kFALSE) { }
   Bool_t  Notify();
};

//______________________________________________________________________________
Bool_t TInterruptHandler::Notify()
{
   // TRint interrupt handler.

   if (fDelay) {
      fDelay++;
      return kTRUE;
   }

   // make sure we use the sbrk heap (in case of mapped files)
   gMmallocDesc = 0;

   if (!G__get_security_error())
      G__genericerror("\n *** Break *** keyboard interrupt");
   else {
      Break("TInterruptHandler::Notify", "keyboard interrupt");
      if (TROOT::Initialized()) {
         Getlinem(kInit, "Root > ");
         gInterpreter->RewindDictionary();
         Throw(GetSignal());
      }
   }
   return kTRUE;
}

//----- Terminal Input file handler --------------------------------------------
//______________________________________________________________________________
class TTermInputHandler : public TFileHandler {
public:
   TTermInputHandler(Int_t fd) : TFileHandler(fd, 1) { }
   Bool_t Notify();
   Bool_t ReadNotify() { return Notify(); }
};

//______________________________________________________________________________
Bool_t TTermInputHandler::Notify()
{
   return gApplication->HandleTermInput();
}

ClassImp(TRint)

//______________________________________________________________________________
TRint::TRint(const char *appClassName, Int_t *argc, char **argv, void *options,
             Int_t numOptions, Bool_t noLogo)
       : TApplication(appClassName, argc, argv, options, numOptions)
{
   // Create an application environment. The TRint environment provides an
   // interface to the WM manager functionality and eventloop via inheritance
   // of TApplication and in addition provides interactive access to
   // the CINT C++ interpreter via the command line.

   fNcmd          = 0;
   fDefaultPrompt = "root [%d] ";
   fInterrupt     = kFALSE;

   gBenchmark = new TBenchmark();

   if (!noLogo && !NoLogoOpt())
      PrintLogo();

   // Everybody expects iostream to be available, so load it...
   ProcessLine("#include <iostream>", kTRUE);
   ProcessLine("#include <_string>", kTRUE); // for std::string iostream.

   // Allow the usage of ClassDef and ClassImp in interpreted macros
   ProcessLine("#include <RtypesCint.h>", kTRUE);

   // Disallow the interpretation of Rtypes.h, TError.h and TGenericClassInfo.h
   ProcessLine("#define ROOT_Rtypes 0", kTRUE);
   ProcessLine("#define ROOT_TError 0", kTRUE);
   ProcessLine("#define ROOT_TGenericClassInfo 0", kTRUE);

   // The following libs are also useful to have, make sure they are loaded...
   gROOT->LoadClass("TMinuit",     "Minuit");
   gROOT->LoadClass("TPostScript", "Postscript");
   gROOT->LoadClass("THtml",       "Html");

   // Load user functions
   const char *logon;
   logon = gEnv->GetValue("Rint.Load", (char*)0);
   if (logon) {
      char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);
      if (mac)
         ProcessLine(Form(".L %s",logon),kTRUE);
      delete [] mac;
   }

   // Execute logon macro
   logon = gEnv->GetValue("Rint.Logon", (char*)0);
   if (logon && !NoLogOpt()) {
      char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);
      if (mac)
         ProcessFile(logon);
      delete [] mac;
   }

   // Save current interpreter context
   gInterpreter->SaveContext();
   gInterpreter->SaveGlobalsContext();

   // Install interrupt and terminal input handlers
   TInterruptHandler *ih = new TInterruptHandler();
   ih->Add();
   SetSignalHandler(ih);

   // Handle stdin events
   fInputHandler = new TTermInputHandler(0);
   fInputHandler->Add();

   // Goto into raw terminal input mode
   char defhist[128];
#ifndef R__VMS
   sprintf(defhist, "%s/.root_hist", gSystem->Getenv("HOME"));
#else
   sprintf(defhist, "%s.root_hist", gSystem->Getenv("HOME"));
#endif
   logon = gEnv->GetValue("Rint.History", defhist);
   Gl_histinit((char *)logon);
   Gl_windowchanged();

   // Setup for tab completion
   gTabCom = new TTabCom;
   Gl_in_key = &key_pressed;
}

//______________________________________________________________________________
TRint::~TRint()
{

}

//______________________________________________________________________________
void TRint::Run(Bool_t retrn)
{
   // Main application eventloop. First process files given on the command
   // line and then go into the main application event loop, unless the -q
   // command line option was specfied in which case the program terminates.
   // When retrun is true this method returns even when -q was specified.
   //
   // When QuitOpt is true and retrn is false, terminate the application with
   // an error code equal to either the ProcessLine error (if any) or the
   // return value of the command casted to a long.

   Getlinem(kInit, GetPrompt());

   Long_t retval = 0;
   Int_t  error = 0;

   // Process shell command line input files
   if (InputFiles()) {
      Bool_t needGetlinemInit = kFALSE;
      TIter next(InputFiles());
      RETRY {
         retval = 0; error = 0;
         Int_t nfile = 0;
         TObjString *file;
         while ((file = (TObjString *)next())) {
            char cmd[256];
            if (!fNcmd)
               printf("\n");
            if (file->String().EndsWith(".root")) {
               const char *rfile = (const char*)file->String();
               Printf("Attaching file %s as _file%d...", rfile, nfile);
               sprintf(cmd, "TFile *_file%d = TFile::Open(\"%s\")", nfile++, rfile);
            } else {
               Printf("Processing %s...", (const char*)file->String());
               sprintf(cmd, ".x %s", (const char*)file->String());
            }
            Getlinem(kCleanUp, 0);
            Gl_histadd(cmd);
            fNcmd++;

            // The ProcessLine might throw an 'exception'.  In this case,
            // GetLinem(kInit,"Root >") is called and we are jump back
            // to RETRY ... and we have to avoid the Getlinem(kInit, GetPrompt());
            needGetlinemInit = kFALSE;
            retval = ProcessLine(cmd, kFALSE, &error);

            // The ProcessLine has successfully completed and we need
            // to call Getlinem(kInit, GetPrompt());
            needGetlinemInit = kTRUE;

            if (error != 0) break;
         }
      } ENDTRY;

      if (QuitOpt()) {
         if (retrn) return;
         Terminate(error == 0 ? retval : error);
      }

      ClearInputFiles();

      if (needGetlinemInit) Getlinem(kInit, GetPrompt());
   }

   if (QuitOpt()) {
      printf("\n");
      if (retrn) return;
      Terminate(0);
   }

   TApplication::Run(retrn);

   Getlinem(kCleanUp, 0);
}

//______________________________________________________________________________
void TRint::PrintLogo()
{
   // Print the ROOT logo on standard output.

   Int_t iday,imonth,iyear;
   static const char *months[] = {"January","February","March","April","May",
                                  "June","July","August","September","October",
                                  "November","December"};
   const char *root_version = gROOT->GetVersion();
   Int_t idatqq = gROOT->GetVersionDate();
   iday   = idatqq%100;
   imonth = (idatqq/100)%100;
   iyear  = (idatqq/10000);
   char *root_date = Form("%d %s %4d",iday,months[imonth-1],iyear);

   Printf("  *******************************************");
   Printf("  *                                         *");
   Printf("  *        W E L C O M E  to  R O O T       *");
   Printf("  *                                         *");
   Printf("  *   Version%10s %17s   *", root_version, root_date);
// Printf("  *            Development version          *");
   Printf("  *                                         *");
   Printf("  *  You are welcome to visit our Web site  *");
   Printf("  *          http://root.cern.ch            *");
   Printf("  *                                         *");
   Printf("  *******************************************");

   if (strstr(gVirtualX->GetName(), "TTF")) {
      Int_t major, minor, patch;
      //TTF::Version(major, minor, patch);
      // avoid dependency on libGraf and hard code, will not change too often
      major = 2; minor = 1; patch = 3;
      Printf("\nFreeType Engine v%d.%d.%d used to render TrueType fonts.",
             major, minor, patch);
   }
#ifdef _REENTRANT
   else
      printf("\n");
   Printf("Compiled for %s with thread support.", gSystem->GetBuildArch());
#else
   else
      printf("\n");
   Printf("Compiled for %s.", gSystem->GetBuildArch());
#endif

   gInterpreter->PrintIntro();

#ifdef R__UNIX
   // Popdown X logo, only if started with -splash option
   for (int i = 0; i < Argc(); i++)
      if (!strcmp(Argv(i), "-splash"))
         kill(getppid(), SIGUSR1);
#endif
}

//______________________________________________________________________________
char *TRint::GetPrompt()
{
   // Get prompt from interpreter. Either "root [n]" or "end with '}'".

   char *s = gInterpreter->GetPrompt();
   if (s[0])
      strcpy(fPrompt, s);
   else
      sprintf(fPrompt, fDefaultPrompt.Data(), fNcmd);

   return fPrompt;
}

//______________________________________________________________________________
const char *TRint::SetPrompt(const char *newPrompt)
{
   // Set a new default prompt. It returns the previous prompt.
   // The prompt may contain a %d which will be replaced by the commend
   // number. The default prompt is "root [%d] ". The maximum length of
   // the prompt is 55 characters. To set the prompt in an interactive
   // session do:
   // root [0] ((TRint*)gROOT->GetApplication())->SetPrompt("aap> ")
   // aap>

   static TString op = fDefaultPrompt;

   if (newPrompt && strlen(newPrompt) <= 55)
      fDefaultPrompt = newPrompt;
   else
      Error("SetPrompt", "newPrompt too long (> 55 characters)");

   return op.Data();
}

//______________________________________________________________________________
Bool_t TRint::HandleTermInput()
{
   // Handle input coming from terminal.

   static TStopwatch timer;
   char *line;

   if ((line = Getlinem(kOneChar, 0))) {
      if (line[0] == 0 && Gl_eof())
         Terminate(0);

      gVirtualX->SetKeyAutoRepeat(kTRUE);

      Gl_histadd(line);

      TString sline = line;
      line[0] = 0;

      // strip off '\n' and leading and trailing blanks
      sline = sline.Chop();
      sline = sline.Strip(TString::kBoth);
      ReturnPressed((char*)sline.Data());

      fInterrupt = kFALSE;

      if (!gInterpreter->GetMore() && !sline.IsNull()) fNcmd++;

      // prevent recursive calling of this input handler
      fInputHandler->DeActivate();

      if (gROOT->Timer()) timer.Start();

      Bool_t added = kFALSE;
#ifdef R__EH
      try {
#endif
         TRY {
            ProcessLine(sline);
         } CATCH(excode) {
            // enable again input handler
            fInputHandler->Activate();
            added = kTRUE;
            Throw(excode);
         } ENDTRY;
#ifdef R__EH
      }
      // handle every exception
      catch (...) {
         // enable again intput handler
         if (!added) fInputHandler->Activate();
         throw;
      }
#endif

      if (gROOT->Timer()) timer.Print("u");

      // enable again intput handler
      fInputHandler->Activate();

      if (!sline.BeginsWith(".reset"))
         gInterpreter->EndOfLineAction();

      gTabCom->ClearAll();
      Getlinem(kInit, GetPrompt());
   }
   return kTRUE;
}

//______________________________________________________________________________
void TRint::Terminate(Int_t status)
{
   // Terminate the application. Reset the terminal to sane mode and call
   // the logoff macro defined via Rint.Logoff environment variable.

   Getlinem(kCleanUp, 0);

   if (ReturnFromRun()) {
      gSystem->ExitLoop();
   } else {
      //Execute logoff macro
      const char *logoff;
      logoff = gEnv->GetValue("Rint.Logoff", (char*)0);
      if (logoff && !NoLogOpt()) {
         char *mac = gSystem->Which(TROOT::GetMacroPath(), logoff, kReadPermission);
         if (mac)
            ProcessFile(logoff);
         delete [] mac;
      }

      gSystem->Exit(status);
   }
}

//______________________________________________________________________________
void TRint::SetEchoMode(Bool_t mode)
{
   // Set console mode:
   //
   //  mode = kTRUE  - echo input symbols
   //  mode = kFALSE - noecho input symbols

   Gl_config("noecho", mode ? 0 : 1);
}
<commit_msg>From Philippe: This patch insures that the temporary object created by a script given as an argument are deleted immediately (instead of __after__ the execution of the user's first command).<commit_after>// @(#)root/rint:$Name:  $:$Id: TRint.cxx,v 1.42 2005/01/05 01:28:12 rdm Exp $
// Author: Rene Brun   17/02/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Rint                                                                 //
//                                                                      //
// Rint is the ROOT Interactive Interface. It allows interactive access //
// to the ROOT system via the CINT C/C++ interpreter.                   //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TROOT.h"
#include "TClass.h"
#include "TVirtualX.h"
#include "Getline.h"
#include "TStyle.h"
#include "TObjectTable.h"
#include "TClassTable.h"
#include "TStopwatch.h"
#include "TBenchmark.h"
#include "TRint.h"
#include "TSystem.h"
#include "TEnv.h"
#include "TSysEvtHandler.h"
#include "TError.h"
#include "TException.h"
#include "TInterpreter.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TFile.h"
#include "TMapFile.h"
#include "TTabCom.h"
#include "TError.h"

#ifdef R__UNIX
#include <signal.h>

extern "C" {
   extern int G__get_security_error();
   extern int G__genericerror(const char* msg);
}
#endif

static Int_t key_pressed(Int_t key) { gApplication->KeyPressed(key); return 0; }

//----- Interrupt signal handler -----------------------------------------------
//______________________________________________________________________________
class TInterruptHandler : public TSignalHandler {
public:
   TInterruptHandler() : TSignalHandler(kSigInterrupt, kFALSE) { }
   Bool_t  Notify();
};

//______________________________________________________________________________
Bool_t TInterruptHandler::Notify()
{
   // TRint interrupt handler.

   if (fDelay) {
      fDelay++;
      return kTRUE;
   }

   // make sure we use the sbrk heap (in case of mapped files)
   gMmallocDesc = 0;

   if (!G__get_security_error())
      G__genericerror("\n *** Break *** keyboard interrupt");
   else {
      Break("TInterruptHandler::Notify", "keyboard interrupt");
      if (TROOT::Initialized()) {
         Getlinem(kInit, "Root > ");
         gInterpreter->RewindDictionary();
         Throw(GetSignal());
      }
   }
   return kTRUE;
}

//----- Terminal Input file handler --------------------------------------------
//______________________________________________________________________________
class TTermInputHandler : public TFileHandler {
public:
   TTermInputHandler(Int_t fd) : TFileHandler(fd, 1) { }
   Bool_t Notify();
   Bool_t ReadNotify() { return Notify(); }
};

//______________________________________________________________________________
Bool_t TTermInputHandler::Notify()
{
   return gApplication->HandleTermInput();
}

ClassImp(TRint)

//______________________________________________________________________________
TRint::TRint(const char *appClassName, Int_t *argc, char **argv, void *options,
             Int_t numOptions, Bool_t noLogo)
       : TApplication(appClassName, argc, argv, options, numOptions)
{
   // Create an application environment. The TRint environment provides an
   // interface to the WM manager functionality and eventloop via inheritance
   // of TApplication and in addition provides interactive access to
   // the CINT C++ interpreter via the command line.

   fNcmd          = 0;
   fDefaultPrompt = "root [%d] ";
   fInterrupt     = kFALSE;

   gBenchmark = new TBenchmark();

   if (!noLogo && !NoLogoOpt())
      PrintLogo();

   // Everybody expects iostream to be available, so load it...
   ProcessLine("#include <iostream>", kTRUE);
   ProcessLine("#include <_string>", kTRUE); // for std::string iostream.

   // Allow the usage of ClassDef and ClassImp in interpreted macros
   ProcessLine("#include <RtypesCint.h>", kTRUE);

   // Disallow the interpretation of Rtypes.h, TError.h and TGenericClassInfo.h
   ProcessLine("#define ROOT_Rtypes 0", kTRUE);
   ProcessLine("#define ROOT_TError 0", kTRUE);
   ProcessLine("#define ROOT_TGenericClassInfo 0", kTRUE);

   // The following libs are also useful to have, make sure they are loaded...
   gROOT->LoadClass("TMinuit",     "Minuit");
   gROOT->LoadClass("TPostScript", "Postscript");
   gROOT->LoadClass("THtml",       "Html");

   // Load user functions
   const char *logon;
   logon = gEnv->GetValue("Rint.Load", (char*)0);
   if (logon) {
      char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);
      if (mac)
         ProcessLine(Form(".L %s",logon),kTRUE);
      delete [] mac;
   }

   // Execute logon macro
   logon = gEnv->GetValue("Rint.Logon", (char*)0);
   if (logon && !NoLogOpt()) {
      char *mac = gSystem->Which(TROOT::GetMacroPath(), logon, kReadPermission);
      if (mac)
         ProcessFile(logon);
      delete [] mac;
   }

   // Save current interpreter context
   gInterpreter->SaveContext();
   gInterpreter->SaveGlobalsContext();

   // Install interrupt and terminal input handlers
   TInterruptHandler *ih = new TInterruptHandler();
   ih->Add();
   SetSignalHandler(ih);

   // Handle stdin events
   fInputHandler = new TTermInputHandler(0);
   fInputHandler->Add();

   // Goto into raw terminal input mode
   char defhist[128];
#ifndef R__VMS
   sprintf(defhist, "%s/.root_hist", gSystem->Getenv("HOME"));
#else
   sprintf(defhist, "%s.root_hist", gSystem->Getenv("HOME"));
#endif
   logon = gEnv->GetValue("Rint.History", defhist);
   Gl_histinit((char *)logon);
   Gl_windowchanged();

   // Setup for tab completion
   gTabCom = new TTabCom;
   Gl_in_key = &key_pressed;
}

//______________________________________________________________________________
TRint::~TRint()
{

}

//______________________________________________________________________________
void TRint::Run(Bool_t retrn)
{
   // Main application eventloop. First process files given on the command
   // line and then go into the main application event loop, unless the -q
   // command line option was specfied in which case the program terminates.
   // When retrun is true this method returns even when -q was specified.
   //
   // When QuitOpt is true and retrn is false, terminate the application with
   // an error code equal to either the ProcessLine error (if any) or the
   // return value of the command casted to a long.

   Getlinem(kInit, GetPrompt());

   Long_t retval = 0;
   Int_t  error = 0;

   // Process shell command line input files
   if (InputFiles()) {
      Bool_t needGetlinemInit = kFALSE;
      TIter next(InputFiles());
      RETRY {
         retval = 0; error = 0;
         Int_t nfile = 0;
         TObjString *file;
         while ((file = (TObjString *)next())) {
            char cmd[256];
            if (!fNcmd)
               printf("\n");
            if (file->String().EndsWith(".root")) {
               const char *rfile = (const char*)file->String();
               Printf("Attaching file %s as _file%d...", rfile, nfile);
               sprintf(cmd, "TFile *_file%d = TFile::Open(\"%s\")", nfile++, rfile);
            } else {
               Printf("Processing %s...", (const char*)file->String());
               sprintf(cmd, ".x %s", (const char*)file->String());
            }
            Getlinem(kCleanUp, 0);
            Gl_histadd(cmd);
            fNcmd++;

            // The ProcessLine might throw an 'exception'.  In this case,
            // GetLinem(kInit,"Root >") is called and we are jump back
            // to RETRY ... and we have to avoid the Getlinem(kInit, GetPrompt());
            needGetlinemInit = kFALSE;
            retval = ProcessLine(cmd, kFALSE, &error);
	    gInterpreter->EndOfLineAction();

            // The ProcessLine has successfully completed and we need
            // to call Getlinem(kInit, GetPrompt());
            needGetlinemInit = kTRUE;

            if (error != 0) break;
         }
      } ENDTRY;

      if (QuitOpt()) {
         if (retrn) return;
         Terminate(error == 0 ? retval : error);
      }

      ClearInputFiles();

      if (needGetlinemInit) Getlinem(kInit, GetPrompt());
   }

   if (QuitOpt()) {
      printf("\n");
      if (retrn) return;
      Terminate(0);
   }

   TApplication::Run(retrn);

   Getlinem(kCleanUp, 0);
}

//______________________________________________________________________________
void TRint::PrintLogo()
{
   // Print the ROOT logo on standard output.

   Int_t iday,imonth,iyear;
   static const char *months[] = {"January","February","March","April","May",
                                  "June","July","August","September","October",
                                  "November","December"};
   const char *root_version = gROOT->GetVersion();
   Int_t idatqq = gROOT->GetVersionDate();
   iday   = idatqq%100;
   imonth = (idatqq/100)%100;
   iyear  = (idatqq/10000);
   char *root_date = Form("%d %s %4d",iday,months[imonth-1],iyear);

   Printf("  *******************************************");
   Printf("  *                                         *");
   Printf("  *        W E L C O M E  to  R O O T       *");
   Printf("  *                                         *");
   Printf("  *   Version%10s %17s   *", root_version, root_date);
// Printf("  *            Development version          *");
   Printf("  *                                         *");
   Printf("  *  You are welcome to visit our Web site  *");
   Printf("  *          http://root.cern.ch            *");
   Printf("  *                                         *");
   Printf("  *******************************************");

   if (strstr(gVirtualX->GetName(), "TTF")) {
      Int_t major, minor, patch;
      //TTF::Version(major, minor, patch);
      // avoid dependency on libGraf and hard code, will not change too often
      major = 2; minor = 1; patch = 3;
      Printf("\nFreeType Engine v%d.%d.%d used to render TrueType fonts.",
             major, minor, patch);
   }
#ifdef _REENTRANT
   else
      printf("\n");
   Printf("Compiled for %s with thread support.", gSystem->GetBuildArch());
#else
   else
      printf("\n");
   Printf("Compiled for %s.", gSystem->GetBuildArch());
#endif

   gInterpreter->PrintIntro();

#ifdef R__UNIX
   // Popdown X logo, only if started with -splash option
   for (int i = 0; i < Argc(); i++)
      if (!strcmp(Argv(i), "-splash"))
         kill(getppid(), SIGUSR1);
#endif
}

//______________________________________________________________________________
char *TRint::GetPrompt()
{
   // Get prompt from interpreter. Either "root [n]" or "end with '}'".

   char *s = gInterpreter->GetPrompt();
   if (s[0])
      strcpy(fPrompt, s);
   else
      sprintf(fPrompt, fDefaultPrompt.Data(), fNcmd);

   return fPrompt;
}

//______________________________________________________________________________
const char *TRint::SetPrompt(const char *newPrompt)
{
   // Set a new default prompt. It returns the previous prompt.
   // The prompt may contain a %d which will be replaced by the commend
   // number. The default prompt is "root [%d] ". The maximum length of
   // the prompt is 55 characters. To set the prompt in an interactive
   // session do:
   // root [0] ((TRint*)gROOT->GetApplication())->SetPrompt("aap> ")
   // aap>

   static TString op = fDefaultPrompt;

   if (newPrompt && strlen(newPrompt) <= 55)
      fDefaultPrompt = newPrompt;
   else
      Error("SetPrompt", "newPrompt too long (> 55 characters)");

   return op.Data();
}

//______________________________________________________________________________
Bool_t TRint::HandleTermInput()
{
   // Handle input coming from terminal.

   static TStopwatch timer;
   char *line;

   if ((line = Getlinem(kOneChar, 0))) {
      if (line[0] == 0 && Gl_eof())
         Terminate(0);

      gVirtualX->SetKeyAutoRepeat(kTRUE);

      Gl_histadd(line);

      TString sline = line;
      line[0] = 0;

      // strip off '\n' and leading and trailing blanks
      sline = sline.Chop();
      sline = sline.Strip(TString::kBoth);
      ReturnPressed((char*)sline.Data());

      fInterrupt = kFALSE;

      if (!gInterpreter->GetMore() && !sline.IsNull()) fNcmd++;

      // prevent recursive calling of this input handler
      fInputHandler->DeActivate();

      if (gROOT->Timer()) timer.Start();

      Bool_t added = kFALSE;
#ifdef R__EH
      try {
#endif
         TRY {
            ProcessLine(sline);
         } CATCH(excode) {
            // enable again input handler
            fInputHandler->Activate();
            added = kTRUE;
            Throw(excode);
         } ENDTRY;
#ifdef R__EH
      }
      // handle every exception
      catch (...) {
         // enable again intput handler
         if (!added) fInputHandler->Activate();
         throw;
      }
#endif

      if (gROOT->Timer()) timer.Print("u");

      // enable again intput handler
      fInputHandler->Activate();

      if (!sline.BeginsWith(".reset"))
         gInterpreter->EndOfLineAction();

      gTabCom->ClearAll();
      Getlinem(kInit, GetPrompt());
   }
   return kTRUE;
}

//______________________________________________________________________________
void TRint::Terminate(Int_t status)
{
   // Terminate the application. Reset the terminal to sane mode and call
   // the logoff macro defined via Rint.Logoff environment variable.

   Getlinem(kCleanUp, 0);

   if (ReturnFromRun()) {
      gSystem->ExitLoop();
   } else {
      //Execute logoff macro
      const char *logoff;
      logoff = gEnv->GetValue("Rint.Logoff", (char*)0);
      if (logoff && !NoLogOpt()) {
         char *mac = gSystem->Which(TROOT::GetMacroPath(), logoff, kReadPermission);
         if (mac)
            ProcessFile(logoff);
         delete [] mac;
      }

      gSystem->Exit(status);
   }
}

//______________________________________________________________________________
void TRint::SetEchoMode(Bool_t mode)
{
   // Set console mode:
   //
   //  mode = kTRUE  - echo input symbols
   //  mode = kFALSE - noecho input symbols

   Gl_config("noecho", mode ? 0 : 1);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 *
 */

#include "net.hh"
#include <utility>

using std::move;

namespace net {

l3_protocol::l3_protocol(interface* netif, eth_protocol_num proto_num)
    : _netif(netif), _proto_num(proto_num) {
}

subscription<packet, ethernet_address> l3_protocol::receive(
        std::function<future<> (packet p, ethernet_address from)> rx_fn,
        std::function<unsigned (packet&, size_t)> forward) {
    return _netif->register_l3(_proto_num, std::move(rx_fn), std::move(forward));
};

future<> l3_protocol::send(ethernet_address to, packet p) {
    return _netif->send(_proto_num, to, std::move(p));
}

interface::interface(std::shared_ptr<device> dev)
    : _dev(dev)
    , _rx(_dev->receive([this] (packet p) { return dispatch_packet(std::move(p)); }))
    , _hw_address(_dev->hw_address())
    , _hw_features(_dev->hw_features()) {
}

subscription<packet, ethernet_address>
interface::register_l3(eth_protocol_num proto_num,
        std::function<future<> (packet p, ethernet_address from)> next,
        std::function<unsigned (packet&, size_t)> forward) {
    auto i = _proto_map.emplace(std::piecewise_construct, std::make_tuple(uint16_t(proto_num)), std::forward_as_tuple(std::move(forward)));
    assert(i.second);
    l3_rx_stream& l3_rx = i.first->second;
    return l3_rx.packet_stream.listen(std::move(next));
}

void interface::forward(unsigned cpuid, packet p) {
    static __thread unsigned queue_depth;

    if (queue_depth < 1000) {
        queue_depth++;
        auto src_cpu = engine.cpu_id();
        smp::submit_to(cpuid, [this, p = std::move(p), src_cpu]() mutable {
            _dev->l2receive(p.free_on_cpu(src_cpu));
        }).then([] {
            queue_depth--;
        });
    }
}

future<> interface::dispatch_packet(packet p) {
    auto eh = p.get_header<eth_hdr>();
    if (eh) {
        auto i = _proto_map.find(ntoh(eh->eth_proto));
        if (i != _proto_map.end()) {
            l3_rx_stream& l3 = i->second;
            auto fw = _dev->local_queue().may_forward() ? l3.forward(p, sizeof(eth_hdr)) : engine.cpu_id();
            if (fw != engine.cpu_id() && fw < smp::count) {
                forward(fw, std::move(p));
            } else {
                if (fw != engine.cpu_id()) { // broadcast to all cpus
                    for (unsigned i = 0; i< smp::count; i++) {
                        if (i != engine.cpu_id()) {
                            forward(i, p.share());
                        }
                    }
                }
                auto h = ntoh(*eh);
                auto from = h.src_mac;
                p.trim_front(sizeof(*eh));
                // avoid chaining, since queue lenth is unlimited
                // drop instead.
                if (l3.ready.available()) {
                    l3.ready = l3.packet_stream.produce(std::move(p), from);
                }
            }
        }
    }
    return make_ready_future<>();
}

future<> interface::send(eth_protocol_num proto_num, ethernet_address to, packet p) {
    auto eh = p.prepend_header<eth_hdr>();
    eh->dst_mac = to;
    eh->src_mac = _hw_address;
    eh->eth_proto = uint16_t(proto_num);
    *eh = hton(*eh);
    return _dev->local_queue().send(std::move(p));
}

}
<commit_msg>net: remove broadcast logic from forwarding path<commit_after>/*
 * Copyright (C) 2014 Cloudius Systems, Ltd.
 *
 */

#include "net.hh"
#include <utility>

using std::move;

namespace net {

l3_protocol::l3_protocol(interface* netif, eth_protocol_num proto_num)
    : _netif(netif), _proto_num(proto_num) {
}

subscription<packet, ethernet_address> l3_protocol::receive(
        std::function<future<> (packet p, ethernet_address from)> rx_fn,
        std::function<unsigned (packet&, size_t)> forward) {
    return _netif->register_l3(_proto_num, std::move(rx_fn), std::move(forward));
};

future<> l3_protocol::send(ethernet_address to, packet p) {
    return _netif->send(_proto_num, to, std::move(p));
}

interface::interface(std::shared_ptr<device> dev)
    : _dev(dev)
    , _rx(_dev->receive([this] (packet p) { return dispatch_packet(std::move(p)); }))
    , _hw_address(_dev->hw_address())
    , _hw_features(_dev->hw_features()) {
}

subscription<packet, ethernet_address>
interface::register_l3(eth_protocol_num proto_num,
        std::function<future<> (packet p, ethernet_address from)> next,
        std::function<unsigned (packet&, size_t)> forward) {
    auto i = _proto_map.emplace(std::piecewise_construct, std::make_tuple(uint16_t(proto_num)), std::forward_as_tuple(std::move(forward)));
    assert(i.second);
    l3_rx_stream& l3_rx = i.first->second;
    return l3_rx.packet_stream.listen(std::move(next));
}

void interface::forward(unsigned cpuid, packet p) {
    static __thread unsigned queue_depth;

    if (queue_depth < 1000) {
        queue_depth++;
        auto src_cpu = engine.cpu_id();
        smp::submit_to(cpuid, [this, p = std::move(p), src_cpu]() mutable {
            _dev->l2receive(p.free_on_cpu(src_cpu));
        }).then([] {
            queue_depth--;
        });
    }
}

future<> interface::dispatch_packet(packet p) {
    auto eh = p.get_header<eth_hdr>();
    if (eh) {
        auto i = _proto_map.find(ntoh(eh->eth_proto));
        if (i != _proto_map.end()) {
            l3_rx_stream& l3 = i->second;
            auto fw = _dev->local_queue().may_forward() ? l3.forward(p, sizeof(eth_hdr)) : engine.cpu_id();
            if (fw != engine.cpu_id()) {
                forward(fw, std::move(p));
            } else {
                auto h = ntoh(*eh);
                auto from = h.src_mac;
                p.trim_front(sizeof(*eh));
                // avoid chaining, since queue lenth is unlimited
                // drop instead.
                if (l3.ready.available()) {
                    l3.ready = l3.packet_stream.produce(std::move(p), from);
                }
            }
        }
    }
    return make_ready_future<>();
}

future<> interface::send(eth_protocol_num proto_num, ethernet_address to, packet p) {
    auto eh = p.prepend_header<eth_hdr>();
    eh->dst_mac = to;
    eh->src_mac = _hw_address;
    eh->eth_proto = uint16_t(proto_num);
    *eh = hton(*eh);
    return _dev->local_queue().send(std::move(p));
}

}
<|endoftext|>


<commit_before>#include "test/test_syscoin_services.h"
#include "data/utxo.json.h"
#include "utiltime.h"
#include "rpcserver.h"
#include <boost/test/unit_test.hpp>
#include <univalue.h>

extern UniValue read_json(const std::string& jsondata);
BOOST_FIXTURE_TEST_SUITE (syscoin_snapshot_tests, SyscoinMainNetSetup)
struct PaymentAmount
{
	std::string address;
	std::string amount;
};
void VerifySnapShot()
{
}
void GenerateSnapShot()
{
}
void GetUTXOs(std::vector<PaymentAmount> &paymentAmounts)
{
    UniValue tests = read_json(std::string(json_tests::utxo, json_tests::utxo + sizeof(json_tests::utxo)));
    for (unsigned int idx = 0; idx < tests.size(); idx++) {
        UniValue test = tests[idx];
        std::string strTest = test.write();
        if (test.size() < 2) // Allow for extra stuff (useful for comments)
        {
            BOOST_ERROR("Bad test: " << strTest);
            continue;
        }
		PaymentAmount payment;
        payment.address  = test[0].get_str();
        payment.amount = ValueFromAmount(test[1].get_int64()).write();
		paymentAmounts.push_back(payment);
    }
}
bool IsMainNetAlreadyCreated()
{
	int height;
	UniValue r;
	BOOST_CHECK_NO_THROW(r = CallRPC("mainnet1", "getinfo", false));
	height = find_value(r.get_obj(), "blocks").get_int();
	return height > 0;
}
BOOST_AUTO_TEST_CASE (generate_and_verify_snapshot)
{
	std::vector<PaymentAmount> paymentAmounts;
	GetUTXOs(paymentAmounts);
	if(IsMainNetAlreadyCreated())
	{
		VerifySnapShot();
	}
	else
	{
		GenerateSnapShot();
		VerifySnapShot();
	}
}
BOOST_AUTO_TEST_SUITE_END ()<commit_msg>send snapshot payment<commit_after>#include "test/test_syscoin_services.h"
#include "data/utxo.json.h"
#include "utiltime.h"
#include "rpcserver.h"
#include <boost/test/unit_test.hpp>
#include <univalue.h>
int currentTx = 0;
extern UniValue read_json(const std::string& jsondata);
BOOST_FIXTURE_TEST_SUITE (syscoin_snapshot_tests, SyscoinMainNetSetup)
struct PaymentAmount
{
	std::string address;
	std::string amount;
};
void VerifySnapShot()
{
}
void SendSnapShotPayment(const std::string &strSend)
{
	currentTx++;
	std::string strSendMany = "sendmany \"\" " + strSend + "}";
	std::
	UniValue r;
	printf("strSendMany #%d: %s\n", currentTx, strSendMany);
	BOOST_CHECK_NO_THROW(r = CallRPC("mainnet1", strSendMany, false));
}
void GenerateSnapShot(const std::vector<PaymentAmount> &paymentAmounts)
{
	int numberOfTxPerBlock = 1000;
	std::string sendManyString = "";
	for(int i =0;i<paymentAmounts.size();i++)
	{
		if(sendManyString != "")
			sendManyString += ","
		sendManyString += paymentAmounts[i].address + "," + paymentAmounts[i].amount;
		if((i%numberOfTxPerBlock) == 0)
		{
			sendManyString = "";
			SendSnapShotPayment(sendManyString);
			GenerateMainNetBlocks(1, "mainnet1");
		}
	}
	if(sendManyString != "")
	{
		SendSnapShotPayment(sendManyString);
		GenerateMainNetBlocks(1, "mainnet1");
	}

}
void GetUTXOs(std::vector<PaymentAmount> &paymentAmounts)
{
    UniValue tests = read_json(std::string(json_tests::utxo, json_tests::utxo + sizeof(json_tests::utxo)));
    for (unsigned int idx = 0; idx < tests.size(); idx++) {
        UniValue test = tests[idx];
        std::string strTest = test.write();
        if (test.size() < 2) // Allow for extra stuff (useful for comments)
        {
            BOOST_ERROR("Bad test: " << strTest);
            continue;
        }
		PaymentAmount payment;
        payment.address  = test[0].get_str();
        payment.amount = ValueFromAmount(test[1].get_int64()).write();
		paymentAmounts.push_back(payment);
    }
}
bool IsMainNetAlreadyCreated()
{
	int height;
	UniValue r;
	BOOST_CHECK_NO_THROW(r = CallRPC("mainnet1", "getinfo", false));
	height = find_value(r.get_obj(), "blocks").get_int();
	return height > 0;
}
BOOST_AUTO_TEST_CASE (generate_and_verify_snapshot)
{
	std::vector<PaymentAmount> paymentAmounts;
	GetUTXOs(paymentAmounts);
	if(IsMainNetAlreadyCreated())
	{
		VerifySnapShot();
	}
	else
	{
		GenerateSnapShot();
		VerifySnapShot();
	}
}
BOOST_AUTO_TEST_SUITE_END ()<|endoftext|>


<commit_before>#include <cstdlib>
#include <chrono>
#include <thread>
#include <unistd.h>
#include <vector>

#include "quicklook.hh"

// ----------------------------------------------------------------------

#ifdef __APPLE__

void acmacs::quicklook(std::string_view aFilename, size_t aDelayInSeconds)
{
    run_and_detach({"/usr/bin/qlmanage", "-p", aFilename.data()}, 0);
    if (aDelayInSeconds) {
        using namespace std::chrono_literals;
        std::this_thread::sleep_for(1s * aDelayInSeconds);
    }

} // acmacs::quicklook

void acmacs::open(std::string_view aFilename, size_t aDelayBeforeInSeconds, size_t aDelayAfterInSeconds)
{
    run_and_detach({"/usr/bin/open", aFilename.data()}, aDelayBeforeInSeconds);
    if (aDelayAfterInSeconds) {
        using namespace std::chrono_literals;
        std::this_thread::sleep_for(1s * aDelayAfterInSeconds);
    }

} // acmacs::quicklook

#else

void acmacs::quicklook(std::string_view /*aFilename*/, size_t /*aDelayInSeconds*/)
{
}

void acmacs::open(std::string_view /*aFilename*/, size_t /*aDelayBeforeInSeconds*/, size_t /*aDelayAfterInSeconds*/)
{
}

#endif

// ----------------------------------------------------------------------

void acmacs::run_and_detach(std::initializer_list<const char *> argv, size_t aDelayBeforeInSeconds)
{
    if (!fork()) {
        close(0);
        close(1);
        close(2);
        setsid();
        if (aDelayBeforeInSeconds) {
            using namespace std::chrono_literals;
            std::this_thread::sleep_for(1s * aDelayBeforeInSeconds);
        }
        std::vector<const char *> argv_v{argv};
        argv_v.push_back(nullptr);
        execvp(argv_v[0], const_cast<char *const *>(argv_v.data()));
        perror(argv_v[0]);
        std::exit(-1);
    }

} // acmacs::run_and_detach

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>open image in background<commit_after>#include <cstdlib>
#include <chrono>
#include <thread>
#include <unistd.h>
#include <vector>

#include "quicklook.hh"

// ----------------------------------------------------------------------

#ifdef __APPLE__

void acmacs::quicklook(std::string_view aFilename, size_t aDelayInSeconds)
{
    run_and_detach({"/usr/bin/qlmanage", "-p", aFilename.data()}, 0);
    if (aDelayInSeconds) {
        using namespace std::chrono_literals;
        std::this_thread::sleep_for(1s * aDelayInSeconds);
    }

} // acmacs::quicklook

void acmacs::open(std::string_view aFilename, size_t aDelayBeforeInSeconds, size_t aDelayAfterInSeconds)
{
    run_and_detach({"/usr/bin/open", "-g", aFilename.data()}, aDelayBeforeInSeconds);
    if (aDelayAfterInSeconds) {
        using namespace std::chrono_literals;
        std::this_thread::sleep_for(1s * aDelayAfterInSeconds);
    }

} // acmacs::quicklook

#else

void acmacs::quicklook(std::string_view /*aFilename*/, size_t /*aDelayInSeconds*/)
{
}

void acmacs::open(std::string_view /*aFilename*/, size_t /*aDelayBeforeInSeconds*/, size_t /*aDelayAfterInSeconds*/)
{
}

#endif

// ----------------------------------------------------------------------

void acmacs::run_and_detach(std::initializer_list<const char *> argv, size_t aDelayBeforeInSeconds)
{
    if (!fork()) {
        close(0);
        close(1);
        close(2);
        setsid();
        if (aDelayBeforeInSeconds) {
            using namespace std::chrono_literals;
            std::this_thread::sleep_for(1s * aDelayBeforeInSeconds);
        }
        std::vector<const char *> argv_v{argv};
        argv_v.push_back(nullptr);
        execvp(argv_v[0], const_cast<char *const *>(argv_v.data()));
        perror(argv_v[0]);
        std::exit(-1);
    }

} // acmacs::run_and_detach

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>


<commit_before>#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <sys/types.h>
#include <sys/mman.h>

#include "acmacs-base/xz.hh"
#include "acmacs-base/bzip2.hh"
#include "acmacs-base/string.hh"
#include "acmacs-base/read-file.hh"

// ----------------------------------------------------------------------

acmacs::file::read_access::read_access(std::string aFilename)
{
    if (fs::exists(aFilename)) {
        len = fs::file_size(aFilename);
        fd = ::open(aFilename.c_str(), O_RDONLY);
        if (fd >= 0) {
            mapped = reinterpret_cast<char*>(mmap(nullptr, len, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0));
            if (mapped == MAP_FAILED)
                throw cannot_read(aFilename + ": " + strerror(errno));
        }
        else {
            throw not_opened(aFilename + ": " + strerror(errno));
        }
    }
    else {
        throw not_found{aFilename};
    }

} // acmacs::file::read_access

// ----------------------------------------------------------------------

acmacs::file::read_access::read_access(read_access&& other)
    : fd{other.fd}, len{other.len}, mapped{other.mapped}
{
    other.fd = -1;
    other.len = 0;
    other.mapped = nullptr;

} // acmacs::file::read_access::read_access

// ----------------------------------------------------------------------

acmacs::file::read_access::~read_access()
{
    if (fd >= 0) {
        if (mapped)
            munmap(mapped, len);
        close(fd);
    }

} // acmacs::file::read_access::~read_access

// ----------------------------------------------------------------------

acmacs::file::read_access& acmacs::file::read_access::operator=(read_access&& other)
{
    fd = other.fd;
    len = other.len;
    mapped = other.mapped;

    other.fd = -1;
    other.len = 0;
    other.mapped = nullptr;

    return *this;

} // acmacs::file::read_access::operator=

// ----------------------------------------------------------------------

std::string acmacs::file::decompress_if_necessary(std::string_view aSource)
{
    if (xz_compressed(aSource.data()))
        return xz_decompress(aSource);
    else if (bz2_compressed(aSource.data()))
        return bz2_decompress(aSource);
    else
        return std::string(aSource);

} // acmacs::file::decompress_if_necessary

// ----------------------------------------------------------------------

std::string acmacs::file::read_from_file_descriptor(int fd, size_t chunk_size)
{
    std::string buffer;
    std::string::size_type offset = 0;
    for (;;) {
        buffer.resize(buffer.size() + chunk_size, ' ');
        const auto bytes_read = ::read(fd, (&*buffer.begin()) + offset, chunk_size);
        if (bytes_read < 0)
            throw std::runtime_error(std::string("Cannot read from file descriptor: ") + strerror(errno));
        if (static_cast<size_t>(bytes_read) < chunk_size) {
            buffer.resize(buffer.size() - chunk_size + static_cast<size_t>(bytes_read));
            break;
        }
        offset += static_cast<size_t>(bytes_read);
    }
    return decompress_if_necessary(std::string_view(buffer));

} // acmacs::file::read_from_file_descriptor

// ----------------------------------------------------------------------

void acmacs::file::backup(std::string aFilename)
{
    fs::path to_backup{aFilename};
    if (fs::exists(to_backup)) {
        fs::path backup_dir = to_backup.parent_path() / ".backup";
        create_directory(backup_dir);

        for (int version = 1; version < 1000; ++version) {
            char infix[10];
            std::sprintf(infix, ".~%03d~", version);
            fs::path new_name = backup_dir / (to_backup.stem().string() + infix + to_backup.extension().string());
            if (!fs::exists(new_name) || version == 999) {
                fs::copy_file(to_backup, new_name, fs::copy_options::overwrite_existing);
                break;
            }
        }
    }

} // acmacs::file::backup

// ----------------------------------------------------------------------

void acmacs::file::write(std::string aFilename, std::string_view aData, ForceCompression aForceCompression, BackupFile aBackupFile)
{
    int f = -1;
    if (aFilename == "-") {
        f = 1;
    }
    else if (aFilename == "=") {
        f = 2;
    }
    else {
        if (aBackupFile == BackupFile::Yes)
            backup(aFilename);
        f = open(aFilename.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0644);
        if (f < 0)
            throw std::runtime_error(std::string("Cannot open ") + aFilename + ": " + strerror(errno));
    }
    try {
        if (aForceCompression == ForceCompression::Yes || (aFilename.size() > 3 && string::ends_with(aFilename, ".xz"))) {
            const auto compressed = xz_compress(aData);
            if (::write(f, compressed.data(), compressed.size()) < 0)
                throw std::runtime_error(std::string("Cannot write ") + aFilename + ": " + strerror(errno));
        }
        else {
            if (::write(f, aData.data(), aData.size()) < 0)
                throw std::runtime_error(std::string("Cannot write ") + aFilename + ": " + strerror(errno));
        }
        if (f > 2)
            close(f);
    }
    catch (std::exception&) {
        if (f > 2)
            close(f);
        throw;
    }

} // acmacs::file::write

// ----------------------------------------------------------------------

acmacs::file::temp::temp(std::string suffix)
    : name(make_template() + suffix), fd(mkstemps(const_cast<char*>(name.c_str()), static_cast<int>(suffix.size())))
{
    if (fd < 0)
        throw std::runtime_error(std::string("Cannot create temporary file using template ") + name + ": " + strerror(errno));

} // acmacs::file::temp::temp

// ----------------------------------------------------------------------

acmacs::file::temp::~temp()
{
    if (!name.empty())
        fs::remove(name.c_str());

} // acmacs::file::temp::~temp

// ----------------------------------------------------------------------

std::string acmacs::file::temp::make_template()
{
    const char* tdir = std::getenv("T");
    if (!tdir)
        tdir = std::getenv("TMPDIR");
    if (!tdir)
        tdir = "/tmp";
    return tdir + std::string{"/AD.XXXXXXXX"};

} // acmacs::file::temp::make_template

// ----------------------------------------------------------------------

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<commit_msg>bug fix<commit_after>#include <iostream>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <sys/types.h>
#include <sys/mman.h>

#include "acmacs-base/xz.hh"
#include "acmacs-base/bzip2.hh"
#include "acmacs-base/string.hh"
#include "acmacs-base/read-file.hh"

// ----------------------------------------------------------------------

acmacs::file::read_access::read_access(std::string aFilename)
{
    if (fs::exists(aFilename)) {
        len = fs::file_size(aFilename);
        fd = ::open(aFilename.c_str(), O_RDONLY);
        if (fd >= 0) {
            mapped = reinterpret_cast<char*>(mmap(nullptr, len, PROT_READ, MAP_FILE|MAP_PRIVATE, fd, 0));
            if (mapped == MAP_FAILED)
                throw cannot_read(aFilename + ": " + strerror(errno));
        }
        else {
            throw not_opened(aFilename + ": " + strerror(errno));
        }
    }
    else {
        throw not_found{aFilename};
    }

} // acmacs::file::read_access

// ----------------------------------------------------------------------

acmacs::file::read_access::read_access(read_access&& other)
    : fd{other.fd}, len{other.len}, mapped{other.mapped}
{
    other.fd = -1;
    other.len = 0;
    other.mapped = nullptr;

} // acmacs::file::read_access::read_access

// ----------------------------------------------------------------------

acmacs::file::read_access::~read_access()
{
    if (fd >= 0) {
        if (mapped)
            munmap(mapped, len);
        close(fd);
    }

} // acmacs::file::read_access::~read_access

// ----------------------------------------------------------------------

acmacs::file::read_access& acmacs::file::read_access::operator=(read_access&& other)
{
    fd = other.fd;
    len = other.len;
    mapped = other.mapped;

    other.fd = -1;
    other.len = 0;
    other.mapped = nullptr;

    return *this;

} // acmacs::file::read_access::operator=

// ----------------------------------------------------------------------

std::string acmacs::file::decompress_if_necessary(std::string_view aSource)
{
    if (xz_compressed(aSource.data()))
        return xz_decompress(aSource);
    else if (bz2_compressed(aSource.data()))
        return bz2_decompress(aSource);
    else
        return std::string(aSource);

} // acmacs::file::decompress_if_necessary

// ----------------------------------------------------------------------

std::string acmacs::file::read_from_file_descriptor(int fd, size_t chunk_size)
{
    std::string buffer;
    std::string::size_type offset = 0;
    for (;;) {
        buffer.resize(buffer.size() + chunk_size, ' ');
        const auto bytes_read = ::read(fd, (&*buffer.begin()) + offset, chunk_size);
        if (bytes_read < 0)
            throw std::runtime_error(std::string("Cannot read from file descriptor: ") + strerror(errno));
        if (static_cast<size_t>(bytes_read) < chunk_size) {
            buffer.resize(buffer.size() - chunk_size + static_cast<size_t>(bytes_read));
            break;
        }
        offset += static_cast<size_t>(bytes_read);
    }
    return decompress_if_necessary(std::string_view(buffer));

} // acmacs::file::read_from_file_descriptor

// ----------------------------------------------------------------------

void acmacs::file::backup(std::string aFilename)
{
    fs::path to_backup{aFilename};
    if (fs::exists(to_backup)) {
        fs::path backup_dir = to_backup.parent_path() / ".backup";
        create_directory(backup_dir);

        for (int version = 1; version < 1000; ++version) {
            char infix[10];
            std::sprintf(infix, ".~%03d~", version);
            fs::path new_name = backup_dir / (to_backup.stem().string() + infix + to_backup.extension().string());
            if (!fs::exists(new_name) || version == 999) {
                fs::copy_file(to_backup, new_name, fs::copy_options::overwrite_existing);
                break;
            }
        }
    }

} // acmacs::file::backup

// ----------------------------------------------------------------------

void acmacs::file::write(std::string aFilename, std::string_view aData, ForceCompression aForceCompression, BackupFile aBackupFile)
{
    int f = -1;
    if (aFilename == "-") {
        f = 1;
    }
    else if (aFilename == "=") {
        f = 2;
    }
    else {
        if (aBackupFile == BackupFile::Yes)
            backup(aFilename);
        f = open(aFilename.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0644);
        if (f < 0)
            throw std::runtime_error(std::string("Cannot open ") + aFilename + ": " + strerror(errno));
    }
    try {
        if (aForceCompression == ForceCompression::Yes || (aFilename.size() > 3 && string::ends_with(aFilename, ".xz"))) {
            const auto compressed = xz_compress(aData);
            if (::write(f, compressed.data(), compressed.size()) < 0)
                throw std::runtime_error(std::string("Cannot write ") + aFilename + ": " + strerror(errno));
        }
        else {
            if (::write(f, aData.data(), aData.size()) < 0)
                throw std::runtime_error(std::string("Cannot write ") + aFilename + ": " + strerror(errno));
        }
        if (f > 2)
            close(f);
    }
    catch (std::exception&) {
        if (f > 2)
            close(f);
        throw;
    }

} // acmacs::file::write

// ----------------------------------------------------------------------

acmacs::file::temp::temp(std::string suffix)
    : name(make_template() + suffix), fd(mkstemps(const_cast<char*>(name.c_str()), static_cast<int>(suffix.size())))
{
    if (fd < 0)
        throw std::runtime_error(std::string("Cannot create temporary file using template ") + name + ": " + strerror(errno));

} // acmacs::file::temp::temp

// ----------------------------------------------------------------------

acmacs::file::temp::~temp()
{
    if (!name.empty())
        fs::remove(name.c_str());

} // acmacs::file::temp::~temp

// ----------------------------------------------------------------------

std::string acmacs::file::temp::make_template()
{
    const char* tdir = std::getenv("T");
    if (!tdir || *tdir != '/')
        tdir = std::getenv("TMPDIR");
    if (!tdir)
        tdir = "/tmp";
    return tdir + std::string{"/AD.XXXXXXXX"};

} // acmacs::file::temp::make_template

// ----------------------------------------------------------------------

// ----------------------------------------------------------------------
/// Local Variables:
/// eval: (if (fboundp 'eu-rename-buffer) (eu-rename-buffer))
/// End:
<|endoftext|>


<commit_before>#include <iostream>
using namespace std;

int main(void) {
	cout<<"hello, world!"<<endl;
	return 0;
}<commit_msg>remove POJCoding.cpp<commit_after><|endoftext|>


<commit_before>#include <stddef.h>
#include <stdlib.h>
#include <new>
#include <string>
#include <locale>
#include <stdio.h>
#include <iostream>
#include "novoht.h"

NoVoHT::NoVoHT(){
   kvpairs = new kvpair*[1000];
   size = 1000;
   numEl = 0;
   magicNumber = 1000;
   resizeNum = -1;
   resizing = false;
   oldpairs = NULL;
}

/*
NoVoHT::NoVoHT(int s){
   kvpairs = new kvpair*[s];
   size = s;
   numEl=0;
   file = NULL;
}

NoVoHT::NoVoHT(char * f){
   kvpairs = new kvpair*[1000];
   size = 1000;
   numEl=0;
   file = f;
   readFile();
}
*/
NoVoHT::NoVoHT(string f,int s, int m){
   kvpairs = new kvpair*[s];
   for (int x = 0;x<s;x++){
      kvpairs[x] = NULL;
   }
   magicNumber = m;
   nRem = 0;
   resizeNum = 0;
   size = s;
   numEl=0;
   filename=f;
   dbfile = fopen(f.c_str(), "r+");
   if (!dbfile) dbfile = fopen(f.c_str(), "w+");
   readFile();
   resizing = false;
   oldpairs = NULL;
}
NoVoHT::NoVoHT(string f,int s, int m, float r){
   kvpairs = new kvpair*[s];
   for (int x = 0;x<s;x++){
      kvpairs[x] = NULL;
   }
   magicNumber = m;
   nRem = 0;
   resizeNum = r;
   size = s;
   numEl=0;
   filename=f;
   dbfile = fopen(f.c_str(), "r+");
   if (!dbfile) dbfile = fopen(f.c_str(), "w+");
   readFile();
   resizing = false;
   oldpairs = NULL;
}
/*
NoVoHT::NoVoHT(char * f, NoVoHT *map){
   kvpairs = new kvpair*[1000];
   size = 1000;
   numEl=0;
   file = f;
   readFile();
}*/
NoVoHT::~NoVoHT(){
   if (dbfile){
      //writeFile();
      fclose(dbfile);
   }
   for (int i = 0; i < size; i++){
      fsu(kvpairs[i]);
   }
   delete [] kvpairs;
}

//0 success, -1 no insert, -2 no write
int NoVoHT::put(string k, string v){
   while(resizing){ /* Wait till done */}
   if (numEl >= size*resizeNum) {
      if (resizeNum !=0){
         printf("Resizing\n");
         resize(size*2);
      }
   }
   int slot;
   slot = hash(k)%size;
   kvpair *cur = kvpairs[slot];
   kvpair *add = new kvpair;
   add->key = k;
   add->val = v;
   add->next = NULL;
   if (cur == NULL){
      kvpairs[slot] = add;
      numEl++;
      return write(add);
   }
   while (cur->next != NULL){
      if (k.compare(cur->key) == 0) {delete add; return -1;}
      cur = cur->next;
   }
   if (k.compare(cur->key) == 0) {delete add; return -1;}
   cur->next = add;
   numEl++;
   return write(add);
}

string* NoVoHT::get(string k){
   while(resizing){ /* Wait till done */}
   int loc = hash(k)%size;
   kvpair *cur = kvpairs[loc];
   while (cur != NULL && !k.empty()){
      if (k.compare(cur->key) == 0) return &(cur->val);
      cur = cur->next;
   }
   return NULL;
}

//return 0 for success, -1 fail to remove, -2+ write failure
int NoVoHT::remove(string k){
   while(resizing){ /* Wait till done */}
   int ret =0;
   int loc = hash(k)%size;
   kvpair *cur = kvpairs[loc];
   if (cur == NULL) return ret-1;       //not found
   if (k.compare(cur->key) ==0) {
      fpos_t toRem = kvpairs[loc]->pos;
      kvpairs[loc] = cur->next;
      numEl--;
      ret+=mark(toRem);
      delete cur;
      nRem++;
      if (nRem == magicNumber) ret+=writeFile(); //write and save write success
      return ret;
   }
   while(cur != NULL){
      if (cur->next == NULL) return ret-1;
      else if (k.compare(cur->next->key)==0){
         kvpair *r = cur->next;
         cur->next = r->next;
         ret+=mark(r->pos);              //mark and sace status code
         delete r;
         numEl--;
         nRem++;
         if (nRem == magicNumber) ret+=writeFile();              //mark and sace status code
         return ret;
      }
      cur = cur->next;
   }
   return ret-1;        //not found
}

//return 0 if success -2 if failed
//write hashmap to file
int NoVoHT::writeFile(){
   int ret =0;
   if (!dbfile)return (filename.compare("") == 0 ? 0 : -2);
   rewind(dbfile);
   for (int i=0; i<size;i++){
      kvpair *cur = kvpairs[i];
      while (cur != NULL){
         if(!cur->key.empty() && !cur->val.empty()){
                fgetpos(dbfile, &(cur->pos));
                fprintf(dbfile, "%s\t%s\t", cur->key.c_str(), cur->val.c_str());
         }
         cur = cur->next;
      }
   }
   truncate(filename.c_str(), (off_t)SEEK_CUR-SEEK_SET-1);
   return ret;
}

//success 0 fail -2
//resize the hashmap's base size
void NoVoHT::resize(int ns){
   int olds = size;
   size = ns;
   oldpairs = kvpairs;
   resizing = true;
   kvpairs = new kvpair*[ns];
   for (int z=0; z<ns; z++) { kvpairs[z] = NULL;}
   numEl = 0;
   for (int i=0; i<olds;i++){
      kvpair *cur = oldpairs[i];
      while (cur != NULL){
         int pos = hash(cur->key)%size;
         kvpair * tmp = kvpairs[pos];
         kvpairs[pos] = cur;
         cur = cur->next;
         kvpairs[pos]->next = tmp;
      }
   }
   resizing = false;
   delete [] oldpairs;
}

//success 0 fail -2
//write kvpair to file
int NoVoHT::write(kvpair * p){
   if (!dbfile)return (filename.compare("") == 0 ? 0 : -2);
   fseek(dbfile, 0, SEEK_END);
   fgetpos(dbfile, &(p->pos));
   fprintf(dbfile, "%s\t%s\t", p->key.c_str(), p->val.c_str());
   return 0;
}

//success 0 fail -2
//mark line in file for deletion
int NoVoHT::mark(fpos_t position){
   if (!dbfile)return (filename.compare("") == 0 ? 0 : -2);
   fsetpos(dbfile, &position);
   fputc((int) '~', dbfile);
   return 0;
}
char *readTabString(FILE *file, char *buffer){
   int n =0;
   char t;
   while((t=fgetc(file)) != EOF){
      if (t == '\t') {
         buffer[n] = '\0';
         return buffer;
      }
      buffer[n] = t;
      n++;
   }
   buffer[n] = '\0';
   return (n == 0 ? NULL : buffer);
}

void NoVoHT::readFile(){
   if(!dbfile) return;
   char s[300];
   char v[300];
   while(readTabString(dbfile, s) != NULL){
      string key(s);
      if (readTabString(dbfile, v) == NULL) break;
      string val(v);
      if (key[0] != '~'){
         put(key,val);
      }
         cout << key << ":" << val << endl;
   }
   writeFile();
}

unsigned long long hash(string k){ //FNV hash
#if SIZE_OF_LONG_LONG_INT==8
#define FNV_PRIME 14695981039346656037
#define FNV_OFFSET 1099511628211
#else //SIZE_OF_LONG_LONG_INT == 4
#define FNV_PRIME 16777619
#define FNV_OFFSET 2166136261
#endif
   unsigned long long x = FNV_PRIME;
   for (unsigned int y=0;y<k.length();y++){
      x = x ^ (k[y]);
      x = x * FNV_OFFSET;
   }
   return (x);
}

void fsu(kvpair* p){
   if(p != NULL){
      fsu(p->next);
      delete p;
   }
}
<commit_msg>	modified:   novoht.cxx<commit_after>#include <stddef.h>
#include <stdlib.h>
#include <new>
#include <string>
#include <locale>
#include <stdio.h>
#include <iostream>
#include "novoht.h"

NoVoHT::NoVoHT(){
   kvpairs = new kvpair*[1000];
   size = 1000;
   numEl = 0;
   magicNumber = 1000;
   resizeNum = -1;
   resizing = false;
   oldpairs = NULL;
}

/*
NoVoHT::NoVoHT(int s){
   kvpairs = new kvpair*[s];
   size = s;
   numEl=0;
   file = NULL;
}

NoVoHT::NoVoHT(char * f){
   kvpairs = new kvpair*[1000];
   size = 1000;
   numEl=0;
   file = f;
   readFile();
}
*/
NoVoHT::NoVoHT(string f,int s, int m){
   kvpairs = new kvpair*[s];
   for (int x = 0;x<s;x++){
      kvpairs[x] = NULL;
   }
   resizing=false;
   magicNumber = m;
   nRem = 0;
   resizeNum = 0;
   size = s;
   numEl=0;
   filename=f;
   dbfile = fopen(f.c_str(), "r+");
   if (!dbfile) dbfile = fopen(f.c_str(), "w+");
   readFile();
   oldpairs = NULL;
}
NoVoHT::NoVoHT(string f,int s, int m, float r){
   kvpairs = new kvpair*[s];
   for (int x = 0;x<s;x++){
      kvpairs[x] = NULL;
   }
   resizing=false;
   magicNumber = m;
   nRem = 0;
   resizeNum = r;
   size = s;
   numEl=0;
   filename=f;
   dbfile = fopen(f.c_str(), "r+");
   if (!dbfile) dbfile = fopen(f.c_str(), "w+");
   readFile();
   oldpairs = NULL;
}
/*
NoVoHT::NoVoHT(char * f, NoVoHT *map){
   kvpairs = new kvpair*[1000];
   size = 1000;
   numEl=0;
   file = f;
   readFile();
}*/
NoVoHT::~NoVoHT(){
   if (dbfile){
      writeFile();
      fclose(dbfile);
   }
   for (int i = 0; i < size; i++){
      fsu(kvpairs[i]);
   }
   delete [] kvpairs;
}

//0 success, -1 no insert, -2 no write
int NoVoHT::put(string k, string v){
   while(resizing){ /* Wait till done */}
   if (numEl >= size*resizeNum) {
      if (resizeNum !=0){
         printf("Resizing\n");
         resize(size*2);
      }
   }
   int slot;
   slot = hash(k)%size;
   kvpair *cur = kvpairs[slot];
   kvpair *add = new kvpair;
   add->key = k;
   add->val = v;
   add->next = NULL;
   if (cur == NULL){
      kvpairs[slot] = add;
      numEl++;
      return write(add);
   }
   while (cur->next != NULL){
      if (k.compare(cur->key) == 0) {delete add; return -1;}
      cur = cur->next;
   }
   if (k.compare(cur->key) == 0) {delete add; return -1;}
   cur->next = add;
   numEl++;
   return write(add);
}

string* NoVoHT::get(string k){
   while(resizing){ /* Wait till done */}
   int loc = hash(k)%size;
   kvpair *cur = kvpairs[loc];
   while (cur != NULL && !k.empty()){
      if (k.compare(cur->key) == 0) return &(cur->val);
      cur = cur->next;
   }
   return NULL;
}

//return 0 for success, -1 fail to remove, -2+ write failure
int NoVoHT::remove(string k){
   while(resizing){ /* Wait till done */}
   int ret =0;
   int loc = hash(k)%size;
   kvpair *cur = kvpairs[loc];
   if (cur == NULL) return ret-1;       //not found
   if (k.compare(cur->key) ==0) {
      fpos_t toRem = kvpairs[loc]->pos;
      kvpairs[loc] = cur->next;
      numEl--;
      ret+=mark(toRem);
      delete cur;
      nRem++;
      if (nRem == magicNumber) ret+=writeFile(); //write and save write success
      return ret;
   }
   while(cur != NULL){
      if (cur->next == NULL) return ret-1;
      else if (k.compare(cur->next->key)==0){
         kvpair *r = cur->next;
         cur->next = r->next;
         ret+=mark(r->pos);              //mark and sace status code
         delete r;
         numEl--;
         nRem++;
         if (nRem == magicNumber) ret+=writeFile();              //mark and sace status code
         return ret;
      }
      cur = cur->next;
   }
   return ret-1;        //not found
}

//return 0 if success -2 if failed
//write hashmap to file
int NoVoHT::writeFile(){
   int ret =0;
   if (!dbfile)return (filename.compare("") == 0 ? 0 : -2);
   rewind(dbfile);
   for (int i=0; i<size;i++){
      kvpair *cur = kvpairs[i];
      while (cur != NULL){
         if(!cur->key.empty() && !cur->val.empty()){
                fgetpos(dbfile, &(cur->pos));
                fprintf(dbfile, "%s\t%s\t", cur->key.c_str(), cur->val.c_str());
         }
         cur = cur->next;
      }
   }
   truncate(filename.c_str(), (off_t)SEEK_CUR-SEEK_SET-1);
   return ret;
}

//success 0 fail -2
//resize the hashmap's base size
void NoVoHT::resize(int ns){
   int olds = size;
   size = ns;
   oldpairs = kvpairs;
   resizing = true;
   kvpairs = new kvpair*[ns];
   for (int z=0; z<ns; z++) { kvpairs[z] = NULL;}
   numEl = 0;
   for (int i=0; i<olds;i++){
      kvpair *cur = oldpairs[i];
      while (cur != NULL){
         int pos = hash(cur->key)%size;
         kvpair * tmp = kvpairs[pos];
         kvpairs[pos] = cur;
         cur = cur->next;
         kvpairs[pos]->next = tmp;
      }
   }
   resizing = false;
   delete [] oldpairs;
}

//success 0 fail -2
//write kvpair to file
int NoVoHT::write(kvpair * p){
   if (!dbfile)return (filename.compare("") == 0 ? 0 : -2);
   fseek(dbfile, 0, SEEK_END);
   fgetpos(dbfile, &(p->pos));
   fprintf(dbfile, "%s\t%s\t", p->key.c_str(), p->val.c_str());
   return 0;
}

//success 0 fail -2
//mark line in file for deletion
int NoVoHT::mark(fpos_t position){
   if (!dbfile)return (filename.compare("") == 0 ? 0 : -2);
   fsetpos(dbfile, &position);
   fputc((int) '~', dbfile);
   return 0;
}
char *readTabString(FILE *file, char *buffer){
   int n =0;
   char t;
   while((t=fgetc(file)) != EOF){
      if (t == '\t') {
         buffer[n] = '\0';
         return buffer;
      }
      buffer[n] = t;
      n++;
   }
   buffer[n] = '\0';
   return (n == 0 ? NULL : buffer);
}

void NoVoHT::readFile(){
   if(!dbfile) return;
   char s[300];
   char v[300];
   while(readTabString(dbfile, s) != NULL){
      string key(s);
      if (readTabString(dbfile, v) == NULL) break;
      string val(v);
      if (key[0] != '~'){
         put(key,val);
      }
   }
   writeFile();
}

unsigned long long hash(string k){ //FNV hash
#if SIZE_OF_LONG_LONG_INT==8
#define FNV_PRIME 14695981039346656037
#define FNV_OFFSET 1099511628211
#else //SIZE_OF_LONG_LONG_INT == 4
#define FNV_PRIME 16777619
#define FNV_OFFSET 2166136261
#endif
   unsigned long long x = FNV_PRIME;
   for (unsigned int y=0;y<k.length();y++){
      x = x ^ (k[y]);
      x = x * FNV_OFFSET;
   }
   return (x);
}

void fsu(kvpair* p){
   if(p != NULL){
      fsu(p->next);
      delete p;
   }
}
<|endoftext|>


<commit_before>/** @file dbfactory.cc
 * @brief Database factories for non-remote databases.
 */
/* Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2011,2012,2013,2014,2015,2016,2017,2019 Olly Betts
 * Copyright 2008 Lemur Consulting Ltd
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 * USA
 */

#include "config.h"

#include "xapian/dbfactory.h"

#include "xapian/constants.h"
#include "xapian/database.h"
#include "xapian/error.h"
#include "xapian/version.h" // For XAPIAN_HAS_XXX_BACKEND.

#include "xapian/backends/backends.h"
#include "xapian/backends/databasehelpers.h"
#include "xapian/common/debuglog.h"
#include "xapian/common/filetests.h"
#include "xapian/common/fileutils.h"
#include "xapian/common/posixy_wrapper.h"
#include "xapian/common/str.h"

#include <cerrno>
#include <cstdlib> // For atoi().

#ifdef XAPIAN_HAS_GLASS_BACKEND
# include "xapian/backends/glass/glass_database.h"
#endif
#include "xapian/backends/glass/glass_defs.h"
#ifdef XAPIAN_HAS_HONEY_BACKEND
# include "xapian/backends/honey/honey_database.h"
#endif
#include "xapian/backends/honey/honey_defs.h"
#ifdef XAPIAN_HAS_INMEMORY_BACKEND
# include "xapian/backends/inmemory/inmemory_database.h"
#endif
// Even if none of the above get included, we still need a definition of
// Database::Internal.
#include "xapian/backends/databaseinternal.h"

#include <fstream>
#include <string>

using namespace std;

namespace Xapian {

static void
open_stub(Database& db, const string& file)
{
    read_stub_file(file,
		   [&db](const string& path) {
		       db.add_database(Database(path));
		   },
		   [&db](const string& path) {
#ifdef XAPIAN_HAS_GLASS_BACKEND
		       db.add_database(Database(new GlassDatabase(path)));
#else
		       (void)path;
#endif
		   },
		   [&db](const string& path) {
#ifdef XAPIAN_HAS_HONEY_BACKEND
		       db.add_database(Database(new HoneyDatabase(path)));
#else
		       (void)path;
#endif
		   },
		   [&db](const string& prog, const string& args) {
#ifdef XAPIAN_HAS_REMOTE_BACKEND
		       db.add_database(Remote::open(prog, args));
#else
		       (void)prog;
		       (void)args;
#endif
		   },
		   [&db](const string& host, unsigned port) {
#ifdef XAPIAN_HAS_REMOTE_BACKEND
		       db.add_database(Remote::open(host, port));
#else
		       (void)host;
		       (void)port;
#endif
		   },
		   [&db]() {
#ifdef XAPIAN_HAS_INMEMORY_BACKEND
		       db.add_database(Database(string(), DB_BACKEND_INMEMORY));
#endif
		   });

    // Allowing a stub database with no databases listed allows things like
    // a "search all databases" feature to be implemented by generating a
    // stub database file without having to special case there not being any
    // databases yet.
    //
    // 1.0.x threw DatabaseOpeningError here, but with a "Bad line" message
    // with the line number just past the end of the file, which was a bit odd.
}

static void
open_stub(WritableDatabase& db, const string& file, int flags)
{
    read_stub_file(file,
		   [&db, flags](const string& path) {
		       db.add_database(WritableDatabase(path, flags));
		   },
		   [&db, &flags](const string& path) {
		       flags |= DB_BACKEND_GLASS;
		       db.add_database(WritableDatabase(path, flags));
		   },
		   [](const string&) {
		       auto msg = "Honey databases don't support writing";
		       throw Xapian::DatabaseOpeningError(msg);
		   },
		   [&db, flags](const string& prog, const string& args) {
#ifdef XAPIAN_HAS_REMOTE_BACKEND
		       db.add_database(Remote::open_writable(prog, args,
							     0, flags));
#else
		       (void)prog;
		       (void)args;
#endif
		   },
		   [&db, flags](const string& host, unsigned port) {
#ifdef XAPIAN_HAS_REMOTE_BACKEND
		       db.add_database(Remote::open_writable(host, port,
							     0, 10000, flags));
#else
		       (void)host;
		       (void)port;
#endif
		   },
		   [&db]() {
		       db.add_database(WritableDatabase(string(),
							DB_BACKEND_INMEMORY));
		   });

    if (db.internal->size() == 0) {
	throw DatabaseOpeningError(file + ": No databases listed");
    }
}

Database::Database(const string& path, int flags)
    : Database()
{
    LOGCALL_CTOR(API, "Database", path|flags);

    int type = flags & DB_BACKEND_MASK_;
    switch (type) {
	case DB_BACKEND_CHERT:
	    throw FeatureUnavailableError("Chert backend no longer supported");
	case DB_BACKEND_GLASS:
#ifdef XAPIAN_HAS_GLASS_BACKEND
	    internal = new GlassDatabase(path);
	    return;
#else
	    throw FeatureUnavailableError("Glass backend disabled");
#endif
	case DB_BACKEND_HONEY:
#ifdef XAPIAN_HAS_HONEY_BACKEND
	    internal = new HoneyDatabase(path);
	    return;
#else
	    throw FeatureUnavailableError("Honey backend disabled");
#endif
	case DB_BACKEND_STUB:
	    open_stub(*this, path);
	    return;
	case DB_BACKEND_INMEMORY:
#ifdef XAPIAN_HAS_INMEMORY_BACKEND
	    internal = new InMemoryDatabase();
	    return;
#else
	    throw FeatureUnavailableError("Inmemory backend disabled");
#endif
    }

    struct stat statbuf;
    if (stat(path.c_str(), &statbuf) == -1) {
	throw DatabaseOpeningError("Couldn't stat '" + path + "'", errno);
    }

    if (S_ISREG(statbuf.st_mode)) {
	// Could be a stub database file, or a single file glass database.

	// Initialise to avoid bogus warning from GCC 4.9.2 with -Os.
	int fd = -1;
	switch (test_if_single_file_db(statbuf, path, &fd)) {
	    case BACKEND_GLASS:
#ifdef XAPIAN_HAS_GLASS_BACKEND
		// Single file glass format.
		internal = new GlassDatabase(fd);
		return;
#else
		throw FeatureUnavailableError("Glass backend disabled");
#endif
	    case BACKEND_HONEY:
#ifdef XAPIAN_HAS_HONEY_BACKEND
		// Single file honey format.
		internal = new HoneyDatabase(fd);
		return;
#else
		throw FeatureUnavailableError("Honey backend disabled");
#endif
	}

	open_stub(*this, path);
	return;
    }

    if (rare(!S_ISDIR(statbuf.st_mode))) {
	throw DatabaseOpeningError("Not a regular file or directory: '" + path + "'");
    }

#ifdef XAPIAN_HAS_GLASS_BACKEND
    if (file_exists(path + "/iamglass")) {
	internal = new GlassDatabase(path);
	return;
    }
#endif

#ifdef XAPIAN_HAS_HONEY_BACKEND
    if (file_exists(path + "/iamhoney")) {
	internal = new HoneyDatabase(path);
	return;
    }
#endif

    // Check for "stub directories".
    string stub_file = path;
    stub_file += "/XAPIANDB";
    if (usual(file_exists(stub_file))) {
	open_stub(*this, stub_file);
	return;
    }

#ifndef XAPIAN_HAS_GLASS_BACKEND
    if (file_exists(path + "/iamglass")) {
	throw FeatureUnavailableError("Glass backend disabled");
    }
#endif
#ifndef XAPIAN_HAS_HONEY_BACKEND
    if (file_exists(path + "/iamhoney")) {
	throw FeatureUnavailableError("Honey backend disabled");
    }
#endif
    if (file_exists(path + "/iamchert")) {
	throw FeatureUnavailableError("Chert backend no longer supported");
    }
    if (file_exists(path + "/iamflint")) {
	throw FeatureUnavailableError("Flint backend no longer supported");
    }

    throw DatabaseOpeningError("Couldn't detect type of database");
}

Database::Database(int fd, int flags)
{
    LOGCALL_CTOR(API, "Database", fd|flags);

    if (rare(fd < 0))
	throw InvalidArgumentError("fd < 0");

#ifdef XAPIAN_HAS_GLASS_BACKEND
    int type = flags & DB_BACKEND_MASK_;
    switch (type) {
	case 0:
	case DB_BACKEND_GLASS:
	    internal = new GlassDatabase(fd);
    }
#else
    (void)flags;
#endif

    (void)::close(fd);
    throw DatabaseOpeningError("Couldn't detect type of database");
}

#if defined XAPIAN_HAS_GLASS_BACKEND
#define HAVE_DISK_BACKEND
#endif

WritableDatabase::WritableDatabase(const std::string &path, int flags, int block_size)
    : Database()
{
    LOGCALL_CTOR(API, "WritableDatabase", path|flags|block_size);
    // Avoid warning if all disk-based backends are disabled.
    (void)block_size;
    int type = flags & DB_BACKEND_MASK_;
    // Clear the backend bits, so we just pass on other flags to open_stub, etc.
    flags &= ~DB_BACKEND_MASK_;
    if (type == 0) {
	struct stat statbuf;
	if (stat(path.c_str(), &statbuf) == -1) {
	    // ENOENT probably just means that we need to create the directory.
	    if (errno != ENOENT)
		throw DatabaseOpeningError("Couldn't stat '" + path + "'", errno);
	} else {
	    // File or directory already exists.

	    if (S_ISREG(statbuf.st_mode)) {
		// The path is a file, so assume it is a stub database file.
		open_stub(*this, path, flags);
		return;
	    }

	    if (rare(!S_ISDIR(statbuf.st_mode))) {
		throw DatabaseOpeningError("Not a regular file or directory: '" + path + "'");
	    }

	    if (file_exists(path + "/iamglass")) {
		// Existing glass DB.
#ifdef XAPIAN_HAS_GLASS_BACKEND
		type = DB_BACKEND_GLASS;
#else
		throw FeatureUnavailableError("Glass backend disabled");
#endif
	    } else if (file_exists(path + "/iamhoney")) {
		// Existing honey DB.
		throw InvalidOperationError("Honey backend doesn't support "
					    "updating existing databases");
	    } else if (file_exists(path + "/iamchert")) {
		// Existing chert DB.
		throw FeatureUnavailableError("Chert backend no longer supported");
	    } else if (file_exists(path + "/iamflint")) {
		// Existing flint DB.
		throw FeatureUnavailableError("Flint backend no longer supported");
	    } else {
		// Check for "stub directories".
		string stub_file = path;
		stub_file += "/XAPIANDB";
		if (usual(file_exists(stub_file))) {
		    open_stub(*this, stub_file, flags);
		    return;
		}
	    }
	}
    }

    switch (type) {
	case DB_BACKEND_STUB:
	    open_stub(*this, path, flags);
	    return;
	case 0:
	    // Fall through to first enabled case, so order the remaining cases
	    // by preference.
#ifdef XAPIAN_HAS_GLASS_BACKEND
	case DB_BACKEND_GLASS:
	    internal = new GlassWritableDatabase(path, flags, block_size);
	    return;
#endif
	case DB_BACKEND_HONEY:
	    throw InvalidArgumentError("Honey backend doesn't support "
				       "updating existing databases");
	case DB_BACKEND_CHERT:
	    throw FeatureUnavailableError("Chert backend no longer supported");
	case DB_BACKEND_INMEMORY:
#ifdef XAPIAN_HAS_INMEMORY_BACKEND
	    internal = new InMemoryDatabase();
	    return;
#else
	    throw FeatureUnavailableError("Inmemory backend disabled");
#endif
    }
#ifndef HAVE_DISK_BACKEND
    throw FeatureUnavailableError("No disk-based writable backend is enabled");
#endif
}

}
<commit_msg>xapian-core: Throw DatabaseNotFoundError if directory doesn't exist<commit_after>/** @file dbfactory.cc
 * @brief Database factories for non-remote databases.
 */
/* Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2011,2012,2013,2014,2015,2016,2017,2019 Olly Betts
 * Copyright 2008 Lemur Consulting Ltd
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 * USA
 */

#include "config.h"

#include "xapian/dbfactory.h"

#include "xapian/constants.h"
#include "xapian/database.h"
#include "xapian/error.h"
#include "xapian/version.h" // For XAPIAN_HAS_XXX_BACKEND.

#include "xapian/backends/backends.h"
#include "xapian/backends/databasehelpers.h"
#include "xapian/common/debuglog.h"
#include "xapian/common/filetests.h"
#include "xapian/common/fileutils.h"
#include "xapian/common/posixy_wrapper.h"
#include "xapian/common/str.h"

#include <cerrno>
#include <cstdlib> // For atoi().

#ifdef XAPIAN_HAS_GLASS_BACKEND
# include "xapian/backends/glass/glass_database.h"
#endif
#include "xapian/backends/glass/glass_defs.h"
#ifdef XAPIAN_HAS_HONEY_BACKEND
# include "xapian/backends/honey/honey_database.h"
#endif
#include "xapian/backends/honey/honey_defs.h"
#ifdef XAPIAN_HAS_INMEMORY_BACKEND
# include "xapian/backends/inmemory/inmemory_database.h"
#endif
// Even if none of the above get included, we still need a definition of
// Database::Internal.
#include "xapian/backends/databaseinternal.h"

#include <fstream>
#include <string>

using namespace std;

namespace Xapian {

static void
open_stub(Database& db, const string& file)
{
    read_stub_file(file,
		   [&db](const string& path) {
		       db.add_database(Database(path));
		   },
		   [&db](const string& path) {
#ifdef XAPIAN_HAS_GLASS_BACKEND
		       db.add_database(Database(new GlassDatabase(path)));
#else
		       (void)path;
#endif
		   },
		   [&db](const string& path) {
#ifdef XAPIAN_HAS_HONEY_BACKEND
		       db.add_database(Database(new HoneyDatabase(path)));
#else
		       (void)path;
#endif
		   },
		   [&db](const string& prog, const string& args) {
#ifdef XAPIAN_HAS_REMOTE_BACKEND
		       db.add_database(Remote::open(prog, args));
#else
		       (void)prog;
		       (void)args;
#endif
		   },
		   [&db](const string& host, unsigned port) {
#ifdef XAPIAN_HAS_REMOTE_BACKEND
		       db.add_database(Remote::open(host, port));
#else
		       (void)host;
		       (void)port;
#endif
		   },
		   [&db]() {
#ifdef XAPIAN_HAS_INMEMORY_BACKEND
		       db.add_database(Database(string(), DB_BACKEND_INMEMORY));
#endif
		   });

    // Allowing a stub database with no databases listed allows things like
    // a "search all databases" feature to be implemented by generating a
    // stub database file without having to special case there not being any
    // databases yet.
    //
    // 1.0.x threw DatabaseOpeningError here, but with a "Bad line" message
    // with the line number just past the end of the file, which was a bit odd.
}

static void
open_stub(WritableDatabase& db, const string& file, int flags)
{
    read_stub_file(file,
		   [&db, flags](const string& path) {
		       db.add_database(WritableDatabase(path, flags));
		   },
		   [&db, &flags](const string& path) {
		       flags |= DB_BACKEND_GLASS;
		       db.add_database(WritableDatabase(path, flags));
		   },
		   [](const string&) {
		       auto msg = "Honey databases don't support writing";
		       throw Xapian::DatabaseOpeningError(msg);
		   },
		   [&db, flags](const string& prog, const string& args) {
#ifdef XAPIAN_HAS_REMOTE_BACKEND
		       db.add_database(Remote::open_writable(prog, args,
							     0, flags));
#else
		       (void)prog;
		       (void)args;
#endif
		   },
		   [&db, flags](const string& host, unsigned port) {
#ifdef XAPIAN_HAS_REMOTE_BACKEND
		       db.add_database(Remote::open_writable(host, port,
							     0, 10000, flags));
#else
		       (void)host;
		       (void)port;
#endif
		   },
		   [&db]() {
		       db.add_database(WritableDatabase(string(),
							DB_BACKEND_INMEMORY));
		   });

    if (db.internal->size() == 0) {
	throw DatabaseOpeningError(file + ": No databases listed");
    }
}

Database::Database(const string& path, int flags)
    : Database()
{
    LOGCALL_CTOR(API, "Database", path|flags);

    int type = flags & DB_BACKEND_MASK_;
    switch (type) {
	case DB_BACKEND_CHERT:
	    throw FeatureUnavailableError("Chert backend no longer supported");
	case DB_BACKEND_GLASS:
#ifdef XAPIAN_HAS_GLASS_BACKEND
	    internal = new GlassDatabase(path);
	    return;
#else
	    throw FeatureUnavailableError("Glass backend disabled");
#endif
	case DB_BACKEND_HONEY:
#ifdef XAPIAN_HAS_HONEY_BACKEND
	    internal = new HoneyDatabase(path);
	    return;
#else
	    throw FeatureUnavailableError("Honey backend disabled");
#endif
	case DB_BACKEND_STUB:
	    open_stub(*this, path);
	    return;
	case DB_BACKEND_INMEMORY:
#ifdef XAPIAN_HAS_INMEMORY_BACKEND
	    internal = new InMemoryDatabase();
	    return;
#else
	    throw FeatureUnavailableError("Inmemory backend disabled");
#endif
    }

    struct stat statbuf;
    if (stat(path.c_str(), &statbuf) == -1) {
	if (errno == ENOENT) {
	    throw DatabaseNotFoundError("Couldn't stat '" + path + "'", errno);
	} else {
	    throw DatabaseOpeningError("Couldn't stat '" + path + "'", errno);
	}
    }

    if (S_ISREG(statbuf.st_mode)) {
	// Could be a stub database file, or a single file glass database.

	// Initialise to avoid bogus warning from GCC 4.9.2 with -Os.
	int fd = -1;
	switch (test_if_single_file_db(statbuf, path, &fd)) {
	    case BACKEND_GLASS:
#ifdef XAPIAN_HAS_GLASS_BACKEND
		// Single file glass format.
		internal = new GlassDatabase(fd);
		return;
#else
		throw FeatureUnavailableError("Glass backend disabled");
#endif
	    case BACKEND_HONEY:
#ifdef XAPIAN_HAS_HONEY_BACKEND
		// Single file honey format.
		internal = new HoneyDatabase(fd);
		return;
#else
		throw FeatureUnavailableError("Honey backend disabled");
#endif
	}

	open_stub(*this, path);
	return;
    }

    if (rare(!S_ISDIR(statbuf.st_mode))) {
	throw DatabaseOpeningError("Not a regular file or directory: '" + path + "'");
    }

#ifdef XAPIAN_HAS_GLASS_BACKEND
    if (file_exists(path + "/iamglass")) {
	internal = new GlassDatabase(path);
	return;
    }
#endif

#ifdef XAPIAN_HAS_HONEY_BACKEND
    if (file_exists(path + "/iamhoney")) {
	internal = new HoneyDatabase(path);
	return;
    }
#endif

    // Check for "stub directories".
    string stub_file = path;
    stub_file += "/XAPIANDB";
    if (usual(file_exists(stub_file))) {
	open_stub(*this, stub_file);
	return;
    }

#ifndef XAPIAN_HAS_GLASS_BACKEND
    if (file_exists(path + "/iamglass")) {
	throw FeatureUnavailableError("Glass backend disabled");
    }
#endif
#ifndef XAPIAN_HAS_HONEY_BACKEND
    if (file_exists(path + "/iamhoney")) {
	throw FeatureUnavailableError("Honey backend disabled");
    }
#endif
    if (file_exists(path + "/iamchert")) {
	throw FeatureUnavailableError("Chert backend no longer supported");
    }
    if (file_exists(path + "/iamflint")) {
	throw FeatureUnavailableError("Flint backend no longer supported");
    }

    throw DatabaseNotFoundError("Couldn't detect type of database");
}

Database::Database(int fd, int flags)
{
    LOGCALL_CTOR(API, "Database", fd|flags);

    if (rare(fd < 0))
	throw InvalidArgumentError("fd < 0");

#ifdef XAPIAN_HAS_GLASS_BACKEND
    int type = flags & DB_BACKEND_MASK_;
    switch (type) {
	case 0:
	case DB_BACKEND_GLASS:
	    internal = new GlassDatabase(fd);
    }
#else
    (void)flags;
#endif

    (void)::close(fd);
    throw DatabaseOpeningError("Couldn't detect type of database");
}

#if defined XAPIAN_HAS_GLASS_BACKEND
#define HAVE_DISK_BACKEND
#endif

WritableDatabase::WritableDatabase(const std::string &path, int flags, int block_size)
    : Database()
{
    LOGCALL_CTOR(API, "WritableDatabase", path|flags|block_size);
    // Avoid warning if all disk-based backends are disabled.
    (void)block_size;
    int type = flags & DB_BACKEND_MASK_;
    // Clear the backend bits, so we just pass on other flags to open_stub, etc.
    flags &= ~DB_BACKEND_MASK_;
    if (type == 0) {
	struct stat statbuf;
	if (stat(path.c_str(), &statbuf) == -1) {
	    // ENOENT probably just means that we need to create the directory.
	    if (errno != ENOENT)
		throw DatabaseOpeningError("Couldn't stat '" + path + "'", errno);
	} else {
	    // File or directory already exists.

	    if (S_ISREG(statbuf.st_mode)) {
		// The path is a file, so assume it is a stub database file.
		open_stub(*this, path, flags);
		return;
	    }

	    if (rare(!S_ISDIR(statbuf.st_mode))) {
		throw DatabaseOpeningError("Not a regular file or directory: '" + path + "'");
	    }

	    if (file_exists(path + "/iamglass")) {
		// Existing glass DB.
#ifdef XAPIAN_HAS_GLASS_BACKEND
		type = DB_BACKEND_GLASS;
#else
		throw FeatureUnavailableError("Glass backend disabled");
#endif
	    } else if (file_exists(path + "/iamhoney")) {
		// Existing honey DB.
		throw InvalidOperationError("Honey backend doesn't support "
					    "updating existing databases");
	    } else if (file_exists(path + "/iamchert")) {
		// Existing chert DB.
		throw FeatureUnavailableError("Chert backend no longer supported");
	    } else if (file_exists(path + "/iamflint")) {
		// Existing flint DB.
		throw FeatureUnavailableError("Flint backend no longer supported");
	    } else {
		// Check for "stub directories".
		string stub_file = path;
		stub_file += "/XAPIANDB";
		if (usual(file_exists(stub_file))) {
		    open_stub(*this, stub_file, flags);
		    return;
		}
	    }
	}
    }

    switch (type) {
	case DB_BACKEND_STUB:
	    open_stub(*this, path, flags);
	    return;
	case 0:
	    // Fall through to first enabled case, so order the remaining cases
	    // by preference.
#ifdef XAPIAN_HAS_GLASS_BACKEND
	case DB_BACKEND_GLASS:
	    internal = new GlassWritableDatabase(path, flags, block_size);
	    return;
#endif
	case DB_BACKEND_HONEY:
	    throw InvalidArgumentError("Honey backend doesn't support "
				       "updating existing databases");
	case DB_BACKEND_CHERT:
	    throw FeatureUnavailableError("Chert backend no longer supported");
	case DB_BACKEND_INMEMORY:
#ifdef XAPIAN_HAS_INMEMORY_BACKEND
	    internal = new InMemoryDatabase();
	    return;
#else
	    throw FeatureUnavailableError("Inmemory backend disabled");
#endif
    }
#ifndef HAVE_DISK_BACKEND
    throw FeatureUnavailableError("No disk-based writable backend is enabled");
#endif
}

}
<|endoftext|>


<commit_before><commit_msg>+ [wrd] add performance_test for prototyping of memory component.<commit_after><|endoftext|>


<commit_before><commit_msg>proto<commit_after><|endoftext|>


<commit_before>#pragma once

#ifndef RAZ_LOGGER_HPP
#define RAZ_LOGGER_HPP

#include <functional>
#include <string>

namespace Raz {

enum class LoggingLevel {
  NONE = 0, ///< Ignore all logs.
  ERROR,    ///< Output logs of error category.
  WARNING,  ///< Output logs of warning category & below.
  INFO,     ///< Output logs of info category & below.
  DEBUG,    ///< Output logs of debug category & below.
  ALL       ///< Output all logs.
};

class Logger {
public:
  Logger() = delete;

  static void setLoggingLevel(LoggingLevel level) { m_logLevel = level; }
  static void setLoggingFunction(std::function<void(LoggingLevel, const std::string&)> logFunc) { m_logFunc = std::move(logFunc); }
  static void resetLoggingFunction() { m_logFunc = nullptr; }

  /// Prints an error message.
  /// \note Requires a logging level of "error" or above.
  /// \param message Message to be printed.
  static void error(const std::string& message);
  /// Prints a warning message.
  /// \note Requires a logging level of "warning" or above.
  /// \param message Message to be printed.
  static void warn(const std::string& message);
  /// Prints an information message.
  /// \note Requires a logging level of "info" or above.
  /// \param message Message to be printed.
  static void info(const std::string& message);
#if defined(RAZ_CONFIG_DEBUG) || defined(RAZ_FORCE_DEBUG_LOG)
  /// Prints a debug message.
  /// \note Does nothing in a configuration other than Debug, unless RAZ_FORCE_DEBUG_LOG is defined.
  /// \note Requires a logging level of "debug" or above.
  /// \param message Message to be printed.
  static void debug(const std::string& message);
#else
  static void debug(const std::string&) {}
#endif

  ~Logger() = delete;

private:
  static inline LoggingLevel m_logLevel = LoggingLevel::ERROR;
  static inline std::function<void(LoggingLevel, const std::string&)> m_logFunc {};
};

} // namespace Raz

#endif // RAZ_LOGGER_HPP
<commit_msg>[Utils/Logger] Added a const char* debug() version<commit_after>#pragma once

#ifndef RAZ_LOGGER_HPP
#define RAZ_LOGGER_HPP

#include <functional>
#include <string>

namespace Raz {

enum class LoggingLevel {
  NONE = 0, ///< Ignore all logs.
  ERROR,    ///< Output logs of error category.
  WARNING,  ///< Output logs of warning category & below.
  INFO,     ///< Output logs of info category & below.
  DEBUG,    ///< Output logs of debug category & below.
  ALL       ///< Output all logs.
};

class Logger {
public:
  Logger() = delete;

  static void setLoggingLevel(LoggingLevel level) { m_logLevel = level; }
  static void setLoggingFunction(std::function<void(LoggingLevel, const std::string&)> logFunc) { m_logFunc = std::move(logFunc); }
  static void resetLoggingFunction() { m_logFunc = nullptr; }

  /// Prints an error message.
  /// \note Requires a logging level of "error" or above.
  /// \param message Message to be printed.
  static void error(const std::string& message);
  /// Prints a warning message.
  /// \note Requires a logging level of "warning" or above.
  /// \param message Message to be printed.
  static void warn(const std::string& message);
  /// Prints an information message.
  /// \note Requires a logging level of "info" or above.
  /// \param message Message to be printed.
  static void info(const std::string& message);
#if !defined(NDEBUG) || defined(RAZ_FORCE_DEBUG_LOG)
  /// Prints a debug message.
  /// \note Does nothing in a configuration other than Debug, unless RAZ_FORCE_DEBUG_LOG is defined.
  /// \note Requires a logging level of "debug" or above.
  /// \param message Message to be printed.
  static void debug(const std::string& message);
#else
  static void debug(const char*) {}
  static void debug(const std::string&) {}
#endif

  ~Logger() = delete;

private:
  static inline LoggingLevel m_logLevel = LoggingLevel::ERROR;
  static inline std::function<void(LoggingLevel, const std::string&)> m_logFunc {};
};

} // namespace Raz

#endif // RAZ_LOGGER_HPP
<|endoftext|>