<commit_before>/*
 * Copyright (c) 2015 ARM. All rights reserved.
 */
#include "mbed-net-sockets/UDPSocket.h"
#include "EthernetInterface.h"
#include "test_env.h"
#include "lwm2m-client/m2minterfacefactory.h"
#include "lwm2m-client/m2minterfaceobserver.h"
#include "lwm2m-client/m2mdevice.h"
#include "lwm2m-client/m2mobjectinstance.h"
#include "lwm2m-client/m2minterface.h"
#include "testconfig.h"

// TODO: Remove when yotta supports init.
#include "lwipv4_init.h"

const String &MANUFACTURER = "ARM";
const String &TYPE = "type";

// Dynamic resource variables
const String &DYNAMIC_RESOURCE_NAME = "Dynamic";
const String &DYNAMIC_RESOURCE_TYPE = "DynamicType";
const String &STATIC_RESOURCE_NAME = "Static";
const String &STATIC_RESOURCE_TYPE = "StaticType";
const uint8_t STATIC_VALUE[] = "Static value";

class M2MLWClient: public M2MInterfaceObserver {
public:
    M2MLWClient(TestConfig *test_config){
        _interface = NULL;
        _register_security = NULL;
        _resource_object = NULL;
        _bootstrapped = false;
        _error = false;
        _registered = false;
        _unregistered = false;
        _registration_updated = false;
        _resource_value = 0;
        _object = NULL;
        _test_config = test_config;
    }

    virtual ~M2MLWClient() {
        if(_interface) {
            delete _interface;
        }
        if( _register_security){
            delete _register_security;
        }
    }

    bool create_interface() {
    	bool success = false;
         // Creates M2MInterface using which endpoint can
         // setup its name, resource type, life time, connection mode,
         // Currently only LwIPv4 is supported.
         _interface = M2MInterfaceFactory::create_interface( *this,
												   _test_config->get_endpoint_name(),
												   _test_config->get_endpoint_type(),
												   _test_config->get_lifetime(),
												   _test_config->get_port(),
                                                   "",
                                                   M2MInterface::UDP,
                                                   M2MInterface::LwIP_IPv4,
                                                   "");
         if (_interface) {
        	 success = true;
         }

         return success;
    }

    bool bootstrap_successful() {
        return _bootstrapped;
    }

    M2MSecurity* create_bootstrap_object() {
        // Creates bootstrap server object with Bootstrap server address and other parameters
        // required for client to connect to bootstrap server.
        M2MSecurity *security = M2MInterfaceFactory::create_security(M2MSecurity::Bootstrap);
        if(security) {
            security->set_resource_value(M2MSecurity::M2MServerUri, _test_config->get_bootstrap_server());
            security->set_resource_value(M2MSecurity::SecurityMode, M2MSecurity::NoSecurity);
        }
        return security;
    }

    void test_bootstrap(M2MSecurity *security) {
        if(_interface) {
             // Bootstrap function.
            _interface->bootstrap(security);
        }
    }

    bool register_successful() {
        return _registered;
    }

    bool unregister_successful() {
        return _unregistered;
    }

    bool update_register_successful() {
        return _registration_updated;
    }

    M2MSecurity* create_register_object() {
        // Creates server object with LWM2M server address and other parameters
        // required for client to connect to LWM2M server.
        M2MSecurity *security = M2MInterfaceFactory::create_security(M2MSecurity::M2MServer);
        if(security) {
            security->set_resource_value(M2MSecurity::M2MServerUri, _test_config->get_mds_server());
            security->set_resource_value(M2MSecurity::SecurityMode, M2MSecurity::NoSecurity);
        }
        return security;
    }

    void test_register(M2MObjectList object_list){
        if(_interface) {
            // Register function
            _interface->register_object(_register_security, object_list);
        }
    }

    bool test_update_register(const uint32_t lifetime)
    {
        bool success = false;
        if(_interface && _register_security) {
            success = true;
            _interface->update_registration(_register_security,lifetime);
        }
        return success;
    }

    void test_unregister(){
    	if(_interface) {
    		// Unregister function
    		_interface->unregister_object(NULL);
    	}
    }

    void set_register_object(M2MSecurity *&register_object){
        if(_register_security) {
            delete _register_security;
            _register_security = NULL;
        }
        _register_security = register_object;
    }

    M2MDevice* create_device_object() {
    	M2MDevice *device = M2MInterfaceFactory::create_device();
    	if (device) {
    		device->create_resource(M2MDevice::Manufacturer, MANUFACTURER);
    		device->create_resource(M2MDevice::DeviceType, TYPE);
    	}
    	return device;
    }

    M2MObject* create_generic_object() {
        _object = M2MInterfaceFactory::create_object("Test");
        if(_object) {
            M2MObjectInstance* inst = _object->create_object_instance();
            if(inst) {
                    M2MResource* res = inst->create_dynamic_resource("D","ResourceTest",true);
                    char buffer[20];
                    int size = sprintf(buffer,"%d",_resource_value);
                    res->set_operation(M2MBase::GET_PUT_POST_ALLOWED);
                    res->set_value((const uint8_t*)buffer,
                                   (const uint32_t)size,
                                   true);
                    _resource_value++;

                    inst->create_static_resource("S",
                                                 "ResourceTest",
                                                 STATIC_VALUE,
                                                 sizeof(STATIC_VALUE)-1);
            }
        }
        return _object;
    }

    //Callback from mbed client stack when the bootstrap
    // is successful, it returns the mbed Device Server object
    // which will be used for registering the resources to
    // mbed Device server.
    void bootstrap_done(M2MSecurity *server_object){
    	if(server_object) {
            _bootstrapped = true;
            _error = false;
        }
    }

    //Callback from mbed client stack when the registration
    // is successful, it returns the mbed Device Server object
    // to which the resources are registered and registered objects.
    void object_registered(M2MSecurity */*security_object*/, const M2MServer &/*server_object*/){
        _registered = true;
        _unregistered = false;
    }

    //Callback from mbed client stack when the registration update
        // is successful, it returns the mbed Device Server object
        // to which the resources are registered and registered objects.
    void registration_updated(M2MSecurity */*security_object*/, const M2MServer &/*server_object*/){
            _registration_updated = true;
        }

    //Callback from mbed client stack when the unregistration
    // is successful, it returns the mbed Device Server object
    // to which the resources were unregistered.
    void object_unregistered(M2MSecurity */*server_object*/){
        _unregistered = true;
        _registered = false;
    }

    //Callback from mbed client stack if any value has changed
    // during PUT operation. Object and its type is passed in
    // the callback.
    void value_updated(M2MBase *base, M2MBase::BaseType type) {
        printf("\nValue updated of Object name %s and Type %d\n",
               base->name().c_str(), type);
    }

    //Callback from mbed client stack if any error is encountered
    // during any of the LWM2M operations. Error type is passed in
    // the callback.
    void error(M2MInterface::Error error){
        _error = true;
        printf("\nError occured %d\n", error);
    }

private:

    M2MInterface    	*_interface;
    M2MSecurity         *_register_security;
    M2MObject			*_resource_object;
    M2MObject           *_object;
    volatile bool       _bootstrapped;
    volatile bool       _error;
    volatile bool       _registered;
    volatile bool       _unregistered;
    volatile bool       _registration_updated;
    int                 _resource_value;
    TestConfig			*_test_config;
};

#define SUITE_TEST_INFO(test_name, info)		printf("Suite-%s: %s\n", test_name, info)
#define SUITE_TEST_RESULT(test_name, result)	printf("Suite-%s: result %s\n", test_name, result ? "pass" : "fail")
#define SUITE_RESULT(result)					printf("Suite: result %s\n", result ? "success" : "failure")

bool test_bootstrap(TestConfig *test_config) {
	SUITE_TEST_INFO("test_bootstrap", "started");

	bool interface_success = false;
	bool bootstrap_success = false;

    // Instantiate the class which implements
    // LWM2M Client API
    M2MLWClient *lwm2mclient = new M2MLWClient(test_config);

    SUITE_TEST_INFO("test_bootstrap", "client done");

    // Create LWM2M Client API interface to manage bootstrap,
    // register and unregister
    interface_success = lwm2mclient->create_interface();

    // Create LWM2M bootstrap object specifying bootstrap server
    // information.
    M2MSecurity* security_object = lwm2mclient->create_bootstrap_object();

    // Issue bootstrap command.
    lwm2mclient->test_bootstrap(security_object);

    SUITE_TEST_INFO("test_bootstrap", "bootstrap done");
    // Wait till the bootstrap callback is called successfully.
    // Callback comes in bootstrap_done()
    while (!(bootstrap_success = lwm2mclient->bootstrap_successful())) { __WFI(); }

    // Delete security object created for bootstrapping
    if(security_object) {
        delete security_object;
    }

    if (lwm2mclient) {
    	delete lwm2mclient;
    }

    SUITE_TEST_RESULT("test_bootstrap", interface_success && bootstrap_success);
    return interface_success && bootstrap_success;
}

int main() {
	bool result = true;

    MBED_HOSTTEST_TIMEOUT(20);
    MBED_HOSTTEST_SELECT(lwm2mclient_auto);
    MBED_HOSTTEST_DESCRIPTION(LWM2MClient Happy Day Test);
    MBED_HOSTTEST_START("LWM2MClientHappyDayTest");

    // This sets up the network interface configuration which will be used
    // by LWM2M Client API to communicate with mbed Device server.
    EthernetInterface eth;
    eth.init(); //Use DHCP
    eth.connect();

    lwipv4_socket_init();

    // Create test config object, and setup with unique MAC address
    TestConfig test_config;
    test_config.setup(eth.getMACAddress());

    result &= test_bootstrap(&test_config);
    result &= test_bootstrap(&test_config);
    result &= test_bootstrap(&test_config);
    result &= test_bootstrap(&test_config);
    result &= test_bootstrap(&test_config);
    result &= test_bootstrap(&test_config);

    SUITE_RESULT(result);
}

<commit_msg>Added rest of the cases to allInOne suite.<commit_after>/*
 * Copyright (c) 2015 ARM. All rights reserved.
 */
#include "mbed-net-sockets/UDPSocket.h"
#include "EthernetInterface.h"
#include "test_env.h"
#include "lwm2m-client/m2minterfacefactory.h"
#include "lwm2m-client/m2minterfaceobserver.h"
#include "lwm2m-client/m2mdevice.h"
#include "lwm2m-client/m2mobjectinstance.h"
#include "lwm2m-client/m2minterface.h"
#include "testconfig.h"

// TODO: Remove when yotta supports init.
#include "lwipv4_init.h"

const String &MANUFACTURER = "ARM";
const String &TYPE = "type";

// Dynamic resource variables
const String &DYNAMIC_RESOURCE_NAME = "Dynamic";
const String &DYNAMIC_RESOURCE_TYPE = "DynamicType";
const String &STATIC_RESOURCE_NAME = "Static";
const String &STATIC_RESOURCE_TYPE = "StaticType";
const uint8_t STATIC_VALUE[] = "Static value";

class M2MLWClient: public M2MInterfaceObserver {
public:
    M2MLWClient(TestConfig *test_config){
        _interface = NULL;
        _register_security = NULL;
        _resource_object = NULL;
        _bootstrapped = false;
        _error = false;
        _registered = false;
        _unregistered = false;
        _registration_updated = false;
        _resource_value = 0;
        _object = NULL;
        _test_config = test_config;
    }

    virtual ~M2MLWClient() {
        if(_interface) {
            delete _interface;
        }
        if( _register_security){
            delete _register_security;
        }
    }

    bool create_interface() {
    	bool success = false;
         // Creates M2MInterface using which endpoint can
         // setup its name, resource type, life time, connection mode,
         // Currently only LwIPv4 is supported.
         _interface = M2MInterfaceFactory::create_interface( *this,
												   _test_config->get_endpoint_name(),
												   _test_config->get_endpoint_type(),
												   _test_config->get_lifetime(),
												   _test_config->get_port(),
                                                   "",
                                                   M2MInterface::UDP,
                                                   M2MInterface::LwIP_IPv4,
                                                   "");
         if (_interface) {
        	 success = true;
         }

         return success;
    }

    bool bootstrap_successful() {
        return _bootstrapped;
    }

    M2MSecurity* create_bootstrap_object() {
        // Creates bootstrap server object with Bootstrap server address and other parameters
        // required for client to connect to bootstrap server.
        M2MSecurity *security = M2MInterfaceFactory::create_security(M2MSecurity::Bootstrap);
        if(security) {
            security->set_resource_value(M2MSecurity::M2MServerUri, _test_config->get_bootstrap_server());
            security->set_resource_value(M2MSecurity::SecurityMode, M2MSecurity::NoSecurity);
        }
        return security;
    }

    void test_bootstrap(M2MSecurity *security) {
        if(_interface) {
             // Bootstrap function.
            _interface->bootstrap(security);
        }
    }

    bool register_successful() {
        return _registered;
    }

    bool unregister_successful() {
        return _unregistered;
    }

    bool update_register_successful() {
        return _registration_updated;
    }

    M2MSecurity* create_register_object() {
        // Creates server object with LWM2M server address and other parameters
        // required for client to connect to LWM2M server.
        M2MSecurity *security = M2MInterfaceFactory::create_security(M2MSecurity::M2MServer);
        if(security) {
            security->set_resource_value(M2MSecurity::M2MServerUri, _test_config->get_mds_server());
            security->set_resource_value(M2MSecurity::SecurityMode, M2MSecurity::NoSecurity);
        }
        return security;
    }

    void test_register(M2MObjectList object_list){
        if(_interface) {
            // Register function
            _interface->register_object(_register_security, object_list);
        }
    }

    bool test_update_register(const uint32_t lifetime)
    {
        bool success = false;
        if(_interface && _register_security) {
            success = true;
            _interface->update_registration(_register_security,lifetime);
        }
        return success;
    }

    void test_unregister(){
    	if(_interface) {
    		// Unregister function
    		_interface->unregister_object(NULL);
    	}
    }

    void set_register_object(M2MSecurity *&register_object){
        if(_register_security) {
            delete _register_security;
            _register_security = NULL;
        }
        _register_security = register_object;
    }

    M2MDevice* create_device_object() {
    	M2MDevice *device = M2MInterfaceFactory::create_device();
    	if (device) {
    		device->create_resource(M2MDevice::Manufacturer, MANUFACTURER);
    		device->create_resource(M2MDevice::DeviceType, TYPE);
    	}
    	return device;
    }

    M2MObject* create_generic_object() {
        _object = M2MInterfaceFactory::create_object("Test");
        if(_object) {
            M2MObjectInstance* inst = _object->create_object_instance();
            if(inst) {
                    M2MResource* res = inst->create_dynamic_resource("D","ResourceTest",true);
                    char buffer[20];
                    int size = sprintf(buffer,"%d",_resource_value);
                    res->set_operation(M2MBase::GET_PUT_POST_ALLOWED);
                    res->set_value((const uint8_t*)buffer,
                                   (const uint32_t)size,
                                   true);
                    _resource_value++;

                    inst->create_static_resource("S",
                                                 "ResourceTest",
                                                 STATIC_VALUE,
                                                 sizeof(STATIC_VALUE)-1);
            }
        }
        return _object;
    }

    //Callback from mbed client stack when the bootstrap
    // is successful, it returns the mbed Device Server object
    // which will be used for registering the resources to
    // mbed Device server.
    void bootstrap_done(M2MSecurity *server_object){
    	if(server_object) {
            _bootstrapped = true;
            _error = false;
        }
    }

    //Callback from mbed client stack when the registration
    // is successful, it returns the mbed Device Server object
    // to which the resources are registered and registered objects.
    void object_registered(M2MSecurity */*security_object*/, const M2MServer &/*server_object*/){
        _registered = true;
        _unregistered = false;
    }

    //Callback from mbed client stack when the registration update
        // is successful, it returns the mbed Device Server object
        // to which the resources are registered and registered objects.
    void registration_updated(M2MSecurity */*security_object*/, const M2MServer &/*server_object*/){
            _registration_updated = true;
        }

    //Callback from mbed client stack when the unregistration
    // is successful, it returns the mbed Device Server object
    // to which the resources were unregistered.
    void object_unregistered(M2MSecurity */*server_object*/){
        _unregistered = true;
        _registered = false;
    }

    //Callback from mbed client stack if any value has changed
    // during PUT operation. Object and its type is passed in
    // the callback.
    void value_updated(M2MBase *base, M2MBase::BaseType type) {
        printf("\nValue updated of Object name %s and Type %d\n",
               base->name().c_str(), type);
    }

    //Callback from mbed client stack if any error is encountered
    // during any of the LWM2M operations. Error type is passed in
    // the callback.
    void error(M2MInterface::Error error){
        _error = true;
        printf("\nError occured %d\n", error);
    }

private:

    M2MInterface    	*_interface;
    M2MSecurity         *_register_security;
    M2MObject			*_resource_object;
    M2MObject           *_object;
    volatile bool       _bootstrapped;
    volatile bool       _error;
    volatile bool       _registered;
    volatile bool       _unregistered;
    volatile bool       _registration_updated;
    int                 _resource_value;
    TestConfig			*_test_config;
};

#define SUITE_TEST_INFO(test_name, info)		printf("Suite-%s: %s\n", test_name, info)
#define SUITE_TEST_RESULT(test_name, result)	printf("Suite-%s: result %s\n", test_name, result ? "PASSED" : "FAILED")
#define SUITE_RESULT(result)					printf("Suite: result %s\n", result ? "success" : "failure")

bool test_bootStrap(TestConfig *test_config) {
	bool _result = true;
	const char* _tn = "test_bootStrap";

	SUITE_TEST_INFO(_tn, "STARTED");

    // Instantiate the class which implements
    // LWM2M Client API
    M2MLWClient *lwm2mclient = new M2MLWClient(test_config);

    SUITE_TEST_INFO(_tn, "client done");

    // Create LWM2M Client API interface to manage bootstrap,
    // register and unregister
    _result &= lwm2mclient->create_interface();

    // Create LWM2M bootstrap object specifying bootstrap server
    // information.
    M2MSecurity* security_object = lwm2mclient->create_bootstrap_object();

    // Issue bootstrap command.
    lwm2mclient->test_bootstrap(security_object);

    SUITE_TEST_INFO(_tn, "bootstrap done");
    // Wait till the bootstrap callback is called successfully.
    // Callback comes in bootstrap_done()
    while (!(_result &= lwm2mclient->bootstrap_successful())) { __WFI(); }

    // Delete security object created for bootstrapping
    if(security_object) {
        delete security_object;
    }

    if (lwm2mclient) {
    	delete lwm2mclient;
    }

    SUITE_TEST_RESULT(_tn, _result);
    return _result;
}

bool test_deviceObject(TestConfig *test_config) {
	bool _result = true;
	const char* _tn = "test_deviceObject";

	SUITE_TEST_INFO(_tn, "STARTED");

	// Instantiate the class which implements
    // LWM2M Client API
    M2MLWClient *lwm2mclient = new M2MLWClient(test_config);

    SUITE_TEST_INFO(_tn, "client done");

    // Create LWM2M Client API interface for M2M server
    _result &= lwm2mclient->create_interface();

    M2MSecurity *register_object = lwm2mclient->create_register_object();

    lwm2mclient->set_register_object(register_object);

    // Create LWM2M device object specifying device resources
    // as per OMA LWM2M specification.
    M2MDevice* device_object = lwm2mclient->create_device_object();

    // Add the device object that we want to register
    // into the list and pass the list for register API.
    M2MObjectList object_list;
    object_list.push_back(device_object);

    // Issue register command.
    lwm2mclient->test_register(object_list);

    SUITE_TEST_INFO(_tn, "register done");

	wait_ms(1000);

    // Wait till the register callback is called successfully.
    // Callback comes in object_registered()
    while (!(_result &= lwm2mclient->register_successful() ))
        { __WFI(); }

    SUITE_TEST_INFO(_tn, "register callback done");

    // Wait 5 seconds
	wait_ms(1000);

	//TODO move this to callback when that can be taken in use
	_result &= lwm2mclient->test_update_register(2222);

	SUITE_TEST_INFO(_tn, "update register done");

	// Wait till the register callback is called successfully.
    // Callback comes in object_updated()
	//while (!lwm2mclient.update_register_successful()) { __WFI(); }

	// Issue unregister command.
    lwm2mclient->test_unregister();

	SUITE_TEST_INFO(_tn, "unregister done");

    // Wait for the unregister successful callback,
    // Callback comes in object_unregistered().
    while (!(_result &= lwm2mclient->unregister_successful() ))
        { __WFI(); }

    SUITE_TEST_INFO(_tn, "unregister callback done");

    // Delete device object created for registering device
    // resources.
    if(device_object) {
        delete device_object;
    }

    if (lwm2mclient) {
    	delete lwm2mclient;
    }

	SUITE_TEST_RESULT(_tn, _result);
    return _result;

}

bool test_resource(TestConfig *test_config) {
	bool _result = true;
    const char* _tn = "test_resource";
	SUITE_TEST_INFO(_tn, "STARTED");

	// Instantiate the class which implements
    // LWM2M Client API

	//M2MLWClient *lwm2mclient;
    M2MLWClient *lwm2mclient = new M2MLWClient(test_config);

    SUITE_TEST_INFO(_tn, "client done");

    // Create LWM2M Client API interface for M2M server
    _result &= lwm2mclient->create_interface();

    M2MSecurity *register_object = lwm2mclient->create_register_object();

    lwm2mclient->set_register_object(register_object);

    // Create LWM2M device object specifying device resources
    // as per OMA LWM2M specification.
    M2MDevice* device_object = lwm2mclient->create_device_object();

    // Create LWM2M generic object for resource
    M2MObject* resource_object = lwm2mclient->create_generic_object();

    // Add the device object that we want to register
    // into the list and pass the list for register API.
    M2MObjectList object_list;
    object_list.push_back(device_object);
    object_list.push_back(resource_object);

    // Issue register command.
    lwm2mclient->test_register(object_list);

    SUITE_TEST_INFO(_tn, "register done");

    // Wait till the register callback is called successfully.
    // Callback comes in object_registered()

    //while (! lwm2mclient.register_successful()) { __WFI(); }
    while (!( _result &= lwm2mclient->register_successful() ))
        { __WFI(); }

    SUITE_TEST_INFO(_tn, "register callback done");

    // Wait 5 seconds
    wait_ms(5000);

    // Issue unregister command.
    lwm2mclient->test_unregister();

    SUITE_TEST_INFO(_tn, "unregister done");

    // Wait for the unregister successful callback,
    // Callback comes in object_unregistered().
    while (!( _result &= lwm2mclient->unregister_successful() ))
        { __WFI(); }

    SUITE_TEST_INFO(_tn, "unregister callback done");

    // Delete device object created for registering device
    // resources.
    if(device_object) {
        delete device_object;
    }

    // Delete resource object for registering resources.
    if(resource_object) {
    	delete resource_object;
    }

    if (lwm2mclient) {
    	delete lwm2mclient;
    }

	SUITE_TEST_RESULT(_tn, _result);
    return _result;
}

int main() {
	bool result = true;

    MBED_HOSTTEST_TIMEOUT(180);
    MBED_HOSTTEST_SELECT(lwm2mclient_auto);
    MBED_HOSTTEST_DESCRIPTION(LWM2MClient Happy Day Test);
    MBED_HOSTTEST_START("LWM2MClientHappyDayTest");

    // This sets up the network interface configuration which will be used
    // by LWM2M Client API to communicate with mbed Device server.
    EthernetInterface eth;
    eth.init(); //Use DHCP
    eth.connect();

    lwipv4_socket_init();

    // Create test config object, and setup with unique MAC address
    TestConfig test_config;
    test_config.setup(eth.getMACAddress());

    result &= test_bootStrap(&test_config);
    result &= test_deviceObject(&test_config);
    result &= test_resource(&test_config);

    // Disconnect and teardown the network interface
    eth.disconnect();

    // Communicate test result
    SUITE_RESULT(result);
}

<|endoftext|>


<commit_before>#include <algorithm>
#include <iostream>
#include <numeric>
#include <string_view>

#include "lib/split.h"

namespace {

int score(std::string_view sv) {
  return std::accumulate(
      sv.begin(),
      sv.end(),
      0,
      [](int total, char c) { return total + (c - 'A' + 1); });
}

bool triangle(std::string_view sv) {
  auto s = score(sv);
  for (int i = 1, n = 2; ; i += n, n++) {
    if (i == s) {
      return true;
    } else if (i > s) {
      return false;
    }
  }
}

}

int p42() {
  std::string data;
  std::getline(std::cin, data, '\n');
  auto words = split(data);
  return std::count_if(words.begin(), words.end(), triangle);
}
<commit_msg>p42: fix up triangle for loop condition<commit_after>#include <algorithm>
#include <iostream>
#include <numeric>
#include <string_view>

#include "lib/split.h"

namespace {

int score(std::string_view sv) {
  return std::accumulate(
      sv.begin(),
      sv.end(),
      0,
      [](int total, char c) { return total + (c - 'A' + 1); });
}

bool triangle(std::string_view sv) {
  auto s = score(sv);
  for (int i = 1, n = 2; i <= s; i += n, n++) {
    if (i == s) {
      return true;
    }
  }
  return false;
}

}

int p42() {
  std::string data;
  std::getline(std::cin, data, '\n');
  auto words = split(data);
  return std::count_if(words.begin(), words.end(), triangle);
}
<|endoftext|>


<commit_before>// $Id: peak.C,v 1.4 2000/09/07 19:38:31 oliver Exp $

#include<BALL/NMR/peak.h>
#include<BALL/MATHS/common.h>

using namespace std;

namespace BALL
{

	Peak1D::Peak1D()
	{
		value_ = 0;
		width_ = 0.1;
		height_ = 1;
		atom_ = 0;
	}

	Peak1D::Peak1D(const Peak1D& peak)
		: value_(peak.value_),
			width_(peak.width_),
			height_(peak.height_),
			atom_(peak.atom_)
	{
	}

	Peak1D::~Peak1D()
	{
	}

	float Peak1D::getValue() const
	{
		return value_;
	}

	float Peak1D::getWidth() const
	{
		return width_;
	}

	float Peak1D::getHeight() const
	{
		return height_;
	}

	const Atom* Peak1D::getAtom() const
	{
		return atom_;
	}

	void Peak1D::setValue(float value)
	{
		value_ = value;
	}

	void Peak1D::setWidth(float value)
	{
		width_ = value;
	}

	void Peak1D::setAtom(const Atom* atom)
	{
		atom_ = atom;
	}

	void Peak1D::setHeight(float value)
	{
		height_ = value;
	}

	void Peak1D::operator = (const Peak1D& peak)
	{
		value_ = peak.value_;
		width_ = peak.width_;
		height_ = peak.height_;
		atom_ = peak.atom_;
	}

	bool Peak1D::operator == (const Peak1D& peak) const
	{
		return Maths::isEqual(value_, peak.value_);
	}

	bool Peak1D::operator < (const Peak1D& peak) const
	{
		return Maths::isLess(value_, peak.value_);
	}

	ostream& operator << (ostream& os, const Peak1D& peak)
	{
		return os << peak.getValue();
	}

}	// namespace BALL
<commit_msg>overhaul of code<commit_after>// $Id: peak.C,v 1.5 2000/09/21 23:05:12 amoll Exp $

#include<BALL/NMR/peak.h>
#include<BALL/MATHS/common.h>

namespace BALL
{

	Peak1D::Peak1D()
		: value_(0),
			width_(0.1),
			height_(1),
			atom_(0)
	{
	}

	Peak1D::Peak1D(const Peak1D& peak)
		: value_(peak.value_),
			width_(peak.width_),
			height_(peak.height_),
			atom_(peak.atom_)
	{
	}

	Peak1D::~Peak1D()
	{
	}

	float Peak1D::getValue() const
	{
		return value_;
	}

	float Peak1D::getWidth() const
	{
		return width_;
	}

	float Peak1D::getHeight() const
	{
		return height_;
	}

	const Atom* Peak1D::getAtom() const
	{
		return atom_;
	}

	void Peak1D::setValue(float value)
	{
		value_ = value;
	}

	void Peak1D::setWidth(float value)
	{
		width_ = value;
	}

	void Peak1D::setAtom(const Atom* atom)
	{
		atom_ = atom;
	}

	void Peak1D::setHeight(float value)
	{
		height_ = value;
	}

	void Peak1D::operator = (const Peak1D& peak)
	{
		value_ = peak.value_;
		width_ = peak.width_;
		height_ = peak.height_;
		atom_ = peak.atom_;
	}

	bool Peak1D::operator == (const Peak1D& peak) const
	{
		return Maths::isEqual(value_, peak.value_);
	}

	bool Peak1D::operator < (const Peak1D& peak) const
	{
		return Maths::isLess(value_, peak.value_);
	}

	ostream& operator << (ostream& os, const Peak1D& peak)
	{
		return os << peak.getValue();
	}

}	// namespace BALL
<|endoftext|>


<commit_before>/** \file    add_synonyms.cc
 *  \brief   Generic version for augmenting title data with synonyms found
             in the authority data
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2016, 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/>.
*/

/*  We offer a list of tags and subfields where the primary data resides along
    with a list of tags and subfields where the synonym data is found and
    a list of unused fields in the title data where the synonyms can be stored
*/

#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "FileUtil.h"
#include "MarcReader.h"
#include "MarcRecord.h"
#include "MarcWriter.h"
#include "MediaTypeUtil.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

static unsigned modified_count(0);
static unsigned record_count(0);

void Usage() {
    std::cerr << "Usage: " << ::progname << " master_marc_input norm_data_marc_input marc_output\n";
    std::exit(EXIT_FAILURE);
}

std::string GetTag(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(0, 3);
}

std::string GetSubfieldCodes(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(3);
}

bool FilterPasses(const MarcRecord &record, const std::map<std::string, std::pair<std::string, std::string>> &filter_specs, std::string field_spec) {
      auto filter_spec = filter_specs.find(field_spec);
      if (filter_spec == filter_specs.cend())
          return true;

      auto rule = filter_spec->second;
      // We have field_spec in key and rule to match in value
      std::string subfield_value;
      std::string subfield_code = GetSubfieldCodes(rule.first);
      if(subfield_code.length() != 1)
         Error("Invalid subfield specification "  + subfield_code + " for filter");

      if ((subfield_value = record.extractFirstSubfield(GetTag(rule.first), subfield_code.c_str()[0])) == "")
          return false;

      return (subfield_value == rule.second) ? true : false;
}

void ExtractSynonyms(MarcReader * const authority_reader,
                     const std::set<std::string> &primary_tags_and_subfield_codes,
                     const std::set<std::string> &synonym_tags_and_subfield_codes,
                     std::vector<std::map<std::string, std::string>> * const synonym_maps,
                     const std::map<std::string, std::pair<std::string, std::string>> &filter_spec)
{
    while (const MarcRecord record = authority_reader->read()) {
        std::set<std::string>::const_iterator primary;
        std::set<std::string>::const_iterator synonym;
        unsigned int i(0);
        for (primary = primary_tags_and_subfield_codes.begin(), synonym = synonym_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++synonym, ++i)
        {
            // Fill maps with synonyms
            std::vector<std::string> primary_values;
            std::vector<std::string> synonym_values;

            if (FilterPasses(record, filter_spec, *primary) and
                record.extractSubfields(GetTag(*primary), GetSubfieldCodes(*primary), &primary_values) and
                record.extractSubfields(GetTag(*synonym), GetSubfieldCodes(*synonym), &synonym_values))
                    (*synonym_maps)[i].emplace(StringUtil::Join(primary_values, ','),
                                               StringUtil::Join(synonym_values, ','));
        }
    }
}

inline std::string GetMapValueOrEmptyString(const std::map<std::string, std::string> &map,
                                            const std::string &searchterm)
{
    auto value(map.find(searchterm));
    return (value != map.cend()) ? value->second : "";
}

void ProcessRecord(MarcRecord * const record, const std::vector<std::map<std::string, std::string>> &synonym_maps,
                   const std::set<std::string> &primary_tags_and_subfield_codes,
                   const std::set<std::string> &output_tags_and_subfield_codes)
{
    std::set<std::string>::const_iterator primary;
    std::set<std::string>::const_iterator output;
    unsigned int i(0);

    if (primary_tags_and_subfield_codes.size() == output_tags_and_subfield_codes.size()) {
        for (primary = primary_tags_and_subfield_codes.begin(), output = output_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++output, ++i)
        {
            std::vector<std::string> primary_values;
            std::set<std::string> synonym_values;
            std::vector<size_t> field_indices;
            if (record->getFieldIndices(GetTag(*primary), &field_indices) != MarcRecord::FIELD_NOT_FOUND) {
                for (auto field_index : field_indices) {
                     primary_values.clear();
                     if (record->getSubfields(field_index).extractSubfields(GetSubfieldCodes(*primary), &primary_values)) {
                        std::string searchterm = StringUtil::Join(primary_values, ',');
                        // First case: Look up synonyms only in one category
                        if (i < synonym_maps.size()) {
                            const auto &synonym_map(synonym_maps[i]);
                            const auto &synonym(GetMapValueOrEmptyString(synonym_map, searchterm));
                            if (not synonym.empty())
                                synonym_values.insert(synonym);
                        }

                        // Second case: Look up synonyms in all categories
                        else {
                            for (auto &sm : synonym_maps) {
                                const auto &synonym(GetMapValueOrEmptyString(sm, searchterm));
                                if (not synonym.empty())
                                   synonym_values.insert(synonym);
                            }
                        }
                    }
                 }

                if (synonym_values.empty())
                     continue;

                const std::string synonyms(StringUtil::Join(synonym_values, ','));

                // Insert synonyms
                // Abort if field is already populated
                std::string tag(GetTag(*output));
                if (record->getFieldIndex(tag) != MarcRecord::FIELD_NOT_FOUND)
                    Error("Field with tag " + tag + " is not empty for PPN " + record->getControlNumber() + '\n');
                std::string subfield_spec = GetSubfieldCodes(*output);
                if (subfield_spec.size() != 1)
                    Error("We currently only support a single subfield and thus specifying " + subfield_spec
                          + " as output subfield is not valid\n");
                Subfields subfields(' ', ' '); // <- indicators must be set explicitly although empty
                subfields.addSubfield(subfield_spec.at(0), synonyms);
                if (not(record->insertField(tag, subfields.toString())))
                    Warning("Could not insert field " + tag + " for PPN " + record->getControlNumber() + '\n');
                ++modified_count;
            }
        }
    }
}

void InsertSynonyms(MarcReader * const marc_reader, MarcWriter * const marc_writer,
                    const std::set<std::string> &primary_tags_and_subfield_codes,
                    const std::set<std::string> &output_tags_and_subfield_codes,
                    std::vector<std::map<std::string, std::string>> &synonym_maps)
{
    while (MarcRecord record = marc_reader->read()) {
        ProcessRecord(&record, synonym_maps, primary_tags_and_subfield_codes, output_tags_and_subfield_codes);
        marc_writer->write(record);
        ++record_count;
    }

    std::cerr << "Modified " << modified_count << " of " << record_count << " record(s).\n";
}

int ParseSpec(std::string spec_str, std::set<std::string> * field_specs, std::map<std::string, std::pair<std::string, std::string>> * filter_specs = nullptr) {
    std::set<std::string>  raw_field_specs;

    if (unlikely(StringUtil::Split(spec_str, ":", &raw_field_specs) < 1)){
        Error("Need at least one field");
        return -1;
    }

    if (filter_specs == nullptr) {
        *field_specs = raw_field_specs;
	return 0;
    }

    // Iterate over all Field-specs and extract possible filters
    static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactory("(\\d{1,3}[a-z]+)\\[(\\d{1,3}[a-z])=(.*)\\]"));

    for (auto field_spec : raw_field_specs) {
        if (matcher->matched(field_spec)){
            filter_specs->emplace((*matcher)[1], std::make_pair((*matcher)[2], (*matcher)[3]));
            auto bracket = field_spec.find("[");
            field_spec = (bracket != std::string::npos) ? field_spec.erase(bracket, field_spec.length()) : field_spec;
        }
        field_specs->insert(field_spec);
    }
    return 0;
}

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

    if (argc != 4)
        Usage();

    const std::string marc_input_filename(argv[1]);
    const std::string authority_data_marc_input_filename(argv[2]);
    const std::string marc_output_filename(argv[3]);
    if (unlikely(marc_input_filename == marc_output_filename))
        Error("Title data input file name equals output file name!");
    if (unlikely(authority_data_marc_input_filename == marc_output_filename))
        Error("Authority data input file name equals output file name!");

    std::unique_ptr<MarcReader> marc_reader(MarcReader::Factory(marc_input_filename, MarcReader::BINARY));
    std::unique_ptr<MarcReader> authority_reader(MarcReader::Factory(authority_data_marc_input_filename,
                                                                     MarcReader::BINARY));
    std::unique_ptr<MarcWriter> marc_writer(MarcWriter::Factory(marc_output_filename, MarcWriter::BINARY));

    try {
        // Determine possible mappings
        // Values in square brackets specify a positive criterion for values to be taken into account
        const std::string AUTHORITY_DATA_PRIMARY_SPEC("100abcd[079v=piz]:110abcd:111abcd:130abcd:150abcd:151abcd");
        const std::string AUTHORITY_DATA_SYNONYM_SPEC("400abcd:410abcd:411abcd:430abcd:450abcd:451abcd");
        const std::string TITLE_DATA_PRIMARY_SPEC("600abcd:610abcd:611abcd:630abcd:650abcd:651abcd:689abcd");
        const std::string TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS("180a:181a:182a:183a:184a:185a:186a");

        // Determine fields to handle
        std::set<std::string> primary_tags_and_subfield_codes;
        std::set<std::string> synonym_tags_and_subfield_codes;
        std::set<std::string> input_tags_and_subfield_codes;
        std::set<std::string> output_tags_and_subfield_codes;

        std::map<std::string, std::pair<std::string, std::string>> filter_specs;

        if (unlikely(ParseSpec(AUTHORITY_DATA_PRIMARY_SPEC, &primary_tags_and_subfield_codes, &filter_specs) < 0))
            Error("Could not properly parse " + AUTHORITY_DATA_PRIMARY_SPEC);

        if (unlikely(StringUtil::Split(AUTHORITY_DATA_SYNONYM_SPEC, ":", &synonym_tags_and_subfield_codes) < 1))
            Error("Need at least one synonym field");

        if (unlikely(StringUtil::Split(TITLE_DATA_PRIMARY_SPEC, ":", &input_tags_and_subfield_codes) < 1))
            Error("Need at least one input field");

        if (unlikely(StringUtil::Split(TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS, ":", &output_tags_and_subfield_codes)
                     < 1))
            Error("Need at least one output field");

        unsigned num_of_authority_entries(primary_tags_and_subfield_codes.size());

        if (synonym_tags_and_subfield_codes.size() != num_of_authority_entries)
            Error("Number of authority primary specs must match number of synonym specs");
        if (input_tags_and_subfield_codes.size() != output_tags_and_subfield_codes.size())
            Error("Number of fields title entry specs must match number of output specs");

        std::vector<std::map<std::string, std::string>> synonym_maps(num_of_authority_entries,
                                                                     std::map<std::string, std::string>());

        // Extract the synonyms from authority data
        ExtractSynonyms(authority_reader.get(), primary_tags_and_subfield_codes, synonym_tags_and_subfield_codes,
                        &synonym_maps, filter_specs);

        // Iterate over the title data
        InsertSynonyms(marc_reader.get(), marc_writer.get(), input_tags_and_subfield_codes,
                       output_tags_and_subfield_codes, synonym_maps);

    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<commit_msg>Required changes<commit_after>/** \file    add_synonyms.cc
 *  \brief   Generic version for augmenting title data with synonyms found
             in the authority data
 *  \author  Johannes Riedl
 */

/*
    Copyright (C) 2016, 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/>.
*/

/*  We offer a list of tags and subfields where the primary data resides along
    with a list of tags and subfields where the synonym data is found and
    a list of unused fields in the title data where the synonyms can be stored
*/

#include <iostream>
#include <map>
#include <vector>
#include <cstdlib>
#include "Compiler.h"
#include "FileUtil.h"
#include "MarcReader.h"
#include "MarcRecord.h"
#include "MarcWriter.h"
#include "MediaTypeUtil.h"
#include "RegexMatcher.h"
#include "StringUtil.h"
#include "Subfields.h"
#include "util.h"

static unsigned modified_count(0);
static unsigned record_count(0);

void Usage() {
    std::cerr << "Usage: " << ::progname << " master_marc_input norm_data_marc_input marc_output\n";
    std::exit(EXIT_FAILURE);
}

std::string GetTag(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(0, 3);
}

std::string GetSubfieldCodes(const std::string &tag_and_subfields_spec) {
    return tag_and_subfields_spec.substr(3);
}

bool FilterPasses(const MarcRecord &record, const std::map<std::string, std::pair<std::string, std::string>> &filter_specs, const std::string &field_spec) {
      auto filter_spec(filter_specs.find(field_spec));
      if (filter_spec == filter_specs.cend())
          return true;

      auto rule(filter_spec->second);
      // We have field_spec in key and rule to match in value
      std::string subfield_value;
      std::string subfield_codes(GetSubfieldCodes(rule.first));
      if (subfield_codes.length() != 1)
         Error("Invalid subfield specification "  + subfield_codes + " for filter");

      if ((subfield_value = record.extractFirstSubfield(GetTag(rule.first), subfield_codes.c_str()[0])).empty())
          return false;

      return subfield_value == rule.second;
}

void ExtractSynonyms(MarcReader * const authority_reader,
                     const std::set<std::string> &primary_tags_and_subfield_codes,
                     const std::set<std::string> &synonym_tags_and_subfield_codes,
                     std::vector<std::map<std::string, std::string>> * const synonym_maps,
                     const std::map<std::string, std::pair<std::string, std::string>> &filter_spec)
{
    while (const MarcRecord record = authority_reader->read()) {
        std::set<std::string>::const_iterator primary;
        std::set<std::string>::const_iterator synonym;
        unsigned int i(0);
        for (primary = primary_tags_and_subfield_codes.begin(), synonym = synonym_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++synonym, ++i)
        {
            // Fill maps with synonyms
            std::vector<std::string> primary_values;
            std::vector<std::string> synonym_values;

            if (FilterPasses(record, filter_spec, *primary) and
                record.extractSubfields(GetTag(*primary), GetSubfieldCodes(*primary), &primary_values) and
                record.extractSubfields(GetTag(*synonym), GetSubfieldCodes(*synonym), &synonym_values))
                    (*synonym_maps)[i].emplace(StringUtil::Join(primary_values, ','),
                                               StringUtil::Join(synonym_values, ','));
        }
    }
}

inline std::string GetMapValueOrEmptyString(const std::map<std::string, std::string> &map,
                                            const std::string &searchterm)
{
    auto value(map.find(searchterm));
    return (value != map.cend()) ? value->second : "";
}

void ProcessRecord(MarcRecord * const record, const std::vector<std::map<std::string, std::string>> &synonym_maps,
                   const std::set<std::string> &primary_tags_and_subfield_codes,
                   const std::set<std::string> &output_tags_and_subfield_codes)
{
    std::set<std::string>::const_iterator primary;
    std::set<std::string>::const_iterator output;
    unsigned int i(0);

    if (primary_tags_and_subfield_codes.size() == output_tags_and_subfield_codes.size()) {
        for (primary = primary_tags_and_subfield_codes.begin(), output = output_tags_and_subfield_codes.begin();
            primary != primary_tags_and_subfield_codes.end();
            ++primary, ++output, ++i)
        {
            std::vector<std::string> primary_values;
            std::set<std::string> synonym_values;
            std::vector<size_t> field_indices;
            if (record->getFieldIndices(GetTag(*primary), &field_indices) != MarcRecord::FIELD_NOT_FOUND) {
                for (auto field_index : field_indices) {
                     primary_values.clear();
                     if (record->getSubfields(field_index).extractSubfields(GetSubfieldCodes(*primary), &primary_values)) {
                        std::string searchterm = StringUtil::Join(primary_values, ',');
                        // First case: Look up synonyms only in one category
                        if (i < synonym_maps.size()) {
                            const auto &synonym_map(synonym_maps[i]);
                            const auto &synonym(GetMapValueOrEmptyString(synonym_map, searchterm));
                            if (not synonym.empty())
                                synonym_values.insert(synonym);
                        }

                        // Second case: Look up synonyms in all categories
                        else {
                            for (auto &sm : synonym_maps) {
                                const auto &synonym(GetMapValueOrEmptyString(sm, searchterm));
                                if (not synonym.empty())
                                   synonym_values.insert(synonym);
                            }
                        }
                    }
                 }

                if (synonym_values.empty())
                     continue;

                const std::string synonyms(StringUtil::Join(synonym_values, ','));

                // Insert synonyms
                // Abort if field is already populated
                std::string tag(GetTag(*output));
                if (record->getFieldIndex(tag) != MarcRecord::FIELD_NOT_FOUND)
                    Error("Field with tag " + tag + " is not empty for PPN " + record->getControlNumber() + '\n');
                std::string subfield_spec = GetSubfieldCodes(*output);
                if (subfield_spec.size() != 1)
                    Error("We currently only support a single subfield and thus specifying " + subfield_spec
                          + " as output subfield is not valid\n");
                Subfields subfields(' ', ' '); // <- indicators must be set explicitly although empty
                subfields.addSubfield(subfield_spec.at(0), synonyms);
                if (not(record->insertField(tag, subfields.toString())))
                    Warning("Could not insert field " + tag + " for PPN " + record->getControlNumber() + '\n');
                ++modified_count;
            }
        }
    }
}

void InsertSynonyms(MarcReader * const marc_reader, MarcWriter * const marc_writer,
                    const std::set<std::string> &primary_tags_and_subfield_codes,
                    const std::set<std::string> &output_tags_and_subfield_codes,
                    std::vector<std::map<std::string, std::string>> &synonym_maps)
{
    while (MarcRecord record = marc_reader->read()) {
        ProcessRecord(&record, synonym_maps, primary_tags_and_subfield_codes, output_tags_and_subfield_codes);
        marc_writer->write(record);
        ++record_count;
    }

    std::cerr << "Modified " << modified_count << " of " << record_count << " record(s).\n";
}

int ParseSpec(std::string spec_str, std::set<std::string> * field_specs, std::map<std::string, std::pair<std::string, std::string>> * filter_specs = nullptr) {
    std::set<std::string>  raw_field_specs;

    if (unlikely(StringUtil::Split(spec_str, ":", &raw_field_specs) < 1)){
        Error("Need at least one field");
        return -1;
    }

    if (filter_specs == nullptr) {
        *field_specs = raw_field_specs;
	return 0;
    }

    // Iterate over all Field-specs and extract possible filters
    static RegexMatcher * const matcher(RegexMatcher::RegexMatcherFactory("(\\d{1,3}[a-z]+)\\[(\\d{1,3}[a-z])=(.*)\\]"));

    for (auto field_spec : raw_field_specs) {
        if (matcher->matched(field_spec)){
            filter_specs->emplace((*matcher)[1], std::make_pair((*matcher)[2], (*matcher)[3]));
            auto bracket = field_spec.find("[");
            field_spec = (bracket != std::string::npos) ? field_spec.erase(bracket, field_spec.length()) : field_spec;
        }
        field_specs->insert(field_spec);
    }
    return 0;
}

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

    if (argc != 4)
        Usage();

    const std::string marc_input_filename(argv[1]);
    const std::string authority_data_marc_input_filename(argv[2]);
    const std::string marc_output_filename(argv[3]);
    if (unlikely(marc_input_filename == marc_output_filename))
        Error("Title data input file name equals output file name!");
    if (unlikely(authority_data_marc_input_filename == marc_output_filename))
        Error("Authority data input file name equals output file name!");

    std::unique_ptr<MarcReader> marc_reader(MarcReader::Factory(marc_input_filename, MarcReader::BINARY));
    std::unique_ptr<MarcReader> authority_reader(MarcReader::Factory(authority_data_marc_input_filename,
                                                                     MarcReader::BINARY));
    std::unique_ptr<MarcWriter> marc_writer(MarcWriter::Factory(marc_output_filename, MarcWriter::BINARY));

    try {
        // Determine possible mappings
        // Values in square brackets specify a positive criterion for values to be taken into account
        const std::string AUTHORITY_DATA_PRIMARY_SPEC("100abcd[079v=piz]:110abcd:111abcd:130abcd:150abcd:151abcd");
        const std::string AUTHORITY_DATA_SYNONYM_SPEC("400abcd:410abcd:411abcd:430abcd:450abcd:451abcd");
        const std::string TITLE_DATA_PRIMARY_SPEC("600abcd:610abcd:611abcd:630abcd:650abcd:651abcd:689abcd");
        const std::string TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS("180a:181a:182a:183a:184a:185a:186a");

        // Determine fields to handle
        std::set<std::string> primary_tags_and_subfield_codes;
        std::set<std::string> synonym_tags_and_subfield_codes;
        std::set<std::string> input_tags_and_subfield_codes;
        std::set<std::string> output_tags_and_subfield_codes;

        std::map<std::string, std::pair<std::string, std::string>> filter_specs;

        if (unlikely(ParseSpec(AUTHORITY_DATA_PRIMARY_SPEC, &primary_tags_and_subfield_codes, &filter_specs) < 0))
            Error("Could not properly parse " + AUTHORITY_DATA_PRIMARY_SPEC);

        if (unlikely(StringUtil::Split(AUTHORITY_DATA_SYNONYM_SPEC, ":", &synonym_tags_and_subfield_codes) < 1))
            Error("Need at least one synonym field");

        if (unlikely(StringUtil::Split(TITLE_DATA_PRIMARY_SPEC, ":", &input_tags_and_subfield_codes) < 1))
            Error("Need at least one input field");

        if (unlikely(StringUtil::Split(TITLE_DATA_UNUSED_FIELDS_FOR_SYNONYMS, ":", &output_tags_and_subfield_codes)
                     < 1))
            Error("Need at least one output field");

        unsigned num_of_authority_entries(primary_tags_and_subfield_codes.size());

        if (synonym_tags_and_subfield_codes.size() != num_of_authority_entries)
            Error("Number of authority primary specs must match number of synonym specs");
        if (input_tags_and_subfield_codes.size() != output_tags_and_subfield_codes.size())
            Error("Number of fields title entry specs must match number of output specs");

        std::vector<std::map<std::string, std::string>> synonym_maps(num_of_authority_entries,
                                                                     std::map<std::string, std::string>());

        // Extract the synonyms from authority data
        ExtractSynonyms(authority_reader.get(), primary_tags_and_subfield_codes, synonym_tags_and_subfield_codes,
                        &synonym_maps, filter_specs);

        // Iterate over the title data
        InsertSynonyms(marc_reader.get(), marc_writer.get(), input_tags_and_subfield_codes,
                       output_tags_and_subfield_codes, synonym_maps);

    } catch (const std::exception &x) {
        Error("caught exception: " + std::string(x.what()));
    }
}
<|endoftext|>


<commit_before>/** \file    util.cc
 *  \brief   Implementation of various utility functions.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2015,2017,2018 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 "util.h"
#include <iterator>
#include <stdexcept>
#include <cctype>
#include <cstdlib>
#include <execinfo.h>
#include <signal.h>
#include "Compiler.h"
#include "MiscUtil.h"
#include "TimeUtil.h"

// Macro to determine the number of entries in a one-dimensional array:
#define DIM(array) (sizeof(array) / sizeof(array[0]))

char *progname; // Must be set in main() with "progname = argv[0];";

Logger::Logger()
    : fd_(STDERR_FILENO), log_process_pids_(false), log_no_decorations_(false), log_strip_call_site_(false),
      min_log_level_(LL_INFO)
{
    const char * const min_log_level(::getenv("MIN_LOG_LEVEL"));
    if (min_log_level != nullptr)
        min_log_level_ = Logger::StringToLogLevel(min_log_level);
    const char * const logger_format(::getenv("LOGGER_FORMAT"));
    if (logger_format != nullptr) {
        if (std::strstr(logger_format, "process_pids") != nullptr)
            log_process_pids_ = true;
        if (std::strstr(logger_format, "no_decorations") != nullptr)
            log_no_decorations_ = true;
        if (std::strstr(logger_format, "strip_call_site") != nullptr)
            log_strip_call_site_ = true;
    }
}

void Logger::error(const std::string &msg) {
    std::lock_guard<std::mutex> mutex_locker(mutex_);

    writeString("SEVERE", msg);
    if (::getenv("BACKTRACE") != nullptr) {
        const bool saved_log_no_decorations(log_no_decorations_);
        log_no_decorations_ = true;
        writeString("", "Backtrace:");
        for (const auto &stack_entry : MiscUtil::GetCallStack())
            writeString("", "  " + stack_entry);
        log_no_decorations_ = saved_log_no_decorations;
    }

    std::exit(EXIT_FAILURE);
}

void Logger::warning(const std::string &msg) {
    if (min_log_level_ < LL_WARNING)
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("WARN", msg);
}

void Logger::info(const std::string &msg) {
    if (min_log_level_ < LL_INFO)
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("INFO", msg);
}

void Logger::debug(const std::string &msg) {
    if ((min_log_level_ < LL_DEBUG) and (MiscUtil::SafeGetEnv("UTIL_LOG_DEBUG") != "true"))
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("DEBUG", msg);
}

inline Logger *LoggerInstantiator() {
    return new Logger();
}

Logger *logger(LoggerInstantiator());

Logger::LogLevel Logger::StringToLogLevel(const std::string &level_candidate) {
    if (level_candidate == "ERROR")
        return Logger::LL_ERROR;
    if (level_candidate == "WARNING")
        return Logger::LL_WARNING;
    if (level_candidate == "INFO")
        return Logger::LL_INFO;
    if (level_candidate == "DEBUG")
        return Logger::LL_DEBUG;
    LOG_ERROR("not a valid minimum log level: \"" + level_candidate + "\"! (Use ERROR, WARNING, INFO or DEBUG)");
}

std::string Logger::LogLevelToString(const LogLevel log_level) {
    if (log_level == Logger::LL_ERROR)
        return "ERROR";
    if (log_level == Logger::LL_WARNING)
        return "WARNING";
    if (log_level == Logger::LL_INFO)
        return "INFO";
    if (log_level == Logger::LL_DEBUG)
        return "DEBUG";
    LOG_ERROR("unsupported log level, we should *never* get here!");
}

void Logger::writeString(const std::string &level, std::string msg) {
    if (unlikely(::progname == nullptr))
        msg = "You must set \"progname\" in main() with \"::progname = argv[0];\" in oder to use the Logger API!";
    else if (not log_no_decorations_) {
        msg = TimeUtil::GetCurrentDateAndTime(TimeUtil::ISO_8601_FORMAT) + " " + level + " " + std::string(::progname) + ": "
              + msg;
        if (log_process_pids_)
            msg += " (PID: " + std::to_string(::getpid()) + ")";
    }

    if (log_strip_call_site_) {
        const auto END_OF_CALL_SITE_PREFIX(msg.find("): "));
        if (END_OF_CALL_SITE_PREFIX != std::string::npos)
            msg = msg.substr(END_OF_CALL_SITE_PREFIX + 3);
    }

    msg += '\n';

    if (unlikely(::write(fd_, reinterpret_cast<const void *>(msg.data()), msg.size()) == -1)) {
        const std::string error_message("in Logger::writeString(util.cc): write to file descriptor " + std::to_string(fd_)
                                        + " failed! (errno = " + std::to_string(errno) + ")");
        #pragma GCC diagnostic ignored "-Wunused-result"
        ::write(STDERR_FILENO, error_message.data(), error_message.size());
        #pragma GCC diagnostic warning "-Wunused-result"
        _exit(EXIT_FAILURE);
    }

    if (unlikely(::progname == nullptr))
        _exit(EXIT_FAILURE);
}

DSVReader::DSVReader(const std::string &filename, const char field_separator, const char field_delimiter)
    : field_separator_(field_separator), field_delimiter_(field_delimiter), line_no_(0), filename_(filename)
{
    input_ = std::fopen(filename.c_str(), "rm");
    if (input_ == nullptr)
        throw std::runtime_error("in DSVReader::DSVReader: can't open \"" + filename + "\" for reading!");
}

DSVReader::~DSVReader() {
    if (input_ != nullptr)
        std::fclose(input_);
}

namespace {

void SkipFieldPadding(FILE * const input) {
    int ch = std::fgetc(input);
    while (isblank(ch))
        ch = std::fgetc(input);
    std::ungetc(ch, input);
}

/** \brief Remove trailing spaces and tabs from "s". */
std::string TrimBlanks(std::string * s) {
    std::string::const_reverse_iterator it(s->crbegin());
    for (/* Empty! */; it != s->crend() and std::isblank(*it); ++it)
        /* Intentionally Empty! */;
    if (it != s->crbegin())
        *s = s->substr(0, std::distance(it, s->crend()));

    return *s;
}

std::string ReadQuotedValue(FILE * const input, const char field_delimiter, const char field_separator) {
    std::string value;
    bool delimiter_seen(false);
    for (;;) {
        const int ch(std::fgetc(input));
        if (ch == EOF)
            throw std::runtime_error("unexpected EOF while reading a quoted DSV value!");
        if (ch == field_delimiter) {
            if (delimiter_seen) {
                // ignore if it's not the outermost delimiter
                const int next(std::fgetc(input));
                std::ungetc(next, input);

                if (next == field_separator or next == '\n' or next == EOF)
                    return value;
            } else
                delimiter_seen = true;
        } else {
            if (ch == '\n' or ch == EOF) {
                std::ungetc(ch, input);
                return TrimBlanks(&value);
            }
            value += static_cast<char>(ch);
        }
    }
}

std::string ReadNonQuotedValue(FILE * const input, const char field_separator) {
    std::string value;
    for (;;) {
        const int ch(std::fgetc(input));
        if (ch == EOF or ch == '\n' or ch == field_separator) {
            std::ungetc(ch, input);
            return TrimBlanks(&value);
        }
        value += static_cast<char>(ch);
    }
}

void BacktraceSignalHandler(int signal_no) {
    void *stack_return_addresses[20];
    const size_t number_of_addresses(::backtrace(stack_return_addresses, DIM(stack_return_addresses)));
    char err_msg[1024] = "Caught signal ";
    char *cp = err_msg + std::strlen(err_msg);
    if (signal_no > 10)
        *cp++ = '0' + (signal_no / 10);
    *cp++ = '0' + (signal_no % 10);
    *cp++ = '.';
    *cp++ = '\n';
    *cp = '\0';
    ssize_t unused(::write(STDERR_FILENO, err_msg, std::strlen(err_msg)));
    (void)unused;
    ::backtrace_symbols_fd(stack_return_addresses, number_of_addresses, STDERR_FILENO);
    ::_exit(EXIT_FAILURE);
}

int InstallSegvSignalHandler(void handler(int)) {
    ::signal(SIGSEGV, handler);
    return 0;
}

volatile int dummy = InstallSegvSignalHandler(BacktraceSignalHandler);

} // unnamed namespace

bool DSVReader::readLine(std::vector<std::string> * const values) {
    values->clear();
    ++line_no_;

    int ch;
    for (;;) {
        if (not values->empty()) {
            SkipFieldPadding(input_);
            ch = std::fgetc(input_);
            if (ch == EOF)
                return not values->empty();
            if (ch == '\n')
                return true;
            if (ch != field_separator_)
                throw std::runtime_error("in DSVReader::readLine: on line " + std::to_string(line_no_)
                                         + ": field separator expected, found '"
                                         + std::string(1, static_cast<char>(ch)) + "' instead!");
        }

        SkipFieldPadding(input_);
        ch = std::fgetc(input_);
        if (ch == '\n')
            return true;
        if (ch == EOF)
            return not values->empty();
        if (ch == field_separator_) {
            std::ungetc(ch, input_);
            values->emplace_back("");
        } else if (ch == field_delimiter_) {
            std::ungetc(ch, input_);
            values->emplace_back(ReadQuotedValue(input_, field_delimiter_, field_separator_));
        } else {
            std::ungetc(ch, input_);
            values->emplace_back(ReadNonQuotedValue(input_, field_separator_));
        }
    }
}
<commit_msg>Update util.cc<commit_after>/** \file    util.cc
 *  \brief   Implementation of various utility functions.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2015,2017,2018 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 "util.h"
#include <iterator>
#include <stdexcept>
#include <cctype>
#include <cstdlib>
#include <execinfo.h>
#include <signal.h>
#include "Compiler.h"
#include "MiscUtil.h"
#include "TimeUtil.h"

// Macro to determine the number of entries in a one-dimensional array:
#define DIM(array) (sizeof(array) / sizeof(array[0]))

char *progname; // Must be set in main() with "progname = argv[0];";

Logger::Logger()
    : fd_(STDERR_FILENO), log_process_pids_(false), log_no_decorations_(false), log_strip_call_site_(false),
      min_log_level_(LL_INFO)
{
    const char * const min_log_level(::getenv("MIN_LOG_LEVEL"));
    if (min_log_level != nullptr)
        min_log_level_ = Logger::StringToLogLevel(min_log_level);
    const char * const logger_format(::getenv("LOGGER_FORMAT"));
    if (logger_format != nullptr) {
        if (std::strstr(logger_format, "process_pids") != nullptr)
            log_process_pids_ = true;
        if (std::strstr(logger_format, "no_decorations") != nullptr)
            log_no_decorations_ = true;
        if (std::strstr(logger_format, "strip_call_site") != nullptr)
            log_strip_call_site_ = true;
    }
}

void Logger::error(const std::string &msg) {
    std::lock_guard<std::mutex> mutex_locker(mutex_);

    writeString("SEVERE", msg);
    if (::getenv("BACKTRACE") != nullptr) {
        const bool saved_log_no_decorations(log_no_decorations_);
        log_no_decorations_ = true;
        writeString("", "Backtrace:");
        for (const auto &stack_entry : MiscUtil::GetCallStack())
            writeString("", "  " + stack_entry);
        log_no_decorations_ = saved_log_no_decorations;
    }

    std::exit(EXIT_FAILURE);
}

void Logger::warning(const std::string &msg) {
    if (min_log_level_ < LL_WARNING)
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("WARN", msg);
}

void Logger::info(const std::string &msg) {
    if (min_log_level_ < LL_INFO)
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("INFO", msg);
}

void Logger::debug(const std::string &msg) {
    if ((min_log_level_ < LL_DEBUG) and (MiscUtil::SafeGetEnv("UTIL_LOG_DEBUG") != "true"))
        return;

    std::lock_guard<std::mutex> mutex_locker(mutex_);
    writeString("DEBUG", msg);
}

inline Logger *LoggerInstantiator() {
    return new Logger();
}

Logger *logger(LoggerInstantiator());

Logger::LogLevel Logger::StringToLogLevel(const std::string &level_candidate) {
    if (level_candidate == "ERROR")
        return Logger::LL_ERROR;
    if (level_candidate == "WARNING")
        return Logger::LL_WARNING;
    if (level_candidate == "INFO")
        return Logger::LL_INFO;
    if (level_candidate == "DEBUG")
        return Logger::LL_DEBUG;
    LOG_ERROR("not a valid minimum log level: \"" + level_candidate + "\"! (Use ERROR, WARNING, INFO or DEBUG)");
}

std::string Logger::LogLevelToString(const LogLevel log_level) {
    if (log_level == Logger::LL_ERROR)
        return "ERROR";
    if (log_level == Logger::LL_WARNING)
        return "WARNING";
    if (log_level == Logger::LL_INFO)
        return "INFO";
    if (log_level == Logger::LL_DEBUG)
        return "DEBUG";
    LOG_ERROR("unsupported log level, we should *never* get here!");
}

void Logger::writeString(const std::string &level, std::string msg) {
    if (unlikely(::progname == nullptr))
        msg = "You must set \"progname\" in main() with \"::progname = argv[0];\" in oder to use the Logger API!";
    else if (not log_no_decorations_) {
        msg = TimeUtil::GetCurrentDateAndTime(TimeUtil::ISO_8601_FORMAT) + " " + level + " " + std::string(::progname) + ": "
              + msg;
        if (log_process_pids_)
            msg += " (PID: " + std::to_string(::getpid()) + ")";
    }

    if (log_strip_call_site_) {
        const auto END_OF_CALL_SITE_PREFIX(msg.find("): "));
        if (END_OF_CALL_SITE_PREFIX != std::string::npos)
            msg = msg.substr(END_OF_CALL_SITE_PREFIX + 3);
    }

    msg += '\n';

    if (unlikely(::write(fd_, reinterpret_cast<const void *>(msg.data()), msg.size()) == -1)) {
        const std::string error_message("in Logger::writeString(util.cc): write to file descriptor " + std::to_string(fd_)
                                        + " failed! (errno = " + std::to_string(errno) + ")");
        #pragma GCC diagnostic ignored "-Wunused-result"
        ::write(STDERR_FILENO, error_message.data(), error_message.size());
        #pragma GCC diagnostic warning "-Wunused-result"
        _exit(EXIT_FAILURE);
    }

    if (unlikely(::progname == nullptr))
        _exit(EXIT_FAILURE);
}

DSVReader::DSVReader(const std::string &filename, const char field_separator, const char field_delimiter)
    : field_separator_(field_separator), field_delimiter_(field_delimiter), line_no_(0), filename_(filename)
{
    input_ = std::fopen(filename.c_str(), "rm");
    if (input_ == nullptr)
        throw std::runtime_error("in DSVReader::DSVReader: can't open \"" + filename + "\" for reading!");
}

DSVReader::~DSVReader() {
    if (input_ != nullptr)
        std::fclose(input_);
}

namespace {

void SkipFieldPadding(FILE * const input) {
    int ch = std::fgetc(input);
    while (isblank(ch))
        ch = std::fgetc(input);
    std::ungetc(ch, input);
}

/** \brief Remove trailing spaces and tabs from "s". */
std::string TrimBlanks(std::string * s) {
    std::string::const_reverse_iterator it(s->crbegin());
    for (/* Empty! */; it != s->crend() and std::isblank(*it); ++it)
        /* Intentionally Empty! */;
    if (it != s->crbegin())
        *s = s->substr(0, std::distance(it, s->crend()));

    return *s;
}

std::string ReadQuotedValue(FILE * const input, const char field_delimiter, const char field_separator) {
    std::string value;
    bool delimiter_seen(false);
    for (;;) {
        const int ch(std::fgetc(input));
        if (ch == EOF)
            throw std::runtime_error("unexpected EOF while reading a quoted DSV value!");
        if (ch == field_delimiter) {
            if (delimiter_seen) {
                // ignore if it's not the outermost delimiter
                const int next(std::fgetc(input));
                std::ungetc(next, input);

                if (next == field_separator or next == '\n' or next == EOF)
                    return value;
            } else
                delimiter_seen = true;
        } else {
            if (ch == '\n' or ch == EOF) {
                std::ungetc(ch, input);
                return TrimBlanks(&value);
            }
            value += static_cast<char>(ch);
        }
    }
}

std::string ReadNonQuotedValue(FILE * const input, const char field_separator) {
    std::string value;
    for (;;) {
        const int ch(std::fgetc(input));
        if (ch == EOF or ch == '\n' or ch == field_separator) {
            std::ungetc(ch, input);
            return TrimBlanks(&value);
        }
        value += static_cast<char>(ch);
    }
}

void BacktraceSignalHandler(int signal_no) {
    void *stack_return_addresses[20];
    const size_t number_of_addresses(::backtrace(stack_return_addresses, DIM(stack_return_addresses)));
    char err_msg[1024] = "Caught signal ";
    char *cp = err_msg + std::strlen(err_msg);
    if (signal_no > 10)
        *cp++ = '0' + (signal_no / 10);
    *cp++ = '0' + (signal_no % 10);
    *cp++ = '.';
    *cp++ = '\n';
    *cp = '\0';
    ssize_t unused(::write(STDERR_FILENO, err_msg, std::strlen(err_msg)));
    (void)unused;
    ::backtrace_symbols_fd(stack_return_addresses, number_of_addresses, STDERR_FILENO);
    ::_exit(EXIT_FAILURE);
}

int InstallSegvSignalHandler(void handler(int)) {
    ::signal(SIGSEGV, handler);
    return 0;
}

volatile int dummy = InstallSegvSignalHandler(BacktraceSignalHandler);

} // unnamed namespace

bool DSVReader::readLine(std::vector<std::string> * const values) {
    values->clear();
    ++line_no_;

    int ch;
    for (;;) {
        if (not values->empty()) {
            SkipFieldPadding(input_);
            ch = std::fgetc(input_);
            if (ch == EOF)
                return not values->empty();
            if (ch == '\n')
                return true;
            if (ch != field_separator_)
                throw std::runtime_error("in DSVReader::readLine: on line " + std::to_string(line_no_)
                                         + ": field separator expected, found '"
                                         + std::string(1, static_cast<char>(ch)) + "' instead!");
        }

        SkipFieldPadding(input_);
        ch = std::fgetc(input_);
        if (ch == '\n')
            return true;
        if (ch == EOF)
            return not values->empty();
        if (ch == field_separator_) {
            std::ungetc(ch, input_);
            values->emplace_back("");
        } else if (ch == field_delimiter_) {
            std::ungetc(ch, input_);
            values->emplace_back(ReadQuotedValue(input_, field_delimiter_, field_separator_));
        } else {
            std::ungetc(ch, input_);
            values->emplace_back(ReadNonQuotedValue(input_, field_separator_));
        }
    }
}
<|endoftext|>