<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile: SampleAppMain.cpp,v $
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/ for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "SampleApp.h"
#include <qapplication.h>
#include "itkTextOutput.h"
#include <itksys/SystemTools.hxx>
#include <stdexcept>

#include <mitkStandardFileLocations.h>
#include <mitkDataStorage.h>

#include <QmitkFunctionalityTesting.h>
#include <sstream>

#include "MITKSplashScreen_xpm.h" // qembed --images MITKSplashScreen.png > MITKSplashScreen_xpm.h
#include "QmitkSplashScreen.h"
#include <qtimer.h>

/*
* BUG: ATI-grafics-cards are slow in building up display lists in case of displaying transparent surfaces.
* Activating GlobalImmediateModeRendering in vtk solves this problem.
*/
//#include <vtkMapper.h>

#include <QmitkControlsRightFctLayoutTemplate.h>

int main(int argc, char* argv[])
{
  int result;
  try
  {
    // Add directory in which the application executable resides as search directory
    mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch(itksys::SystemTools::GetFilenamePath(argv[0]).c_str());
    //
    // determine application name without path and extension
    //
    std::string executableName = itksys::SystemTools::GetFilenameWithoutExtension( itksys::SystemTools::GetFilenameName(argv[0] ) );
    std::stringstream caption;
    caption << executableName << ", Builddate " << __DATE__ << ", " << __TIME__ << ".";
    itk::OutputWindow::SetInstance(itk::TextOutput::New().GetPointer());
    // parse testing parameters
    int testType = 0;
    for (int i = 0; i < argc; i++)
    {
        if ((strcmp(argv[i], "-testing") == 0))
        {
             testType |= QmitkFunctionalityTesting::GUITest;
        }
        if ((strcmp(argv[i], "-optiontesting") == 0))
        {
             testType |= QmitkFunctionalityTesting::OptionsTest;
        }
        if ((strcmp(argv[i], "-alltesting") == 0))
        {
             testType |= QmitkFunctionalityTesting::AllTests;
        }
    }

    std::cout << "testType = " << testType << "\n";

    const char * testingParameter = NULL;
    if ((strcmp(argv[argc - 1], "-testing") != 0) && (strcmp(argv[argc - 1], "-optiontesting") != 0) && (strcmp(argv[argc - 1], "-alltesting") != 0) )
        testingParameter = argv[argc - 1];

    QApplication a( argc, argv );

    // popup a splash screen
    bool showSplashScreen(false);
    QmitkSplashScreen* splasher(NULL);
    if (showSplashScreen)
    {
      QImage icon = qembed_findImage("MITKSplashScreen");
      QPixmap pixmap(icon);
      splasher = new QmitkSplashScreen( pixmap );
      a.processEvents();
    }

    SampleApp mainWindow(NULL, "mainwindow",Qt::WType_TopLevel,testingParameter);
    mainWindow.setCaption( caption.str().c_str() );
    a.setMainWidget(&mainWindow);

#ifdef USEDARKPALETTE
    std::cout << "changing palette ..." << std::endl;
    QPalette p( QColor( 64,64,64), QColor(64,64,64));
    a.setPalette(p,TRUE);
#endif
    /*
    * BUG: ATI-grafics-cards are slow in building up display lists in case of displaying transparent surfaces.
    * Activating GlobalImmediateModeRendering in vtk solves this problem. Also add #include vtkMapper above
    */
    //vtkMapper::GlobalImmediateModeRenderingOn();

    mainWindow.SetDefaultWidgetSize();

    // reinit views after mainwindow and fctwidget initialization
    mainWindow.viewReinitMultiWidget();

    if (showSplashScreen)
    {
      QTimer::singleShot(5000, splasher, SLOT(close()) );
    }

    if(testType)
    {
      std::cout.setf(std::ios_base::unitbuf);
      result = StartQmitkFunctionalityTesting(mainWindow.GetFctMediator(), testType);
    }
    else
    {
      result = a.exec();
    }
  }
  catch (const std::bad_alloc& e)
  {
    std::cout << "MITK MainApp caught bad_alloc: Could not acquire enough memory: " << e.what() << std::endl;
    return EXIT_FAILURE;
  }
  catch (const std::exception& e)
  {
    std::cout << "MITK MainApp caught an exception: " << e.what() << std::endl;
    return EXIT_FAILURE;
  }
  catch (...)
  {
    std::cout << "MITK MainApp caught something like an exception..." << std::endl;
    return EXIT_FAILURE;
  }
  try
  {
    mitk::DataStorage::GetInstance()->ShutdownSingleton();
  }
  catch (const std::exception& e)
  {
    std::cout << "MITK MainApp caught an exception on ShutdownSingleton: " << e.what() << std::endl;
    return EXIT_FAILURE;
  }
  catch (...)
  {
    std::cout << "MITK MainApp caught something like an exception on ShutdownSingleton..." << std::endl;
    return EXIT_FAILURE;
  }
  return result;
}
<commit_msg>FIX (#1531): Functionality icons missing, inserted missing check for (testType != 0)<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Module:    $RCSfile: SampleAppMain.cpp,v $
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/ for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "SampleApp.h"
#include <qapplication.h>
#include "itkTextOutput.h"
#include <itksys/SystemTools.hxx>
#include <stdexcept>

#include <mitkStandardFileLocations.h>
#include <mitkDataStorage.h>

#include <QmitkFunctionalityTesting.h>
#include <sstream>

#include "MITKSplashScreen_xpm.h" // qembed --images MITKSplashScreen.png > MITKSplashScreen_xpm.h
#include "QmitkSplashScreen.h"
#include <qtimer.h>

/*
* BUG: ATI-grafics-cards are slow in building up display lists in case of displaying transparent surfaces.
* Activating GlobalImmediateModeRendering in vtk solves this problem.
*/
//#include <vtkMapper.h>

#include <QmitkControlsRightFctLayoutTemplate.h>

int main(int argc, char* argv[])
{
  int result;
  try
  {
    // Add directory in which the application executable resides as search directory
    mitk::StandardFileLocations::GetInstance()->AddDirectoryForSearch(itksys::SystemTools::GetFilenamePath(argv[0]).c_str());
    //
    // determine application name without path and extension
    //
    std::string executableName = itksys::SystemTools::GetFilenameWithoutExtension( itksys::SystemTools::GetFilenameName(argv[0] ) );
    std::stringstream caption;
    caption << executableName << ", Builddate " << __DATE__ << ", " << __TIME__ << ".";
    itk::OutputWindow::SetInstance(itk::TextOutput::New().GetPointer());
    // parse testing parameters
    int testType = 0;
    for (int i = 0; i < argc; i++)
    {
        if ((strcmp(argv[i], "-testing") == 0))
        {
             testType |= QmitkFunctionalityTesting::GUITest;
        }
        if ((strcmp(argv[i], "-optiontesting") == 0))
        {
             testType |= QmitkFunctionalityTesting::OptionsTest;
        }
        if ((strcmp(argv[i], "-alltesting") == 0))
        {
             testType |= QmitkFunctionalityTesting::AllTests;
        }
    }

    std::cout << "testType = " << testType << "\n";

    const char * testingParameter = NULL;
    if ((testType != 0) && (strcmp(argv[argc - 1], "-testing") != 0) && (strcmp(argv[argc - 1], "-optiontesting") != 0) && (strcmp(argv[argc - 1], "-alltesting") != 0) )
        testingParameter = argv[argc - 1];

    QApplication a( argc, argv );

    // popup a splash screen
    bool showSplashScreen(false);
    QmitkSplashScreen* splasher(NULL);
    if (showSplashScreen)
    {
      QImage icon = qembed_findImage("MITKSplashScreen");
      QPixmap pixmap(icon);
      splasher = new QmitkSplashScreen( pixmap );
      a.processEvents();
    }

    SampleApp mainWindow(NULL, "mainwindow",Qt::WType_TopLevel,testingParameter);
    mainWindow.setCaption( caption.str().c_str() );
    a.setMainWidget(&mainWindow);

#ifdef USEDARKPALETTE
    std::cout << "changing palette ..." << std::endl;
    QPalette p( QColor( 64,64,64), QColor(64,64,64));
    a.setPalette(p,TRUE);
#endif
    /*
    * BUG: ATI-grafics-cards are slow in building up display lists in case of displaying transparent surfaces.
    * Activating GlobalImmediateModeRendering in vtk solves this problem. Also add #include vtkMapper above
    */
    //vtkMapper::GlobalImmediateModeRenderingOn();

    mainWindow.SetDefaultWidgetSize();

    // reinit views after mainwindow and fctwidget initialization
    mainWindow.viewReinitMultiWidget();

    if (showSplashScreen)
    {
      QTimer::singleShot(5000, splasher, SLOT(close()) );
    }

    if(testType)
    {
      std::cout.setf(std::ios_base::unitbuf);
      result = StartQmitkFunctionalityTesting(mainWindow.GetFctMediator(), testType);
    }
    else
    {
      result = a.exec();
    }
  }
  catch (const std::bad_alloc& e)
  {
    std::cout << "MITK MainApp caught bad_alloc: Could not acquire enough memory: " << e.what() << std::endl;
    return EXIT_FAILURE;
  }
  catch (const std::exception& e)
  {
    std::cout << "MITK MainApp caught an exception: " << e.what() << std::endl;
    return EXIT_FAILURE;
  }
  catch (...)
  {
    std::cout << "MITK MainApp caught something like an exception..." << std::endl;
    return EXIT_FAILURE;
  }
  try
  {
    mitk::DataStorage::GetInstance()->ShutdownSingleton();
  }
  catch (const std::exception& e)
  {
    std::cout << "MITK MainApp caught an exception on ShutdownSingleton: " << e.what() << std::endl;
    return EXIT_FAILURE;
  }
  catch (...)
  {
    std::cout << "MITK MainApp caught something like an exception on ShutdownSingleton..." << std::endl;
    return EXIT_FAILURE;
  }
  return result;
}
<|endoftext|>


<commit_before>#include <Empathy/Empathy/Empathy.h>
#include <Empathy/empathy-linear/linear_empathy.h>
#include <irrKlang.h>
#include <GLFW/glfw3.h>

using namespace std;

static GLFWwindow * window;
static GLfloat mouseX,mouseY;
irrklang::ISoundEngine* engine;

static GLdouble lastPressTime;
static GLdouble thresholdTime=0.2;
static GLboolean mousePressed=GL_FALSE;

void createClickEvent(int button=GLFW_MOUSE_BUTTON_LEFT){
    empathy::radio::Event event(EMPATHY_EVENT_ACTION_NONE);

    if(button==GLFW_MOUSE_BUTTON_LEFT ){
        event=empathy::radio::Event(EMPATHY_EVENT_INPUT_MOUSE_LEFT_KEY_PRESS);
    }else if(button==GLFW_MOUSE_BUTTON_RIGHT){
        event=empathy::radio::Event(EMPATHY_EVENT_INPUT_MOUSE_RIGHT_KEY_PRESS);
    }

    event.putDouble(EMPATHY_MOUSE_XPOS,mouseX);
    event.putDouble(EMPATHY_MOUSE_YPOS,700-mouseY);

    empathy::radio::BroadcastStation::emit(event);
}
void mouse_input_callback(GLFWwindow *window, int button, int action, int mods) {
    if(action==GLFW_PRESS){
        createClickEvent(button);

        lastPressTime=glfwGetTime();

        mousePressed=GL_TRUE;

    }else if(action==GLFW_RELEASE){
        lastPressTime=0;
        mousePressed=GL_FALSE;
    }
}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) {
//    std::cout<<"key call back received"<<action<<std::endl;

    // When a user presses the escape key, we set the WindowShouldClose property to true,
    // closing the application

    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS){
//            glfwSetWindowShouldClose(instance->window, GL_TRUE);
        empathy_linear::makeReadyToClose();

        return;
    }

    cout<<"KEY callback"<<endl;
    std::string myAction="";
    if(action==GLFW_PRESS){
        myAction=EMPATHY_EVENT_INPUT_KEY_PRESS;
    }else if(action==GLFW_RELEASE){
        myAction=EMPATHY_EVENT_INPUT_KEY_RELEASE;
    }else if(action==GLFW_REPEAT){
        myAction=EMPATHY_EVENT_INPUT_KEY_REPEAT;
    }
    if(myAction != ""){
        empathy::radio::Event event=empathy::radio::Event(myAction);
        event.putInt(EMPATHY_EVENT_INPUT_KEY,key);

        empathy::radio::BroadcastStation::emit(event);
    }

}

void mouse_position_callback(GLFWwindow *window, double xpos, double ypos) {
    mouseX=xpos;
    mouseY=ypos;
}

void initGlfw() {
    //	cout<<"glfwInit"<<endl;

    glfwInit();

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    int count;
    GLFWmonitor** monitors=glfwGetMonitors(&count);

    //Create a GLFW window
    window = glfwCreateWindow((GLuint)700, (GLuint)700, "Empathy | <3", nullptr, nullptr);
    if (window == nullptr)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

    glfwMakeContextCurrent(window);

    //set event receiver call backs.
    glfwSetKeyCallback(window, key_callback);
    glfwSetMouseButtonCallback(window,mouse_input_callback);
    glfwSetCursorPosCallback(window,mouse_position_callback);
}

void init(){

    initGlfw();
    empathy_linear::init();

    empathy_linear::addJsonBrain("brains/test.json");
    empathy_linear::addDummyTouchBrain();

    engine = irrklang::createIrrKlangDevice();

    if (!engine)
    {
        printf("Could not startup engine\n");
        exit(EXIT_FAILURE);
    }

    engine->setSoundVolume(0.4f);
}

void loop(){
    while(! empathy_linear::shouldClose() && !glfwWindowShouldClose(window)){

        std::stack<empathy::moonlight::BasicNote> audioEvents= empathy_linear::getMusicalKeyboardEvents();

        while(! audioEvents.empty()){

            empathy::moonlight::BasicNote playableItem=audioEvents.top();

            std::string fileName=playableItem.getNote()+std::to_string(playableItem.getOctave()-1);
            if(playableItem.isSharp()){
                fileName="#"+fileName;

            }

            std::string path=empathy::getAssetPath("audio/keyboard/music/"+fileName+".mp3");

            try{
                cout<<"Playing audio "<<fileName<<endl;

                engine->play2D(path.c_str());
            }catch (int i){
                cout<<"Could not play "<<path<<endl;
                continue;
            }

            audioEvents.pop();
        }

        if(mousePressed && glfwGetTime()-lastPressTime>thresholdTime){
            createClickEvent();
        }

        glfwPollEvents();

        empathy_linear::loop();

        empathy_linear::setTime((GLfloat ) glfwGetTime());

        glfwSwapBuffers(window);
    }
}
void flush(){
    engine->drop();

    empathy_linear::flush();

    if(window!= nullptr)
        glfwSetWindowShouldClose(window,true);

    glfwTerminate();
}

int  main() {
    init();
    loop();
    flush();
}
<commit_msg>added full screen option<commit_after>#include <Empathy/Empathy/Empathy.h>
#include <Empathy/empathy-linear/linear_empathy.h>
#include <irrKlang.h>
#include <GLFW/glfw3.h>

#define FULL_SCREEN true

#if FULL_SCREEN
 #define RENDER_SIZE 700
 #define SC_SIZE_X 1366
 #define SC_SIZE_Y 768
#else
 #define RENDER_SIZE 700
 #define SC_SIZE_X 700
 #define SC_SIZE_Y 700
#endif

using namespace std;

static GLFWwindow * window;
static GLfloat mouseX,mouseY;
irrklang::ISoundEngine* engine;

static GLdouble lastPressTime;
static GLdouble thresholdTime=0.2;
static GLboolean mousePressed=GL_FALSE;

void createClickEvent(int button=GLFW_MOUSE_BUTTON_LEFT){
    empathy::radio::Event event(EMPATHY_EVENT_ACTION_NONE);

    if(button==GLFW_MOUSE_BUTTON_LEFT ){
        event=empathy::radio::Event(EMPATHY_EVENT_INPUT_MOUSE_LEFT_KEY_PRESS);
    }else if(button==GLFW_MOUSE_BUTTON_RIGHT){
        event=empathy::radio::Event(EMPATHY_EVENT_INPUT_MOUSE_RIGHT_KEY_PRESS);
    }

    event.putDouble(EMPATHY_MOUSE_XPOS,mouseX);
    event.putDouble(EMPATHY_MOUSE_YPOS,RENDER_SIZE-mouseY);

    empathy::radio::BroadcastStation::emit(event);
}
void mouse_input_callback(GLFWwindow *window, int button, int action, int mods) {
    if(action==GLFW_PRESS){
        createClickEvent(button);

        lastPressTime=glfwGetTime();

        mousePressed=GL_TRUE;

    }else if(action==GLFW_RELEASE){
        lastPressTime=0;
        mousePressed=GL_FALSE;
    }
}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mode) {
//    std::cout<<"key call back received"<<action<<std::endl;

    // When a user presses the escape key, we set the WindowShouldClose property to true,
    // closing the application

    if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS){
//            glfwSetWindowShouldClose(instance->window, GL_TRUE);
        empathy_linear::makeReadyToClose();

        return;
    }

    cout<<"KEY callback"<<endl;
    std::string myAction="";
    if(action==GLFW_PRESS){
        myAction=EMPATHY_EVENT_INPUT_KEY_PRESS;
    }else if(action==GLFW_RELEASE){
        myAction=EMPATHY_EVENT_INPUT_KEY_RELEASE;
    }else if(action==GLFW_REPEAT){
        myAction=EMPATHY_EVENT_INPUT_KEY_REPEAT;
    }
    if(myAction != ""){
        empathy::radio::Event event=empathy::radio::Event(myAction);
        event.putInt(EMPATHY_EVENT_INPUT_KEY,key);

        empathy::radio::BroadcastStation::emit(event);
    }

}

void mouse_position_callback(GLFWwindow *window, double xpos, double ypos) {

    mouseX= xpos -(SC_SIZE_X-RENDER_SIZE)/2;;

    mouseY = ypos - (SC_SIZE_Y-RENDER_SIZE)/2;
}

void initGlfw() {
    //	cout<<"glfwInit"<<endl;

    glfwInit();

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

    int count;
    GLFWmonitor** monitors=glfwGetMonitors(&count);

    //Create a GLFW window
    window = glfwCreateWindow((GLuint)SC_SIZE_X, (GLuint)SC_SIZE_Y, "Empathy | <3",
                              FULL_SCREEN ? glfwGetPrimaryMonitor(): nullptr, nullptr);
    if (window == nullptr)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        exit(EXIT_FAILURE);
    }

    glfwMakeContextCurrent(window);

    //set event receiver call backs.
    glfwSetKeyCallback(window, key_callback);
    glfwSetMouseButtonCallback(window,mouse_input_callback);
    glfwSetCursorPosCallback(window,mouse_position_callback);
}

void init(){
    GLFWmonitor * glfWmonitor=glfwGetPrimaryMonitor();

    initGlfw();
    empathy_linear::init();
    empathy_linear::setScreenMargins( (SC_SIZE_X-RENDER_SIZE)/2 , (SC_SIZE_Y-RENDER_SIZE)/2);

    empathy_linear::setScreenSize(RENDER_SIZE);

    empathy_linear::addJsonBrain("brains/test.json");
    empathy_linear::addDummyTouchBrain();

    engine = irrklang::createIrrKlangDevice();

    if (!engine)
    {
        printf("Could not startup engine\n");
        exit(EXIT_FAILURE);
    }

    engine->setSoundVolume(0.4f);
}

void loop(){
    while(! empathy_linear::shouldClose() && !glfwWindowShouldClose(window)){

        std::stack<empathy::moonlight::BasicNote> audioEvents= empathy_linear::getMusicalKeyboardEvents();

        while(! audioEvents.empty()){

            empathy::moonlight::BasicNote playableItem=audioEvents.top();

            std::string fileName=playableItem.getNote()+std::to_string(playableItem.getOctave()-1);
            if(playableItem.isSharp()){
                fileName="#"+fileName;

            }

            std::string path=empathy::getAssetPath("audio/keyboard/music/"+fileName+".mp3");

            try{
                cout<<"Playing audio "<<fileName<<endl;

                engine->play2D(path.c_str());
            }catch (int i){
                cout<<"Could not play "<<path<<endl;
                continue;
            }

            audioEvents.pop();
        }

        if(mousePressed && glfwGetTime()-lastPressTime>thresholdTime){
            createClickEvent();
        }

        glfwPollEvents();

        empathy_linear::loop();

        empathy_linear::setTime((GLfloat ) glfwGetTime());

        glfwSwapBuffers(window);
    }
}
void flush(){
    engine->drop();

    empathy_linear::flush();

    if(window!= nullptr)
        glfwSetWindowShouldClose(window,true);

    glfwTerminate();
}

int  main() {
    init();
    loop();
    flush();
}
<|endoftext|>


<commit_before>/** \file    bib_ref_to_codes_tool.cc
 *  \brief   A tool for converting bible references to numeric codes.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2015-2017, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <fstream>
#include <iostream>
#include <string>
#include <unordered_map>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include "BibleReferenceParser.h"
#include "MapIO.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "util.h"

std::string InsertSpaceAtFirstLetterDigitBoundary(const std::string &s) {
    if (s.empty())
        return s;

    std::string retval;
    bool found_first_boundary(false);
    auto ch(s.cbegin());
    retval += *ch;
    while (++ch != s.cend()) {
        if (not found_first_boundary and (std::isalpha(*(ch - 1)) and std::isdigit(*ch))) {
            found_first_boundary = true;
            retval += ' ';
        }

        retval += *ch;
    }

    return retval;
}

// Squeezes out spaces after a leading number, e.g. "1. mos" => "1.mos" or "1 mos" => "1mos".
std::string CanoniseLeadingNumber(const std::string &bible_reference_candidate) {
    static const RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactory("^\\d\\.?\\s+\\S+"));
    std::string err_msg;
    if (not matcher->matched(bible_reference_candidate, &err_msg)) {
        if (not err_msg.empty())
            Error("unexpected reg ex error: " + err_msg);
        return bible_reference_candidate;
    }

    std::string ordinal_string;
    ordinal_string = bible_reference_candidate[0];
    size_t rest_start(1);
    if (bible_reference_candidate[1] == '.') {
        ordinal_string += '.';
        ++rest_start;
    }

    while (isspace(bible_reference_candidate[rest_start]))
        ++rest_start;

    return ordinal_string + bible_reference_candidate.substr(rest_start);
}

void SplitIntoBookAndChaptersAndVerses(const std::string &bible_reference_candidate,
                                       std::string * const book_candidate,
                                       std::string * const chapters_and_verses_candidate)
{
    book_candidate->clear();
    chapters_and_verses_candidate->clear();

    const size_t len(bible_reference_candidate.length());
    if (len <= 3)
        *book_candidate = bible_reference_candidate;
    else if (isdigit(bible_reference_candidate[len - 1])
             or (isalpha(bible_reference_candidate[len - 1]) and isdigit(bible_reference_candidate[len - 2])))
    {
        const size_t last_space_pos(bible_reference_candidate.rfind(' '));
        if (last_space_pos == std::string::npos)
            *book_candidate = bible_reference_candidate;
        else {
            *book_candidate = bible_reference_candidate.substr(0, last_space_pos);
            *chapters_and_verses_candidate = bible_reference_candidate.substr(last_space_pos + 1);
        }
    } else
        *book_candidate = bible_reference_candidate;
}

/** \brief Map from noncanonical bible book forms to the canonical ones.
 *  \return The mapped name or, if no mapping was found, "bible_book_candidate".
 */
std::string CanoniseBibleBook(const bool verbose,
                              const std::string &books_of_the_bible_to_canonical_form_map_filename,
                              const std::string &bible_book_candidate)
{
    std::unordered_map<std::string, std::string> books_of_the_bible_to_canonical_form_map;
    MapIO::DeserialiseMap(books_of_the_bible_to_canonical_form_map_filename,
                          &books_of_the_bible_to_canonical_form_map);
    const auto non_canonical_form_and_canonical_form(
        books_of_the_bible_to_canonical_form_map.find(bible_book_candidate));
    if (non_canonical_form_and_canonical_form != books_of_the_bible_to_canonical_form_map.end()) {
        if (verbose)
            std::cerr << "Replacing \"" << bible_book_candidate << "\" with \""
                      << non_canonical_form_and_canonical_form->second << "\".\n";
        return non_canonical_form_and_canonical_form->second;
    }

    return bible_book_candidate;
}

std::string MapBibleBookToCode(const bool verbose, const std::string &bible_book_candidate,
                               const std::string &books_of_the_bible_to_code_map_filename)
{
    std::unordered_map<std::string, std::string> bible_books_to_codes_map;
    MapIO::DeserialiseMap(books_of_the_bible_to_code_map_filename, &bible_books_to_codes_map);
    const auto bible_book_and_code(bible_books_to_codes_map.find(bible_book_candidate));
    if (bible_book_and_code == bible_books_to_codes_map.end()) {
        if (verbose)
            std::cerr << "No mapping from \"" << bible_book_candidate << "\" to a book code was found!\n";

        std::exit(EXIT_FAILURE); // Unknown bible book!
    }

    return bible_book_and_code->second;
}

void HandlePericopes(const bool verbose, const bool generate_solr_query, const std::string &bible_reference_candidate,
                     const std::string &pericopes_to_codes_map_filename)
{
    std::unordered_multimap<std::string, std::string> pericopes_to_codes_map;
    MapIO::DeserialiseMap(pericopes_to_codes_map_filename, &pericopes_to_codes_map);

    const auto begin_end(pericopes_to_codes_map.equal_range(bible_reference_candidate));
    if (begin_end.first != begin_end.second) {
        if (verbose)
            std::cerr << "Found a pericope to codes mapping.\n";
        std::string query;
        for (auto pair(begin_end.first); pair != begin_end.second; ++pair) {
            if (generate_solr_query) {
                if (not query.empty())
                    query += ' ';
                query += StringUtil::Map(pair->second, ':', '_');
            } else
                std::cout << pair->second << '\n';
        }
        if (generate_solr_query)
            std::cout << query << '\n';

        std::exit(EXIT_SUCCESS);
    }
}

void HandleBookRanges(const bool verbose, const bool generate_solr_query,
                      const std::string &books_of_the_bible_to_canonical_form_map_filename,
                      const std::string &books_of_the_bible_to_code_map_filename,
                      const std::string &bible_reference_candidate)
{
    const RegexMatcher *matcher(RegexMatcher::RegexMatcherFactory("^([12])-([23])\\s*([A-Za-z]+)\\s*$"));
    if (not matcher->matched(bible_reference_candidate))
        return;

    unsigned starting_volume;
    if (not StringUtil::ToUnsigned((*matcher)[1], &starting_volume) or starting_volume > 2)
        Error("\"" + (*matcher)[1] + "\" is not a valid starting volume!");

    unsigned ending_volume;
    if (not StringUtil::ToUnsigned((*matcher)[2], &ending_volume) or ending_volume > 3
        or ending_volume <= starting_volume)
        Error("\"" + (*matcher)[2] + "\" is not a valid ending volume!");

    const std::string non_canonical_book_name((*matcher)[3]);
    const std::string starting_bible_book_candidate(
        CanoniseBibleBook(verbose, books_of_the_bible_to_canonical_form_map_filename,
                          std::to_string(starting_volume) + non_canonical_book_name));
    const std::string ending_bible_book_candidate(
        CanoniseBibleBook(verbose, books_of_the_bible_to_canonical_form_map_filename,
                          std::to_string(ending_volume) + non_canonical_book_name));
    if (verbose) {
        std::cout << "Identified a bible book range.  Starting volume " << starting_volume << ", ending volume "
                  << ending_volume << ", book is \"" << non_canonical_book_name << "\".\n";
    }

    const std::string first_book_code(MapBibleBookToCode(verbose, starting_bible_book_candidate,
                                                         books_of_the_bible_to_code_map_filename));
    const std::string second_book_code(MapBibleBookToCode(verbose, ending_bible_book_candidate,
                                                          books_of_the_bible_to_code_map_filename));

    std::cout << (first_book_code + std::string(BibleReferenceParser::MAX_CHAPTER_LENGTH
                                                + BibleReferenceParser::MAX_VERSE_LENGTH, '0'))
              << (generate_solr_query ? '_' : ':')
              << (second_book_code + std::string(BibleReferenceParser::MAX_CHAPTER_LENGTH
                                                 + BibleReferenceParser::MAX_VERSE_LENGTH, '9'))
              << '\n';

    std::exit(EXIT_SUCCESS);
}

void HandleOrdinaryReferences(const bool verbose, const bool generate_solr_query,
                              std::string bible_reference_candidate,
                              const std::string &bible_books_to_codes_map_filename,
                              const std::string &books_of_the_bible_to_canonical_form_map_filename)
{
    bible_reference_candidate = CanoniseLeadingNumber(InsertSpaceAtFirstLetterDigitBoundary(
                                    StringUtil::RemoveChars(" \t", &bible_reference_candidate)));
    std::string book_candidate, chapters_and_verses_candidate;
    SplitIntoBookAndChaptersAndVerses(bible_reference_candidate, &book_candidate, &chapters_and_verses_candidate);
    if (verbose) {
        std::cerr << "book_candidate = \"" << book_candidate << "\"\n";
        std::cerr << "chapters_and_verses_candidate = \"" << chapters_and_verses_candidate << "\"\n";
    }

    book_candidate = CanoniseBibleBook(verbose, books_of_the_bible_to_canonical_form_map_filename, book_candidate);
    const std::string book_code(MapBibleBookToCode(verbose, book_candidate, bible_books_to_codes_map_filename));
    if (verbose)
        std::cerr << "book code = \"" << book_code << "\"\n";
    if (chapters_and_verses_candidate.empty()) {
        std::cout << book_code
                  << std::string(BibleReferenceParser::MAX_CHAPTER_LENGTH
                                 + BibleReferenceParser::MAX_VERSE_LENGTH, '0')
                  << (generate_solr_query ? '_' : ':') << book_code
                  << std::string(BibleReferenceParser::MAX_CHAPTER_LENGTH
                                 + BibleReferenceParser::MAX_VERSE_LENGTH, '9')
                  << '\n';

        std::exit(EXIT_SUCCESS);
    }

    std::set<std::pair<std::string, std::string>> start_end;
    if (not BibleReferenceParser::ParseBibleReference(chapters_and_verses_candidate, book_code, &start_end)) {
        if (verbose)
            std::cerr << "The parsing of \"" << chapters_and_verses_candidate
                      << "\" as chapters and verses failed!\n";
        std::exit(EXIT_FAILURE);
    }

    std::string query;
    for (const auto &pair : start_end) {
        if (generate_solr_query) {
            if (not query.empty())
                query += ' ';
            query += pair.first + "_" + pair.second;
        } else
            std::cout << pair.first << ':' << pair.second << '\n';
    }
    if (generate_solr_query)
        std::cout << query << '\n';
}

static void Usage() __attribute__((noreturn));

static void Usage() {
    std::cerr << "usage: " << progname << " [--debug|--query] bible_reference_candidate\n";
    std::cerr << "          books_of_the_bible_to_code_map\n";
    std::cerr << "          books_of_the_bible_to_canonical_form_map pericopes_to_codes_map\n";
    std::cerr << '\n';
    std::cerr << "          When --debug has been specified additional tracing output will be generated.\n";
    std::cerr << "          When --query has been specified SOLR search queries will be output.\n";
    std::exit(EXIT_FAILURE);
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    bool verbose(false), generate_solr_query(false);

    if (argc == 6) {
        if (std::strcmp(argv[1], "--debug") == 0)
            verbose = true;
        else if (std::strcmp(argv[1], "--query") == 0)
            generate_solr_query = true;
        else
            Usage();
        ++argv, --argc;
    }

    if (argc != 5)
        Usage();

    const std::string books_of_the_bible_to_code_map_filename(argv[2]);
    const std::string books_of_the_bible_to_canonical_form_map_filename(argv[3]);
    std::string bible_reference_candidate(StringUtil::Trim(StringUtil::ToLower(argv[1])));
    StringUtil::CollapseWhitespace(&bible_reference_candidate);

    HandleBookRanges(verbose, generate_solr_query, books_of_the_bible_to_canonical_form_map_filename,
                     books_of_the_bible_to_code_map_filename, bible_reference_candidate);
    HandlePericopes(verbose, generate_solr_query, bible_reference_candidate, argv[4]);
    HandleOrdinaryReferences(verbose, generate_solr_query, bible_reference_candidate,
                             books_of_the_bible_to_code_map_filename,
                             books_of_the_bible_to_canonical_form_map_filename);
}
<commit_msg>Allow "ö" in bible book names.<commit_after>/** \file    bib_ref_to_codes_tool.cc
 *  \brief   A tool for converting bible references to numeric codes.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2015-2017, Library of the University of Tübingen

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <fstream>
#include <iostream>
#include <string>
#include <unordered_map>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include "BibleReferenceParser.h"
#include "MapIO.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "util.h"

std::string InsertSpaceAtFirstLetterDigitBoundary(const std::string &s) {
    if (s.empty())
        return s;

    std::string retval;
    bool found_first_boundary(false);
    auto ch(s.cbegin());
    retval += *ch;
    while (++ch != s.cend()) {
        if (not found_first_boundary and (std::isalpha(*(ch - 1)) and std::isdigit(*ch))) {
            found_first_boundary = true;
            retval += ' ';
        }

        retval += *ch;
    }

    return retval;
}

// Squeezes out spaces after a leading number, e.g. "1. mos" => "1.mos" or "1 mos" => "1mos".
std::string CanoniseLeadingNumber(const std::string &bible_reference_candidate) {
    static const RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactory("^\\d\\.?\\s+\\S+"));
    std::string err_msg;
    if (not matcher->matched(bible_reference_candidate, &err_msg)) {
        if (not err_msg.empty())
            Error("unexpected reg ex error: " + err_msg);
        return bible_reference_candidate;
    }

    std::string ordinal_string;
    ordinal_string = bible_reference_candidate[0];
    size_t rest_start(1);
    if (bible_reference_candidate[1] == '.') {
        ordinal_string += '.';
        ++rest_start;
    }

    while (isspace(bible_reference_candidate[rest_start]))
        ++rest_start;

    return ordinal_string + bible_reference_candidate.substr(rest_start);
}

void SplitIntoBookAndChaptersAndVerses(const std::string &bible_reference_candidate,
                                       std::string * const book_candidate,
                                       std::string * const chapters_and_verses_candidate)
{
    book_candidate->clear();
    chapters_and_verses_candidate->clear();

    const size_t len(bible_reference_candidate.length());
    if (len <= 3)
        *book_candidate = bible_reference_candidate;
    else if (isdigit(bible_reference_candidate[len - 1])
             or (isalpha(bible_reference_candidate[len - 1]) and isdigit(bible_reference_candidate[len - 2])))
    {
        const size_t last_space_pos(bible_reference_candidate.rfind(' '));
        if (last_space_pos == std::string::npos)
            *book_candidate = bible_reference_candidate;
        else {
            *book_candidate = bible_reference_candidate.substr(0, last_space_pos);
            *chapters_and_verses_candidate = bible_reference_candidate.substr(last_space_pos + 1);
        }
    } else
        *book_candidate = bible_reference_candidate;
}

/** \brief Map from noncanonical bible book forms to the canonical ones.
 *  \return The mapped name or, if no mapping was found, "bible_book_candidate".
 */
std::string CanoniseBibleBook(const bool verbose,
                              const std::string &books_of_the_bible_to_canonical_form_map_filename,
                              const std::string &bible_book_candidate)
{
    std::unordered_map<std::string, std::string> books_of_the_bible_to_canonical_form_map;
    MapIO::DeserialiseMap(books_of_the_bible_to_canonical_form_map_filename,
                          &books_of_the_bible_to_canonical_form_map);
    const auto non_canonical_form_and_canonical_form(
        books_of_the_bible_to_canonical_form_map.find(bible_book_candidate));
    if (non_canonical_form_and_canonical_form != books_of_the_bible_to_canonical_form_map.end()) {
        if (verbose)
            std::cerr << "Replacing \"" << bible_book_candidate << "\" with \""
                      << non_canonical_form_and_canonical_form->second << "\".\n";
        return non_canonical_form_and_canonical_form->second;
    }

    return bible_book_candidate;
}

std::string MapBibleBookToCode(const bool verbose, const std::string &bible_book_candidate,
                               const std::string &books_of_the_bible_to_code_map_filename)
{
    std::unordered_map<std::string, std::string> bible_books_to_codes_map;
    MapIO::DeserialiseMap(books_of_the_bible_to_code_map_filename, &bible_books_to_codes_map);
    const auto bible_book_and_code(bible_books_to_codes_map.find(bible_book_candidate));
    if (bible_book_and_code == bible_books_to_codes_map.end()) {
        if (verbose)
            std::cerr << "No mapping from \"" << bible_book_candidate << "\" to a book code was found!\n";

        std::exit(EXIT_FAILURE); // Unknown bible book!
    }

    return bible_book_and_code->second;
}

void HandlePericopes(const bool verbose, const bool generate_solr_query, const std::string &bible_reference_candidate,
                     const std::string &pericopes_to_codes_map_filename)
{
    std::unordered_multimap<std::string, std::string> pericopes_to_codes_map;
    MapIO::DeserialiseMap(pericopes_to_codes_map_filename, &pericopes_to_codes_map);

    const auto begin_end(pericopes_to_codes_map.equal_range(bible_reference_candidate));
    if (begin_end.first != begin_end.second) {
        if (verbose)
            std::cerr << "Found a pericope to codes mapping.\n";
        std::string query;
        for (auto pair(begin_end.first); pair != begin_end.second; ++pair) {
            if (generate_solr_query) {
                if (not query.empty())
                    query += ' ';
                query += StringUtil::Map(pair->second, ':', '_');
            } else
                std::cout << pair->second << '\n';
        }
        if (generate_solr_query)
            std::cout << query << '\n';

        std::exit(EXIT_SUCCESS);
    }
}

void HandleBookRanges(const bool verbose, const bool generate_solr_query,
                      const std::string &books_of_the_bible_to_canonical_form_map_filename,
                      const std::string &books_of_the_bible_to_code_map_filename,
                      const std::string &bible_reference_candidate)
{
    const RegexMatcher *matcher(RegexMatcher::RegexMatcherFactory("^([12])-([23])\\s*([A-ZÖa-zö]+)\\s*$"));
    if (not matcher->matched(bible_reference_candidate))
        return;

    unsigned starting_volume;
    if (not StringUtil::ToUnsigned((*matcher)[1], &starting_volume) or starting_volume > 2)
        Error("\"" + (*matcher)[1] + "\" is not a valid starting volume!");

    unsigned ending_volume;
    if (not StringUtil::ToUnsigned((*matcher)[2], &ending_volume) or ending_volume > 3
        or ending_volume <= starting_volume)
        Error("\"" + (*matcher)[2] + "\" is not a valid ending volume!");

    const std::string non_canonical_book_name((*matcher)[3]);
    const std::string starting_bible_book_candidate(
        CanoniseBibleBook(verbose, books_of_the_bible_to_canonical_form_map_filename,
                          std::to_string(starting_volume) + non_canonical_book_name));
    const std::string ending_bible_book_candidate(
        CanoniseBibleBook(verbose, books_of_the_bible_to_canonical_form_map_filename,
                          std::to_string(ending_volume) + non_canonical_book_name));
    if (verbose) {
        std::cout << "Identified a bible book range.  Starting volume " << starting_volume << ", ending volume "
                  << ending_volume << ", book is \"" << non_canonical_book_name << "\".\n";
    }

    const std::string first_book_code(MapBibleBookToCode(verbose, starting_bible_book_candidate,
                                                         books_of_the_bible_to_code_map_filename));
    const std::string second_book_code(MapBibleBookToCode(verbose, ending_bible_book_candidate,
                                                          books_of_the_bible_to_code_map_filename));

    std::cout << (first_book_code + std::string(BibleReferenceParser::MAX_CHAPTER_LENGTH
                                                + BibleReferenceParser::MAX_VERSE_LENGTH, '0'))
              << (generate_solr_query ? '_' : ':')
              << (second_book_code + std::string(BibleReferenceParser::MAX_CHAPTER_LENGTH
                                                 + BibleReferenceParser::MAX_VERSE_LENGTH, '9'))
              << '\n';

    std::exit(EXIT_SUCCESS);
}

void HandleOrdinaryReferences(const bool verbose, const bool generate_solr_query,
                              std::string bible_reference_candidate,
                              const std::string &bible_books_to_codes_map_filename,
                              const std::string &books_of_the_bible_to_canonical_form_map_filename)
{
    bible_reference_candidate = CanoniseLeadingNumber(InsertSpaceAtFirstLetterDigitBoundary(
                                    StringUtil::RemoveChars(" \t", &bible_reference_candidate)));
    std::string book_candidate, chapters_and_verses_candidate;
    SplitIntoBookAndChaptersAndVerses(bible_reference_candidate, &book_candidate, &chapters_and_verses_candidate);
    if (verbose) {
        std::cerr << "book_candidate = \"" << book_candidate << "\"\n";
        std::cerr << "chapters_and_verses_candidate = \"" << chapters_and_verses_candidate << "\"\n";
    }

    book_candidate = CanoniseBibleBook(verbose, books_of_the_bible_to_canonical_form_map_filename, book_candidate);
    const std::string book_code(MapBibleBookToCode(verbose, book_candidate, bible_books_to_codes_map_filename));
    if (verbose)
        std::cerr << "book code = \"" << book_code << "\"\n";
    if (chapters_and_verses_candidate.empty()) {
        std::cout << book_code
                  << std::string(BibleReferenceParser::MAX_CHAPTER_LENGTH
                                 + BibleReferenceParser::MAX_VERSE_LENGTH, '0')
                  << (generate_solr_query ? '_' : ':') << book_code
                  << std::string(BibleReferenceParser::MAX_CHAPTER_LENGTH
                                 + BibleReferenceParser::MAX_VERSE_LENGTH, '9')
                  << '\n';

        std::exit(EXIT_SUCCESS);
    }

    std::set<std::pair<std::string, std::string>> start_end;
    if (not BibleReferenceParser::ParseBibleReference(chapters_and_verses_candidate, book_code, &start_end)) {
        if (verbose)
            std::cerr << "The parsing of \"" << chapters_and_verses_candidate
                      << "\" as chapters and verses failed!\n";
        std::exit(EXIT_FAILURE);
    }

    std::string query;
    for (const auto &pair : start_end) {
        if (generate_solr_query) {
            if (not query.empty())
                query += ' ';
            query += pair.first + "_" + pair.second;
        } else
            std::cout << pair.first << ':' << pair.second << '\n';
    }
    if (generate_solr_query)
        std::cout << query << '\n';
}

static void Usage() __attribute__((noreturn));

static void Usage() {
    std::cerr << "usage: " << progname << " [--debug|--query] bible_reference_candidate\n";
    std::cerr << "          books_of_the_bible_to_code_map\n";
    std::cerr << "          books_of_the_bible_to_canonical_form_map pericopes_to_codes_map\n";
    std::cerr << '\n';
    std::cerr << "          When --debug has been specified additional tracing output will be generated.\n";
    std::cerr << "          When --query has been specified SOLR search queries will be output.\n";
    std::exit(EXIT_FAILURE);
}

int main(int argc, char **argv) {
    ::progname = argv[0];

    bool verbose(false), generate_solr_query(false);

    if (argc == 6) {
        if (std::strcmp(argv[1], "--debug") == 0)
            verbose = true;
        else if (std::strcmp(argv[1], "--query") == 0)
            generate_solr_query = true;
        else
            Usage();
        ++argv, --argc;
    }

    if (argc != 5)
        Usage();

    const std::string books_of_the_bible_to_code_map_filename(argv[2]);
    const std::string books_of_the_bible_to_canonical_form_map_filename(argv[3]);
    std::string bible_reference_candidate(StringUtil::Trim(StringUtil::ToLower(argv[1])));
    StringUtil::CollapseWhitespace(&bible_reference_candidate);

    HandleBookRanges(verbose, generate_solr_query, books_of_the_bible_to_canonical_form_map_filename,
                     books_of_the_bible_to_code_map_filename, bible_reference_candidate);
    HandlePericopes(verbose, generate_solr_query, bible_reference_candidate, argv[4]);
    HandleOrdinaryReferences(verbose, generate_solr_query, bible_reference_candidate,
                             books_of_the_bible_to_code_map_filename,
                             books_of_the_bible_to_canonical_form_map_filename);
}
<|endoftext|>


<commit_before>/** \brief Utility for deleting partial or entire MARC records based on an input list.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *  \documentation https://wiki.bsz-bw.de/doku.php?id=v-team:daten:datendienste:sekkor under "Löschungen".
 *
 *  \copyright 2015-2020 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <memory>
#include <vector>
#include <cstdlib>
#include "BSZUtil.h"
#include "DbConnection.h"
#include "FileUtil.h"
#include "MARC.h"
#include "StringUtil.h"
#include "UBTools.h"
#include "util.h"

namespace {

[[noreturn]] void Usage() {
    ::Usage("[--input-format=(marc-21|marc-xml)] [--output-format=(marc-21|marc-xml)]"
            " deletion_list input_marc21 output_marc21 entire_record_deletion_log\n"
            "Record ID's of records that were deleted and not merely modified will be written to \"entire_record_deletion_log\".");
}

/** \brief Deletes LOK sections from the local data database if their pseudo tags are found in "local_deletion_ids"
 */
void DeleteLocalSections(DbConnection * const db_connection, const std::unordered_set <std::string> &local_deletion_ids,
                         const std::string &ppn)
{
    db_connection->queryOrDie("SELECT local_fields FROM local_data WHERE ppn = "
                              + db_connection->escapeAndQuoteString(ppn));
    auto result_set(db_connection->getLastResultSet());
    if (result_set.empty())
        return; // Nothing to be done!

    const auto row(result_set.getNextRow());
    const auto local_fields_blob(row["local_fields"]);

    size_t processed_size(0);
    bool keep_section;
    std::string new_local_fields_blob;
    do {
        // Convert the 4 character hex string to size of the following field contents:
        const size_t field_contents_size(StringUtil::ToUnsignedLong(local_fields_blob.substr(processed_size, 4), 16));
        processed_size += 4;

        if (unlikely(processed_size + field_contents_size > local_fields_blob.size()))
            LOG_ERROR("Inconsitent blob length for record with PPN " + ppn);

        const MARC::Record::Field local_field(local_fields_blob.substr(processed_size, field_contents_size));
        const auto pseudo_tag_and_data(local_field.getFirstSubfieldWithCode('0'));
        if (StringUtil::StartsWith(pseudo_tag_and_data, "001 "))
            keep_section = local_deletion_ids.find(pseudo_tag_and_data.substr(4)) != local_deletion_ids.cend();

        if (keep_section)
            new_local_fields_blob += local_fields_blob.substr(processed_size - 4, 4 + field_contents_size);

        processed_size += field_contents_size;
    } while (processed_size < local_fields_blob.size());

    if (new_local_fields_blob.size() < local_fields_blob.size()) {
        if (new_local_fields_blob.empty())
            db_connection->queryOrDie("DELETE FROM local_data WHERE ppn = "
                                      + db_connection->escapeAndQuoteString(ppn));
        else
            db_connection->queryOrDie("REPLACE INTO local_data (ppn, local_fields) VALUES("
                                      + db_connection->escapeAndQuoteString(ppn) + ","
                                      + db_connection->sqliteEscapeBlobData(new_local_fields_blob) + ")");
    }
}

void ProcessRecords(DbConnection * const db_connection, const std::unordered_set <std::string> &title_deletion_ids,
                    const std::unordered_set <std::string> &local_deletion_ids, MARC::Reader * const marc_reader,
                    MARC::Writer * const marc_writer, File * const entire_record_deletion_log)
{
    unsigned total_record_count(0), deleted_record_count(0);
    while (MARC::Record record = marc_reader->read()) {
        ++total_record_count;

        if (title_deletion_ids.find(record.getControlNumber()) != title_deletion_ids.end()) {
            ++deleted_record_count;
            (*entire_record_deletion_log) << record.getControlNumber() << '\n';
        } else
            marc_writer->write(record);

        if (not local_deletion_ids.empty())
            DeleteLocalSections(db_connection, local_deletion_ids, record.getControlNumber());
    }

    LOG_INFO("Read " + std::to_string(total_record_count) + " records.");
    LOG_INFO("Deleted " + std::to_string(deleted_record_count) + " records.");
}

} // unnamed namespace

int Main(int argc, char *argv[]) {
    if (argc < 5)
        Usage();

    const auto reader_type(MARC::GetOptionalReaderType(&argc, &argv, 1));
    const auto writer_type(MARC::GetOptionalWriterType(&argc, &argv, 1));

    if (argc != 5)
        Usage();

    const auto deletion_list(FileUtil::OpenInputFileOrDie(argv[1]));
    std::unordered_set<std::string> title_deletion_ids, local_deletion_ids;
    BSZUtil::ExtractDeletionIds(deletion_list.get(), &title_deletion_ids, &local_deletion_ids);

    DbConnection db_connection(UBTools::GetTuelibPath() + "local_data.sq3", DbConnection::READWRITE);

    const auto marc_reader(MARC::Reader::Factory(argv[2], reader_type));
    const auto marc_writer(MARC::Writer::Factory(argv[3], writer_type));
    const auto entire_record_deletion_log(FileUtil::OpenForAppendingOrDie(argv[4]));

    ProcessRecords(&db_connection,title_deletion_ids, local_deletion_ids, marc_reader.get(), marc_writer.get(), entire_record_deletion_log.get());

    return EXIT_SUCCESS;
}
<commit_msg>Comment fix<commit_after>/** \brief Utility for deleting partial or entire MARC records based on an input list.
 *  \author Dr. Johannes Ruscheinski (johannes.ruscheinski@uni-tuebingen.de)
 *  \documentation https://wiki.bsz-bw.de/doku.php?id=v-team:daten:datendienste:sekkor under "Löschungen".
 *
 *  \copyright 2015-2020 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <memory>
#include <vector>
#include <cstdlib>
#include "BSZUtil.h"
#include "DbConnection.h"
#include "FileUtil.h"
#include "MARC.h"
#include "StringUtil.h"
#include "UBTools.h"
#include "util.h"

namespace {

[[noreturn]] void Usage() {
    ::Usage("[--input-format=(marc-21|marc-xml)] [--output-format=(marc-21|marc-xml)]"
            " deletion_list input_marc21 output_marc21 entire_record_deletion_log\n"
            "Record ID's of records that were deleted and not merely modified will be written to \"entire_record_deletion_log\".");
}

/** \brief Deletes LOK sections from the local data database if their pseudo tags are found in "local_deletion_ids"
 */
void DeleteLocalSections(DbConnection * const db_connection, const std::unordered_set <std::string> &local_deletion_ids,
                         const std::string &ppn)
{
    db_connection->queryOrDie("SELECT local_fields FROM local_data WHERE ppn = "
                              + db_connection->escapeAndQuoteString(ppn));
    auto result_set(db_connection->getLastResultSet());
    if (result_set.empty())
        return; // Nothing to be done!

    const auto row(result_set.getNextRow());
    const auto local_fields_blob(row["local_fields"]);

    size_t processed_size(0);
    bool keep_section;
    std::string new_local_fields_blob;
    do {
        // Convert the 4 character hex string to the size of the following field contents:
        const size_t field_contents_size(StringUtil::ToUnsignedLong(local_fields_blob.substr(processed_size, 4), 16));
        processed_size += 4;

        if (unlikely(processed_size + field_contents_size > local_fields_blob.size()))
            LOG_ERROR("Inconsitent blob length for record with PPN " + ppn);

        const MARC::Record::Field local_field(local_fields_blob.substr(processed_size, field_contents_size));
        const auto pseudo_tag_and_data(local_field.getFirstSubfieldWithCode('0'));
        if (StringUtil::StartsWith(pseudo_tag_and_data, "001 "))
            keep_section = local_deletion_ids.find(pseudo_tag_and_data.substr(4)) != local_deletion_ids.cend();

        if (keep_section)
            new_local_fields_blob += local_fields_blob.substr(processed_size - 4, 4 + field_contents_size);

        processed_size += field_contents_size;
    } while (processed_size < local_fields_blob.size());

    if (new_local_fields_blob.size() < local_fields_blob.size()) {
        if (new_local_fields_blob.empty())
            db_connection->queryOrDie("DELETE FROM local_data WHERE ppn = "
                                      + db_connection->escapeAndQuoteString(ppn));
        else
            db_connection->queryOrDie("REPLACE INTO local_data (ppn, local_fields) VALUES("
                                      + db_connection->escapeAndQuoteString(ppn) + ","
                                      + db_connection->sqliteEscapeBlobData(new_local_fields_blob) + ")");
    }
}

void ProcessRecords(DbConnection * const db_connection, const std::unordered_set <std::string> &title_deletion_ids,
                    const std::unordered_set <std::string> &local_deletion_ids, MARC::Reader * const marc_reader,
                    MARC::Writer * const marc_writer, File * const entire_record_deletion_log)
{
    unsigned total_record_count(0), deleted_record_count(0);
    while (MARC::Record record = marc_reader->read()) {
        ++total_record_count;

        if (title_deletion_ids.find(record.getControlNumber()) != title_deletion_ids.end()) {
            ++deleted_record_count;
            (*entire_record_deletion_log) << record.getControlNumber() << '\n';
        } else
            marc_writer->write(record);

        if (not local_deletion_ids.empty())
            DeleteLocalSections(db_connection, local_deletion_ids, record.getControlNumber());
    }

    LOG_INFO("Read " + std::to_string(total_record_count) + " records.");
    LOG_INFO("Deleted " + std::to_string(deleted_record_count) + " records.");
}

} // unnamed namespace

int Main(int argc, char *argv[]) {
    if (argc < 5)
        Usage();

    const auto reader_type(MARC::GetOptionalReaderType(&argc, &argv, 1));
    const auto writer_type(MARC::GetOptionalWriterType(&argc, &argv, 1));

    if (argc != 5)
        Usage();

    const auto deletion_list(FileUtil::OpenInputFileOrDie(argv[1]));
    std::unordered_set<std::string> title_deletion_ids, local_deletion_ids;
    BSZUtil::ExtractDeletionIds(deletion_list.get(), &title_deletion_ids, &local_deletion_ids);

    DbConnection db_connection(UBTools::GetTuelibPath() + "local_data.sq3", DbConnection::READWRITE);

    const auto marc_reader(MARC::Reader::Factory(argv[2], reader_type));
    const auto marc_writer(MARC::Writer::Factory(argv[3], writer_type));
    const auto entire_record_deletion_log(FileUtil::OpenForAppendingOrDie(argv[4]));

    ProcessRecords(&db_connection,title_deletion_ids, local_deletion_ids, marc_reader.get(), marc_writer.get(), entire_record_deletion_log.get());

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: environment.hxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: kz $ $Date: 2007-05-09 13:35:05 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _UNO_ENVIRONMENT_HXX_
#define _UNO_ENVIRONMENT_HXX_

#ifndef _RTL_ALLOC_H_
#include <rtl/alloc.h>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif
#ifndef _UNO_ENVIRONMENT_H_
#include <uno/environment.h>
#endif

#include "uno/lbnames.h"

/** */ //for docpp
namespace com
{
/** */ //for docpp
namespace sun
{
/** */ //for docpp
namespace star
{
/** */ //for docpp
namespace uno
{

/** C++ wrapper for binary C uno_Environment.

    @see uno_Environment
*/
class Environment
{
    /** binary C uno_Environment
    */
    uno_Environment * _pEnv;

public:
    /** Returns the current Environment.

        @param env_type   the optional type of the Environment, falls back to "uno" in case being empty,
                          respectively to current C++ Environment.
        @since UDK 3.2.7
    */
    inline static Environment getCurrent(rtl::OUString const & typeName = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(CPPU_STRINGIFY(CPPU_ENV)))) SAL_THROW( () );

    // these are here to force memory de/allocation to sal lib.
    /** @internal */
    inline static void * SAL_CALL operator new ( size_t nSize ) SAL_THROW( () )
        { return ::rtl_allocateMemory( nSize ); }
    /** @internal */
    inline static void SAL_CALL operator delete ( void * pMem ) SAL_THROW( () )
        { ::rtl_freeMemory( pMem ); }
    /** @internal */
    inline static void * SAL_CALL operator new ( size_t, void * pMem ) SAL_THROW( () )
        { return pMem; }
    /** @internal */
    inline static void SAL_CALL operator delete ( void *, void * ) SAL_THROW( () )
        {}

    /** Constructor: acquires given environment

        @param pEnv environment
    */
    inline Environment( uno_Environment * pEnv = 0 ) SAL_THROW( () );

    /** Gets a specific environment. If the specified environment does not exist, then a default one
        is created and registered.

        @param envDcp           descriptor of the environment
        @param pContext         context pointer
    */
    inline explicit Environment( rtl::OUString const & envDcp, void * pContext = NULL ) SAL_THROW( () );

    /** Copy constructor: acquires given environment

        @param rEnv another environment
    */
    inline Environment( const Environment & rEnv ) SAL_THROW( () );

    /** Destructor: releases a set environment.
    */
    inline ~Environment() SAL_THROW( () );

    /** Sets a given environment, i.e. acquires given one and releases a set one.

        @param pEnv another environment
        @return this environment
    */
    inline Environment & SAL_CALL operator = ( uno_Environment * pEnv ) SAL_THROW( () );
    /** Sets a given environment, i.e. acquires given one and releases a set one.

        @param rEnv another environment
        @return this environment
    */
    inline Environment & SAL_CALL operator = ( const Environment & rEnv ) SAL_THROW( () )
        { return operator = ( rEnv._pEnv ); }

    /** Provides UNacquired pointer to the set C environment.

        @return UNacquired pointer to the C environment struct
    */
    inline uno_Environment * SAL_CALL get() const SAL_THROW( () )
        { return _pEnv; }

    /** Gets type name of set environment.

        @return type name of set environment
    */
    inline ::rtl::OUString SAL_CALL getTypeName() const SAL_THROW( () )
        { return _pEnv->pTypeName; }

    /** Gets free context pointer of set environment.

        @return free context pointer of set environment
    */
    inline void * SAL_CALL getContext() const SAL_THROW( () )
        { return _pEnv->pContext; }

    /** Tests if a environment is set.

        @return true, if a environment is set, false otherwise
    */
    inline sal_Bool SAL_CALL is() const SAL_THROW( () )
        { return (_pEnv != 0); }

    /** Releases a set environment.
    */
    inline void SAL_CALL clear() SAL_THROW( () );

    /** Invoke the passed function in this environment.

        @param pCallee  the function to call
        @param param    the parameter pointer to be passed to the function
        @since UDK 3.2.7
    */
    inline void SAL_CALL invoke_v(uno_EnvCallee * pCallee, va_list param) const SAL_THROW( () );

    /** Invoke the passed function in this environment.

        @param pCallee  the function to call
        @param ...      the parameters to be passed to the function
        @since UDK 3.2.7
    */
    inline void SAL_CALL invoke(uno_EnvCallee * pCallee, ...) const SAL_THROW( () );

    /** Enter this environment explicitly.

        @since UDK 3.2.7
    */
    inline void SAL_CALL enter() const SAL_THROW( () );

    /** Checks, if it is valid to currently call objects
        belonging to this environment.

        @since UDK 3.2.7
    */
    inline int  SAL_CALL isValid(rtl::OUString * pReason) const SAL_THROW( () );
};
//__________________________________________________________________________________________________
inline Environment::Environment( uno_Environment * pEnv ) SAL_THROW( () )
    : _pEnv( pEnv )
{
    if (_pEnv)
        (*_pEnv->acquire)( _pEnv );
}
//__________________________________________________________________________________________________
inline Environment::Environment( rtl::OUString const & rEnvDcp, void * pContext ) SAL_THROW( () )
    : _pEnv(NULL)
{
    uno_getEnvironment(&_pEnv, rEnvDcp.pData, pContext);
}
//__________________________________________________________________________________________________
inline Environment::Environment( const Environment & rEnv ) SAL_THROW( () )
    : _pEnv( rEnv._pEnv )
{
    if (_pEnv)
        (*_pEnv->acquire)( _pEnv );
}
//__________________________________________________________________________________________________
inline Environment::~Environment() SAL_THROW( () )
{
    if (_pEnv)
        (*_pEnv->release)( _pEnv );
}
//__________________________________________________________________________________________________
inline void Environment::clear() SAL_THROW( () )
{
    if (_pEnv)
    {
        (*_pEnv->release)( _pEnv );
        _pEnv = 0;
    }
}
//__________________________________________________________________________________________________
inline Environment & Environment::operator = ( uno_Environment * pEnv ) SAL_THROW( () )
{
    if (pEnv != _pEnv)
    {
        if (pEnv)
            (*pEnv->acquire)( pEnv );
        if (_pEnv)
            (*_pEnv->release)( _pEnv );
        _pEnv = pEnv;
    }
    return *this;
}
//__________________________________________________________________________________________________
inline void SAL_CALL Environment::invoke_v(uno_EnvCallee * pCallee, va_list param) const SAL_THROW( () )
{
    if (_pEnv)
        uno_Environment_invoke_v(_pEnv, pCallee, param);
}
//__________________________________________________________________________________________________
inline void SAL_CALL Environment::invoke(uno_EnvCallee * pCallee, ...) const SAL_THROW( () )
{
    if (_pEnv)
    {
        va_list param;

        va_start(param, pCallee);
        uno_Environment_invoke_v(_pEnv, pCallee, param);
        va_end(param);
    }

}
//__________________________________________________________________________________________________
inline void SAL_CALL Environment::enter() const SAL_THROW( () )
{
    uno_Environment_enter(_pEnv);
}
//__________________________________________________________________________________________________
inline int  SAL_CALL Environment::isValid(rtl::OUString * pReason) const SAL_THROW( () )
{
    return uno_Environment_isValid(_pEnv, (rtl_uString **)pReason);
}
//__________________________________________________________________________________________________
inline Environment Environment::getCurrent(rtl::OUString const & typeName) SAL_THROW( () )
{
    Environment environment;

    uno_Environment * pEnv = NULL;
    uno_getCurrentEnvironment(&pEnv, typeName.pData);
    environment = pEnv;
    if (pEnv)
        pEnv->release(pEnv);

    return environment;
}

}
}
}
}

#endif
<commit_msg>INTEGRATION: CWS unomacli64 (1.8.2); FILE MERGED 2007/06/05 15:00:52 kr 1.8.2.1: #i77422# Use va_list * instead of plain type<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: environment.hxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: obo $ $Date: 2007-07-18 12:20:30 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _UNO_ENVIRONMENT_HXX_
#define _UNO_ENVIRONMENT_HXX_

#ifndef _RTL_ALLOC_H_
#include <rtl/alloc.h>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif
#ifndef _UNO_ENVIRONMENT_H_
#include <uno/environment.h>
#endif

#include "uno/lbnames.h"

/** */ //for docpp
namespace com
{
/** */ //for docpp
namespace sun
{
/** */ //for docpp
namespace star
{
/** */ //for docpp
namespace uno
{

/** C++ wrapper for binary C uno_Environment.

    @see uno_Environment
*/
class Environment
{
    /** binary C uno_Environment
    */
    uno_Environment * _pEnv;

public:
    /** Returns the current Environment.

        @param env_type   the optional type of the Environment, falls back to "uno" in case being empty,
                          respectively to current C++ Environment.
        @since UDK 3.2.7
    */
    inline static Environment getCurrent(rtl::OUString const & typeName = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(CPPU_STRINGIFY(CPPU_ENV)))) SAL_THROW( () );

    // these are here to force memory de/allocation to sal lib.
    /** @internal */
    inline static void * SAL_CALL operator new ( size_t nSize ) SAL_THROW( () )
        { return ::rtl_allocateMemory( nSize ); }
    /** @internal */
    inline static void SAL_CALL operator delete ( void * pMem ) SAL_THROW( () )
        { ::rtl_freeMemory( pMem ); }
    /** @internal */
    inline static void * SAL_CALL operator new ( size_t, void * pMem ) SAL_THROW( () )
        { return pMem; }
    /** @internal */
    inline static void SAL_CALL operator delete ( void *, void * ) SAL_THROW( () )
        {}

    /** Constructor: acquires given environment

        @param pEnv environment
    */
    inline Environment( uno_Environment * pEnv = 0 ) SAL_THROW( () );

    /** Gets a specific environment. If the specified environment does not exist, then a default one
        is created and registered.

        @param envDcp           descriptor of the environment
        @param pContext         context pointer
    */
    inline explicit Environment( rtl::OUString const & envDcp, void * pContext = NULL ) SAL_THROW( () );

    /** Copy constructor: acquires given environment

        @param rEnv another environment
    */
    inline Environment( const Environment & rEnv ) SAL_THROW( () );

    /** Destructor: releases a set environment.
    */
    inline ~Environment() SAL_THROW( () );

    /** Sets a given environment, i.e. acquires given one and releases a set one.

        @param pEnv another environment
        @return this environment
    */
    inline Environment & SAL_CALL operator = ( uno_Environment * pEnv ) SAL_THROW( () );
    /** Sets a given environment, i.e. acquires given one and releases a set one.

        @param rEnv another environment
        @return this environment
    */
    inline Environment & SAL_CALL operator = ( const Environment & rEnv ) SAL_THROW( () )
        { return operator = ( rEnv._pEnv ); }

    /** Provides UNacquired pointer to the set C environment.

        @return UNacquired pointer to the C environment struct
    */
    inline uno_Environment * SAL_CALL get() const SAL_THROW( () )
        { return _pEnv; }

    /** Gets type name of set environment.

        @return type name of set environment
    */
    inline ::rtl::OUString SAL_CALL getTypeName() const SAL_THROW( () )
        { return _pEnv->pTypeName; }

    /** Gets free context pointer of set environment.

        @return free context pointer of set environment
    */
    inline void * SAL_CALL getContext() const SAL_THROW( () )
        { return _pEnv->pContext; }

    /** Tests if a environment is set.

        @return true, if a environment is set, false otherwise
    */
    inline sal_Bool SAL_CALL is() const SAL_THROW( () )
        { return (_pEnv != 0); }

    /** Releases a set environment.
    */
    inline void SAL_CALL clear() SAL_THROW( () );

    /** Invoke the passed function in this environment.

        @param pCallee  the function to call
        @param pParam   the parameter pointer to be passed to the function
        @since UDK 3.2.7
    */
    inline void SAL_CALL invoke_v(uno_EnvCallee * pCallee, va_list * pParam) const SAL_THROW( () );

    /** Invoke the passed function in this environment.

        @param pCallee  the function to call
        @param ...      the parameters to be passed to the function
        @since UDK 3.2.7
    */
    inline void SAL_CALL invoke(uno_EnvCallee * pCallee, ...) const SAL_THROW( () );

    /** Enter this environment explicitly.

        @since UDK 3.2.7
    */
    inline void SAL_CALL enter() const SAL_THROW( () );

    /** Checks, if it is valid to currently call objects
        belonging to this environment.

        @since UDK 3.2.7
    */
    inline int  SAL_CALL isValid(rtl::OUString * pReason) const SAL_THROW( () );
};
//__________________________________________________________________________________________________
inline Environment::Environment( uno_Environment * pEnv ) SAL_THROW( () )
    : _pEnv( pEnv )
{
    if (_pEnv)
        (*_pEnv->acquire)( _pEnv );
}
//__________________________________________________________________________________________________
inline Environment::Environment( rtl::OUString const & rEnvDcp, void * pContext ) SAL_THROW( () )
    : _pEnv(NULL)
{
    uno_getEnvironment(&_pEnv, rEnvDcp.pData, pContext);
}
//__________________________________________________________________________________________________
inline Environment::Environment( const Environment & rEnv ) SAL_THROW( () )
    : _pEnv( rEnv._pEnv )
{
    if (_pEnv)
        (*_pEnv->acquire)( _pEnv );
}
//__________________________________________________________________________________________________
inline Environment::~Environment() SAL_THROW( () )
{
    if (_pEnv)
        (*_pEnv->release)( _pEnv );
}
//__________________________________________________________________________________________________
inline void Environment::clear() SAL_THROW( () )
{
    if (_pEnv)
    {
        (*_pEnv->release)( _pEnv );
        _pEnv = 0;
    }
}
//__________________________________________________________________________________________________
inline Environment & Environment::operator = ( uno_Environment * pEnv ) SAL_THROW( () )
{
    if (pEnv != _pEnv)
    {
        if (pEnv)
            (*pEnv->acquire)( pEnv );
        if (_pEnv)
            (*_pEnv->release)( _pEnv );
        _pEnv = pEnv;
    }
    return *this;
}
//__________________________________________________________________________________________________
inline void SAL_CALL Environment::invoke_v(uno_EnvCallee * pCallee, va_list * pParam) const SAL_THROW( () )
{
    if (_pEnv)
        uno_Environment_invoke_v(_pEnv, pCallee, pParam);
}
//__________________________________________________________________________________________________
inline void SAL_CALL Environment::invoke(uno_EnvCallee * pCallee, ...) const SAL_THROW( () )
{
    if (_pEnv)
    {
        va_list param;

        va_start(param, pCallee);
        uno_Environment_invoke_v(_pEnv, pCallee, &param);
        va_end(param);
    }

}
//__________________________________________________________________________________________________
inline void SAL_CALL Environment::enter() const SAL_THROW( () )
{
    uno_Environment_enter(_pEnv);
}
//__________________________________________________________________________________________________
inline int  SAL_CALL Environment::isValid(rtl::OUString * pReason) const SAL_THROW( () )
{
    return uno_Environment_isValid(_pEnv, (rtl_uString **)pReason);
}
//__________________________________________________________________________________________________
inline Environment Environment::getCurrent(rtl::OUString const & typeName) SAL_THROW( () )
{
    Environment environment;

    uno_Environment * pEnv = NULL;
    uno_getCurrentEnvironment(&pEnv, typeName.pData);
    environment = pEnv;
    if (pEnv)
        pEnv->release(pEnv);

    return environment;
}

}
}
}
}

#endif
<|endoftext|>


<commit_before>/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2002  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library 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
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

// Here are the virtual ports use to display messages from the bioses :
//
//  0x0400 : rombios Panic port with message
//  0x0401 : rombios Panic port with line number
//  0x0402 : rombios Info port with message
//  0xfff0 : rombios Info port with message (legacy port)
//  0x0403 : rombios Debug port with message
//
//  0x0500 : vgabios Info port with message
//  0x0501 : vgabios Panic port with message
//  0x0502 : vgabios Panic port with line number
//  0x0503 : vgabios Debug port with message

// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE

#include "bochs.h"

bx_biosdev_c *theBiosDevice;

  int
libbiosdev_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
  theBiosDevice = new bx_biosdev_c ();
  bx_devices.pluginBiosDevice = theBiosDevice;
  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theBiosDevice, BX_PLUGIN_BIOSDEV);
  return(0); // Success
}

  void
libbiosdev_LTX_plugin_fini(void)
{
}

logfunctions  *bioslog;
logfunctions  *vgabioslog;

bx_biosdev_c::bx_biosdev_c(void)
{
  bioslog = new logfunctions();
  bioslog->put("BIOS");
  bioslog->settype(BIOSLOG);
  s.bios_message_i = 0;

  vgabioslog = new logfunctions();
  vgabioslog->put("VBIOS");
  vgabioslog->settype(BIOSLOG);
  s.vgabios_message_i = 0;
}

bx_biosdev_c::~bx_biosdev_c(void)
{
    if ( bioslog != NULL )
    {
        delete bioslog;
        bioslog = NULL;
    }

    if ( vgabioslog != NULL )
    {
        delete vgabioslog;
        vgabioslog = NULL;
    }
}

  void
bx_biosdev_c::init(void)
{
  DEV_register_iowrite_handler(this, write_handler, 0x0400, "Bios Panic Port 1", 3);
  DEV_register_iowrite_handler(this, write_handler, 0x0401, "Bios Panic Port 2", 3);
  DEV_register_iowrite_handler(this, write_handler, 0x0403, "Bios Debug Port", 1);
  DEV_register_iowrite_handler(this, write_handler, 0x0402, "Bios Info Port", 1);
  DEV_register_iowrite_handler(this, write_handler, 0xfff0, "Bios Info Port (legacy)", 1);

  DEV_register_iowrite_handler(this, write_handler, 0x0501, "VGABios Panic Port 1", 3);
  DEV_register_iowrite_handler(this, write_handler, 0x0502, "VGABios Panic Port 2", 3);
  DEV_register_iowrite_handler(this, write_handler, 0x0503, "VGABios Debug Port", 1);
  DEV_register_iowrite_handler(this, write_handler, 0x0500, "VGABios Info Port", 1);
}

  void
bx_biosdev_c::reset(unsigned type)
{
}

  // static IO port write callback handler
  // redirects to non-static class handler to avoid virtual functions

  void
bx_biosdev_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_BIOS_SMF
  bx_biosdev_c *class_ptr = (bx_biosdev_c *) this_ptr;

  class_ptr->write(address, value, io_len);
}

  void
bx_biosdev_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
  UNUSED(this_ptr);
#endif  // !BX_USE_BIOS_SMF
  UNUSED(io_len);

  switch (address) {
    // 0x400-0x401 are used as panic ports for the rombios
    case 0x0401:
      if (BX_BIOS_THIS s.bios_message_i > 0) {
	// if there are bits of message in the buffer, print them as the
	// panic message.  Otherwise fall into the next case.
	if (BX_BIOS_THIS s.bios_message_i >= BX_BIOS_MESSAGE_SIZE)
	  BX_BIOS_THIS s.bios_message_i = BX_BIOS_MESSAGE_SIZE-1;
        BX_BIOS_THIS s.bios_message[ BX_BIOS_THIS s.bios_message_i] = 0;
	BX_BIOS_THIS s.bios_message_i = 0;
        bioslog->panic("%s", BX_BIOS_THIS s.bios_message);
	break;
      }
    case 0x0400:
      bioslog->panic("BIOS panic at rombios.c, line %d", value);
      break;

    // 0xfff0 is used as the info port for the rombios
    // 0x0402 is used as the info port for the rombios
    // 0x0403 is used as the debug port for the rombios
    case 0xfff0:
    case 0x0402:
    case 0x0403:
      BX_BIOS_THIS s.bios_message[BX_BIOS_THIS s.bios_message_i] =
        (Bit8u) value;
      BX_BIOS_THIS s.bios_message_i ++;
      if ( BX_BIOS_THIS s.bios_message_i >= BX_BIOS_MESSAGE_SIZE ) {
        BX_BIOS_THIS s.bios_message[ BX_BIOS_MESSAGE_SIZE - 1] = 0;
        BX_BIOS_THIS s.bios_message_i = 0;
	if (address==0x403) bioslog->ldebug("%s", BX_BIOS_THIS s.bios_message);
	else bioslog->info("%s", BX_BIOS_THIS s.bios_message);
	}
      else if ((value & 0xff) == '\n') {
        BX_BIOS_THIS s.bios_message[ BX_BIOS_THIS s.bios_message_i - 1 ] = 0;
        BX_BIOS_THIS s.bios_message_i = 0;
	if (address==0x403) bioslog->ldebug("%s", BX_BIOS_THIS s.bios_message);
	else bioslog->info("%s", BX_BIOS_THIS s.bios_message);
        }
      break;

    // 0x501-0x502 are used as panic ports for the vgabios
    case 0x0502:
      if (BX_BIOS_THIS s.vgabios_message_i > 0) {
	// if there are bits of message in the buffer, print them as the
	// panic message.  Otherwise fall into the next case.
	if (BX_BIOS_THIS s.vgabios_message_i >= BX_BIOS_MESSAGE_SIZE)
	  BX_BIOS_THIS s.vgabios_message_i = BX_BIOS_MESSAGE_SIZE-1;
        BX_BIOS_THIS s.vgabios_message[ BX_BIOS_THIS s.vgabios_message_i] = 0;
	BX_BIOS_THIS s.vgabios_message_i = 0;
        vgabioslog->panic("%s", BX_BIOS_THIS s.vgabios_message);
	break;
      }
    case 0x0501:
      vgabioslog->panic("BIOS panic at rombios.c, line %d", value);
      break;

    // 0x0500 is used as the message port for the vgabios
    case 0x0500:
    case 0x0503:
      BX_BIOS_THIS s.vgabios_message[BX_BIOS_THIS s.vgabios_message_i] =
        (Bit8u) value;
      BX_BIOS_THIS s.vgabios_message_i ++;
      if ( BX_BIOS_THIS s.vgabios_message_i >= BX_BIOS_MESSAGE_SIZE ) {
        BX_BIOS_THIS s.vgabios_message[ BX_BIOS_MESSAGE_SIZE - 1] = 0;
        BX_BIOS_THIS s.vgabios_message_i = 0;
        if (address==0x503) vgabioslog->ldebug("%s", BX_BIOS_THIS s.vgabios_message);
        else vgabioslog->info("%s", BX_BIOS_THIS s.vgabios_message);
        }
      else if ((value & 0xff) == '\n') {
        BX_BIOS_THIS s.vgabios_message[ BX_BIOS_THIS s.vgabios_message_i - 1 ] = 0;
        BX_BIOS_THIS s.vgabios_message_i = 0;
        if (address==0x503) vgabioslog->ldebug("%s", BX_BIOS_THIS s.vgabios_message);
        else vgabioslog->info("%s", BX_BIOS_THIS s.vgabios_message);
        }
      break;

    default:
	    break;
    }
}
<commit_msg>Applied patch to remove 0xfff0 legacy port.<commit_after>/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2002  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library 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
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

// Here are the virtual ports use to display messages from the bioses :
//
//  0x0400 : rombios Panic port with message
//  0x0401 : rombios Panic port with line number
//  0x0402 : rombios Info port with message
//  0x0403 : rombios Debug port with message
//
//  0x0500 : vgabios Info port with message
//  0x0501 : vgabios Panic port with message
//  0x0502 : vgabios Panic port with line number
//  0x0503 : vgabios Debug port with message

// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE

#include "bochs.h"

bx_biosdev_c *theBiosDevice;

  int
libbiosdev_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
  theBiosDevice = new bx_biosdev_c ();
  bx_devices.pluginBiosDevice = theBiosDevice;
  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theBiosDevice, BX_PLUGIN_BIOSDEV);
  return(0); // Success
}

  void
libbiosdev_LTX_plugin_fini(void)
{
}

logfunctions  *bioslog;
logfunctions  *vgabioslog;

bx_biosdev_c::bx_biosdev_c(void)
{
  bioslog = new logfunctions();
  bioslog->put("BIOS");
  bioslog->settype(BIOSLOG);
  s.bios_message_i = 0;

  vgabioslog = new logfunctions();
  vgabioslog->put("VBIOS");
  vgabioslog->settype(BIOSLOG);
  s.vgabios_message_i = 0;
}

bx_biosdev_c::~bx_biosdev_c(void)
{
    if ( bioslog != NULL )
    {
        delete bioslog;
        bioslog = NULL;
    }

    if ( vgabioslog != NULL )
    {
        delete vgabioslog;
        vgabioslog = NULL;
    }
}

  void
bx_biosdev_c::init(void)
{
  DEV_register_iowrite_handler(this, write_handler, 0x0400, "Bios Panic Port 1", 3);
  DEV_register_iowrite_handler(this, write_handler, 0x0401, "Bios Panic Port 2", 3);
  DEV_register_iowrite_handler(this, write_handler, 0x0403, "Bios Debug Port", 1);
  DEV_register_iowrite_handler(this, write_handler, 0x0402, "Bios Info Port", 1);

  DEV_register_iowrite_handler(this, write_handler, 0x0501, "VGABios Panic Port 1", 3);
  DEV_register_iowrite_handler(this, write_handler, 0x0502, "VGABios Panic Port 2", 3);
  DEV_register_iowrite_handler(this, write_handler, 0x0503, "VGABios Debug Port", 1);
  DEV_register_iowrite_handler(this, write_handler, 0x0500, "VGABios Info Port", 1);
}

  void
bx_biosdev_c::reset(unsigned type)
{
}

  // static IO port write callback handler
  // redirects to non-static class handler to avoid virtual functions

  void
bx_biosdev_c::write_handler(void *this_ptr, Bit32u address, Bit32u value, unsigned io_len)
{
#if !BX_USE_BIOS_SMF
  bx_biosdev_c *class_ptr = (bx_biosdev_c *) this_ptr;

  class_ptr->write(address, value, io_len);
}

  void
bx_biosdev_c::write(Bit32u address, Bit32u value, unsigned io_len)
{
#else
  UNUSED(this_ptr);
#endif  // !BX_USE_BIOS_SMF
  UNUSED(io_len);

  switch (address) {
    // 0x400-0x401 are used as panic ports for the rombios
    case 0x0401:
      if (BX_BIOS_THIS s.bios_message_i > 0) {
	// if there are bits of message in the buffer, print them as the
	// panic message.  Otherwise fall into the next case.
	if (BX_BIOS_THIS s.bios_message_i >= BX_BIOS_MESSAGE_SIZE)
	  BX_BIOS_THIS s.bios_message_i = BX_BIOS_MESSAGE_SIZE-1;
        BX_BIOS_THIS s.bios_message[ BX_BIOS_THIS s.bios_message_i] = 0;
	BX_BIOS_THIS s.bios_message_i = 0;
        bioslog->panic("%s", BX_BIOS_THIS s.bios_message);
	break;
      }
    case 0x0400:
      bioslog->panic("BIOS panic at rombios.c, line %d", value);
      break;

    // 0x0402 is used as the info port for the rombios
    // 0x0403 is used as the debug port for the rombios
    case 0x0402:
    case 0x0403:
      BX_BIOS_THIS s.bios_message[BX_BIOS_THIS s.bios_message_i] =
        (Bit8u) value;
      BX_BIOS_THIS s.bios_message_i ++;
      if ( BX_BIOS_THIS s.bios_message_i >= BX_BIOS_MESSAGE_SIZE ) {
        BX_BIOS_THIS s.bios_message[ BX_BIOS_MESSAGE_SIZE - 1] = 0;
        BX_BIOS_THIS s.bios_message_i = 0;
	if (address==0x403) bioslog->ldebug("%s", BX_BIOS_THIS s.bios_message);
	else bioslog->info("%s", BX_BIOS_THIS s.bios_message);
	}
      else if ((value & 0xff) == '\n') {
        BX_BIOS_THIS s.bios_message[ BX_BIOS_THIS s.bios_message_i - 1 ] = 0;
        BX_BIOS_THIS s.bios_message_i = 0;
	if (address==0x403) bioslog->ldebug("%s", BX_BIOS_THIS s.bios_message);
	else bioslog->info("%s", BX_BIOS_THIS s.bios_message);
        }
      break;

    // 0x501-0x502 are used as panic ports for the vgabios
    case 0x0502:
      if (BX_BIOS_THIS s.vgabios_message_i > 0) {
	// if there are bits of message in the buffer, print them as the
	// panic message.  Otherwise fall into the next case.
	if (BX_BIOS_THIS s.vgabios_message_i >= BX_BIOS_MESSAGE_SIZE)
	  BX_BIOS_THIS s.vgabios_message_i = BX_BIOS_MESSAGE_SIZE-1;
        BX_BIOS_THIS s.vgabios_message[ BX_BIOS_THIS s.vgabios_message_i] = 0;
	BX_BIOS_THIS s.vgabios_message_i = 0;
        vgabioslog->panic("%s", BX_BIOS_THIS s.vgabios_message);
	break;
      }
    case 0x0501:
      vgabioslog->panic("BIOS panic at rombios.c, line %d", value);
      break;

    // 0x0500 is used as the message port for the vgabios
    case 0x0500:
    case 0x0503:
      BX_BIOS_THIS s.vgabios_message[BX_BIOS_THIS s.vgabios_message_i] =
        (Bit8u) value;
      BX_BIOS_THIS s.vgabios_message_i ++;
      if ( BX_BIOS_THIS s.vgabios_message_i >= BX_BIOS_MESSAGE_SIZE ) {
        BX_BIOS_THIS s.vgabios_message[ BX_BIOS_MESSAGE_SIZE - 1] = 0;
        BX_BIOS_THIS s.vgabios_message_i = 0;
        if (address==0x503) vgabioslog->ldebug("%s", BX_BIOS_THIS s.vgabios_message);
        else vgabioslog->info("%s", BX_BIOS_THIS s.vgabios_message);
        }
      else if ((value & 0xff) == '\n') {
        BX_BIOS_THIS s.vgabios_message[ BX_BIOS_THIS s.vgabios_message_i - 1 ] = 0;
        BX_BIOS_THIS s.vgabios_message_i = 0;
        if (address==0x503) vgabioslog->ldebug("%s", BX_BIOS_THIS s.vgabios_message);
        else vgabioslog->info("%s", BX_BIOS_THIS s.vgabios_message);
        }
      break;

    default:
	    break;
    }
}
<|endoftext|>


<commit_before>#include "file/fd_util.h"

#include <errno.h>
#include <math.h>
#include <stdio.h>
#ifndef _WIN32
#include <unistd.h>
#else
#include <io.h>
#include <winsock2.h>
#endif
#include <fcntl.h>

#include "base/logging.h"

namespace fd_util {

// Slow as hell and should only be used for prototyping.
// Reads from a socket, up to an '\n'. This means that if the line ends
// with '\r', the '\r' will be returned.
ssize_t ReadLine(int fd, char *vptr, size_t buf_size) {
  char *buffer = vptr;
  size_t n;
  for (n = 1; n < buf_size; n++) {
    char c;
    ssize_t rc;
    if ((rc = read(fd, &c, 1)) == 1) {
      *buffer++ = c;
      if (c == '\n')
        break;
    }
    else if (rc == 0) {
      if (n == 1)
        return 0;
      else
        break;
    }
    else {
      if (errno == EINTR)
        continue;
      FLOG("Error in Readline()");
    }
  }

  *buffer = 0;
  return n;
}

// Misnamed, it just writes raw data in a retry loop.
ssize_t WriteLine(int fd, const char *vptr, size_t n) {
  const char *buffer = vptr;
  size_t nleft = n;

  while (nleft > 0) {
    ssize_t nwritten;
    if ((nwritten = write(fd, buffer, nleft)) <= 0) {
      if (errno == EINTR)
        nwritten = 0;
      else
        FLOG("Error in Writeline()");
    }
    nleft  -= nwritten;
    buffer += nwritten;
  }

  return n;
}

ssize_t WriteLine(int fd, const char *buffer) {
  return WriteLine(fd, buffer, strlen(buffer));
}

ssize_t Write(int fd, const std::string &str) {
  return WriteLine(fd, str.c_str(), str.size());
}

bool WaitUntilReady(int fd, double timeout) {
  struct timeval tv;
  tv.tv_sec = floor(timeout);
  tv.tv_usec = (timeout - floor(timeout)) * 1000000.0;

  fd_set fds;
  FD_ZERO(&fds);
  FD_SET(fd, &fds);
  // First argument to select is the highest socket in the set + 1.
  int rval = select(fd + 1, &fds, NULL, NULL, &tv);
  if (rval < 0) {
    // Error calling select.
    return false;
  } else if (rval == 0) {
    // Timeout.
    return false;
  } else {
    // Socket is ready.
    return true;
  }
}

void SetNonBlocking(int sock, bool non_blocking) {
#ifndef _WIN32
	int opts = fcntl(sock, F_GETFL);
  if (opts < 0) {
		perror("fcntl(F_GETFL)");
		exit(EXIT_FAILURE);
	}
	if (non_blocking) {
    opts = (opts | O_NONBLOCK);
  } else {
    opts = (opts & ~O_NONBLOCK);
  }

	if (fcntl(sock, F_SETFL, opts) < 0) {
		perror("fcntl(F_SETFL)");
		exit(EXIT_FAILURE);
	}
#else
  WLOG("NonBlocking mode not supported on Win32");
#endif
}

}  // fd_util
<commit_msg>Add missing sys/time.h include to fd_util.cpp<commit_after>#include "file/fd_util.h"

#include <errno.h>
#include <math.h>
#include <stdio.h>
#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
#else
#include <io.h>
#include <winsock2.h>
#endif
#include <fcntl.h>

#include "base/logging.h"

namespace fd_util {

// Slow as hell and should only be used for prototyping.
// Reads from a socket, up to an '\n'. This means that if the line ends
// with '\r', the '\r' will be returned.
ssize_t ReadLine(int fd, char *vptr, size_t buf_size) {
  char *buffer = vptr;
  size_t n;
  for (n = 1; n < buf_size; n++) {
    char c;
    ssize_t rc;
    if ((rc = read(fd, &c, 1)) == 1) {
      *buffer++ = c;
      if (c == '\n')
        break;
    }
    else if (rc == 0) {
      if (n == 1)
        return 0;
      else
        break;
    }
    else {
      if (errno == EINTR)
        continue;
      FLOG("Error in Readline()");
    }
  }

  *buffer = 0;
  return n;
}

// Misnamed, it just writes raw data in a retry loop.
ssize_t WriteLine(int fd, const char *vptr, size_t n) {
  const char *buffer = vptr;
  size_t nleft = n;

  while (nleft > 0) {
    ssize_t nwritten;
    if ((nwritten = write(fd, buffer, nleft)) <= 0) {
      if (errno == EINTR)
        nwritten = 0;
      else
        FLOG("Error in Writeline()");
    }
    nleft  -= nwritten;
    buffer += nwritten;
  }

  return n;
}

ssize_t WriteLine(int fd, const char *buffer) {
  return WriteLine(fd, buffer, strlen(buffer));
}

ssize_t Write(int fd, const std::string &str) {
  return WriteLine(fd, str.c_str(), str.size());
}

bool WaitUntilReady(int fd, double timeout) {
  struct timeval tv;
  tv.tv_sec = floor(timeout);
  tv.tv_usec = (timeout - floor(timeout)) * 1000000.0;

  fd_set fds;
  FD_ZERO(&fds);
  FD_SET(fd, &fds);
  // First argument to select is the highest socket in the set + 1.
  int rval = select(fd + 1, &fds, NULL, NULL, &tv);
  if (rval < 0) {
    // Error calling select.
    return false;
  } else if (rval == 0) {
    // Timeout.
    return false;
  } else {
    // Socket is ready.
    return true;
  }
}

void SetNonBlocking(int sock, bool non_blocking) {
#ifndef _WIN32
	int opts = fcntl(sock, F_GETFL);
  if (opts < 0) {
		perror("fcntl(F_GETFL)");
		exit(EXIT_FAILURE);
	}
	if (non_blocking) {
    opts = (opts | O_NONBLOCK);
  } else {
    opts = (opts & ~O_NONBLOCK);
  }

	if (fcntl(sock, F_SETFL, opts) < 0) {
		perror("fcntl(F_SETFL)");
		exit(EXIT_FAILURE);
	}
#else
  WLOG("NonBlocking mode not supported on Win32");
#endif
}

}  // fd_util
<|endoftext|>