<commit_before>#include "ncd_gateway.h"
#include "S3B.h"
#include "spark_wiring_eeprom.h"

S3B sModule;
String eventReturns[5];
unsigned long tOut = 3000;

//int s3b(JsonObject& root);

void init_gateway(){
    Particle.function("deviceComm", gatewayCommand);
    Particle.subscribe("ncd_deviceCom", commandHandler, MY_DEVICES);
    Serial1.begin(115200);
    Wire.begin();
}

int gatewayCommand(String arg){
    int length = arg.length();

    byte bytes[length+1];

    arg.getBytes(bytes, length+1);

    int newLen = (length/2)+1;

    byte newBytes[newLen];

    int ind = 0;

    for(int i=0;i<length;i+=2){
        if(i>0){
            ind=i/2;
        }
        int b1=(bytes[i]-32) << 4;
        int b2=bytes[i+1]-32;
        newBytes[ind]=b1+b2;
    }
    //send int pointer for setting to allow me to test how to return results?
    return ncdApi(newBytes);
}

void commandHandler(const char *event, const char *data){
    Serial.println("Got Event "+String(event));
    String newCommand = String(data);
    gatewayCommand(newCommand);
}
int ncdApi(byte packetBytes[]){
    int buffLen = 1;
    Serial.println(String(packetBytes[0]));
    switch(packetBytes[0]){
        case 187:
            {
                //packet of packets
                int i=2;
                int max;
                for(int pn = 0; pn<packetBytes[1]; pn++){

                    max=i+packetBytes[i];
                    Serial.println(max);
                    byte intPacket[packetBytes[i]];
                    i++;
                    int ni=0;
                    for(i;i<=max;i++){
                        intPacket[ni]=packetBytes[i];
                        ni++;
                    }
                    ncdApi(intPacket);
                }
                break;
            }
        case 188:
            {
                //plain i2c w/r command
                if(packetBytes[3] > 0){
                    buffLen = packetBytes[3];
                    byte buff[buffLen];
                    i2c_command(packetBytes, buff);
                }
                return bytesToInt(buff, buffLen);
            }
        case 189:
            {
                //masking command
                int addr = packetBytes[1];
                int maskOp = packetBytes[2];
                int maskedOffsets = packetBytes[3];
                int readCommandLen = packetBytes[4];
                int readLen = packetBytes[5];
                int readCommand[readCommandLen];

                array_slice(packetBytes, 6, readCommandLen, readCommand);

                int writeCommandLen = packetBytes[6+readCommandLen];
                int writeCommand[writeCommandLen];

                array_slice(packetBytes, 7+readCommandLen, writeCommandLen, writeCommand);

                int writeVals[writeCommandLen];
                int wi=0;
                for(wi; wi<maskedOffsets; wi++){
                    writeVals[wi]=writeCommand[wi];
                    Serial.println(writeVals[wi]);
                }

                writeCommandsI2C(addr, readCommand, readCommandLen);
                Wire.requestFrom(addr, readLen);
                for(int i=0;i<readLen;i++){
                    int current = Wire.read();
                    writeVals[wi] = mask(current, writeCommand[wi], maskOp);
                    Serial.println(current);
                    Serial.println(writeVals[wi]);
                    wi++;
                }

                writeCommandsI2C(addr, writeVals, writeCommandLen);
                break;
            }
    }
    return 1;
}
int mask(int val, int mask, int type){
    switch(type){
        case 0:
            val |= mask;
            break;
        case 1:
            val ^= mask;
            break;
        case 2:
            val &= ~mask;
            break;
        case 3:
            val &= mask;
            break;
        case 4:
            val = val << mask;
            break;
        case 5:
            val = val >> mask;
    }
    return val;
}
void i2c_command(byte bytes[], byte *buff){
    if(bytes[0] == 188){
        int commands[bytes[2]];
        array_slice(bytes, 4, bytes[2], commands);
        int addr = bytes[1];
        if(bytes[3] == 0){
            //write command
            buff[0]=writeCommandsI2C(addr, commands, bytes[2]);
        }else{
            //read command
            writeCommandsI2C(addr, commands, bytes[2]);
            Wire.requestFrom(addr, bytes[3]);
            for(int i=0;i<bytes[3];i++){
                buff[i] = Wire.read();
            }
        }
    }
}
void array_slice(byte bytes[], int start, int len, byte *buff){
    int ni = 0;
    int end = start+len;
    for(int i=start; i<=end; i++){
        buff[ni] = bytes[i];
        ni++;
    }
}
void array_slice(byte bytes[], int start, int len, int *buff){
    int ni=0;
    int end = start+len;
    for(int i=start; i<=end; i++){
        buff[ni] = bytes[i];
        ni++;
    }
}
int sendEvent(String key){
    int i = key.toInt();
    String eventName = "";
    eventName = "eventReturn_"+key;
    Particle.publish(eventName, eventReturns[i], 60, PRIVATE);
    eventReturns[i] = "";
    return 1;
};
int setEventReturn(String value){
    int index = 0;
    while(eventReturns[index].length() > 1){
        index++;
    }
    eventReturns[index] = value;
    return index;
};
int writeCommandsI2C(int addr, int* commands, int commandsLen){
    Serial.printf("Running I2C Command, address: %i data: ",addr);
    Wire.beginTransmission(addr);
    for(int i = 0; i < commandsLen; i++){
        Wire.write(commands[i]);
        Serial.printf("%i, ",commands[i]);
    }
    int status = Wire.endTransmission();
    Serial.printf(" Status: %i \n", status);
    return status;
};
int bytesToInt(byte bytes[], int length){
    int ret = bytes[0];
    for(int i=1; i<length; i++){
        ret = ret << 8;
        ret += bytes[i];
    }
    return ret;
}
<commit_msg>Update ncd_gateway.cpp<commit_after>#include "ncd_gateway.h"
#include "S3B.h"
#include "spark_wiring_eeprom.h"

S3B sModule;
String eventReturns[5];
unsigned long tOut = 3000;

//int s3b(JsonObject& root);

void init_gateway(){
    Particle.function("deviceComm", gatewayCommand);
    Particle.subscribe("ncd_deviceCom", commandHandler, MY_DEVICES);
    Serial1.begin(115200);
    Wire.begin();
}

int gatewayCommand(String arg){
    int length = arg.length();

    byte bytes[length+1];

    arg.getBytes(bytes, length+1);

    int newLen = (length/2)+1;

    byte newBytes[newLen];

    int ind = 0;

    for(int i=0;i<length;i+=2){
        if(i>0){
            ind=i/2;
        }
        int b1=(bytes[i]-32) << 4;
        int b2=bytes[i+1]-32;
        newBytes[ind]=b1+b2;
    }
    //send int pointer for setting to allow me to test how to return results?
    return ncdApi(newBytes);
}

void commandHandler(const char *event, const char *data){
    Serial.println("Got Event "+String(event));
    String newCommand = String(data);
    gatewayCommand(newCommand);
}
int ncdApi(byte packetBytes[]){
    int buffLen = 1;
    Serial.println(String(packetBytes[0]));
    switch(packetBytes[0]){
        case 187:
            {
                //packet of packets
                int i=2;
                int max;
                for(int pn = 0; pn<packetBytes[1]; pn++){

                    max=i+packetBytes[i];
                    Serial.println(max);
                    byte intPacket[packetBytes[i]];
                    i++;
                    int ni=0;
                    for(i;i<=max;i++){
                        intPacket[ni]=packetBytes[i];
                        ni++;
                    }
                    ncdApi(intPacket);
                }
                break;
            }
        case 188:
            {
                //plain i2c w/r command
                if(packetBytes[3] > 0){
                    buffLen = packetBytes[3];
                }
                byte buff[buffLen];
                i2c_command(packetBytes, buff);
                return bytesToInt(buff, buffLen);
            }
        case 189:
            {
                //masking command
                int addr = packetBytes[1];
                int maskOp = packetBytes[2];
                int maskedOffsets = packetBytes[3];
                int readCommandLen = packetBytes[4];
                int readLen = packetBytes[5];
                int readCommand[readCommandLen];

                array_slice(packetBytes, 6, readCommandLen, readCommand);

                int writeCommandLen = packetBytes[6+readCommandLen];
                int writeCommand[writeCommandLen];

                array_slice(packetBytes, 7+readCommandLen, writeCommandLen, writeCommand);

                int writeVals[writeCommandLen];
                int wi=0;
                for(wi; wi<maskedOffsets; wi++){
                    writeVals[wi]=writeCommand[wi];
                    Serial.println(writeVals[wi]);
                }

                writeCommandsI2C(addr, readCommand, readCommandLen);
                Wire.requestFrom(addr, readLen);
                for(int i=0;i<readLen;i++){
                    int current = Wire.read();
                    writeVals[wi] = mask(current, writeCommand[wi], maskOp);
                    Serial.println(current);
                    Serial.println(writeVals[wi]);
                    wi++;
                }

                writeCommandsI2C(addr, writeVals, writeCommandLen);
                break;
            }
    }
    return 1;
}
int mask(int val, int mask, int type){
    switch(type){
        case 0:
            val |= mask;
            break;
        case 1:
            val ^= mask;
            break;
        case 2:
            val &= ~mask;
            break;
        case 3:
            val &= mask;
            break;
        case 4:
            val = val << mask;
            break;
        case 5:
            val = val >> mask;
    }
    return val;
}
void i2c_command(byte bytes[], byte *buff){
    if(bytes[0] == 188){
        int commands[bytes[2]];
        array_slice(bytes, 4, bytes[2], commands);
        int addr = bytes[1];
        if(bytes[3] == 0){
            //write command
            buff[0]=writeCommandsI2C(addr, commands, bytes[2]);
        }else{
            //read command
            writeCommandsI2C(addr, commands, bytes[2]);
            Wire.requestFrom(addr, bytes[3]);
            for(int i=0;i<bytes[3];i++){
                buff[i] = Wire.read();
            }
        }
    }
}
void array_slice(byte bytes[], int start, int len, byte *buff){
    int ni = 0;
    int end = start+len;
    for(int i=start; i<=end; i++){
        buff[ni] = bytes[i];
        ni++;
    }
}
void array_slice(byte bytes[], int start, int len, int *buff){
    int ni=0;
    int end = start+len;
    for(int i=start; i<=end; i++){
        buff[ni] = bytes[i];
        ni++;
    }
}
int sendEvent(String key){
    int i = key.toInt();
    String eventName = "";
    eventName = "eventReturn_"+key;
    Particle.publish(eventName, eventReturns[i], 60, PRIVATE);
    eventReturns[i] = "";
    return 1;
};
int setEventReturn(String value){
    int index = 0;
    while(eventReturns[index].length() > 1){
        index++;
    }
    eventReturns[index] = value;
    return index;
};
int writeCommandsI2C(int addr, int* commands, int commandsLen){
    Serial.printf("Running I2C Command, address: %i data: ",addr);
    Wire.beginTransmission(addr);
    for(int i = 0; i < commandsLen; i++){
        Wire.write(commands[i]);
        Serial.printf("%i, ",commands[i]);
    }
    int status = Wire.endTransmission();
    Serial.printf(" Status: %i \n", status);
    return status;
};
int bytesToInt(byte bytes[], int length){
    int ret = bytes[0];
    for(int i=1; i<length; i++){
        ret = ret << 8;
        ret += bytes[i];
    }
    return ret;
}
<|endoftext|>


<commit_before>//===- lib/Linker/LinkArchives.cpp - Link LLVM objects and libraries ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains routines to handle linking together LLVM bitcode files,
// and to handle annoying things like static libraries.
//
//===----------------------------------------------------------------------===//

#include "llvm/Linker.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/Bitcode/Archive.h"
#include "llvm/Config/config.h"
#include <memory>
#include <set>
using namespace llvm;

/// GetAllUndefinedSymbols - calculates the set of undefined symbols that still
/// exist in an LLVM module. This is a bit tricky because there may be two
/// symbols with the same name but different LLVM types that will be resolved to
/// each other but aren't currently (thus we need to treat it as resolved).
///
/// Inputs:
///  M - The module in which to find undefined symbols.
///
/// Outputs:
///  UndefinedSymbols - A set of C++ strings containing the name of all
///                     undefined symbols.
///
static void
GetAllUndefinedSymbols(Module *M, std::set<std::string> &UndefinedSymbols) {
  std::set<std::string> DefinedSymbols;
  UndefinedSymbols.clear();

  // If the program doesn't define a main, try pulling one in from a .a file.
  // This is needed for programs where the main function is defined in an
  // archive, such f2c'd programs.
  Function *Main = M->getFunction("main");
  if (Main == 0 || Main->isDeclaration())
    UndefinedSymbols.insert("main");

  for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
    if (I->hasName()) {
      if (I->isDeclaration())
        UndefinedSymbols.insert(I->getName());
      else if (!I->hasInternalLinkage()) {
        assert(!I->hasDLLImportLinkage()
               && "Found dllimported non-external symbol!");
        DefinedSymbols.insert(I->getName());
      }
    }
  for (Module::global_iterator I = M->global_begin(), E = M->global_end();
       I != E; ++I)
    if (I->hasName()) {
      if (I->isDeclaration())
        UndefinedSymbols.insert(I->getName());
      else if (!I->hasInternalLinkage()) {
        assert(!I->hasDLLImportLinkage()
               && "Found dllimported non-external symbol!");
        DefinedSymbols.insert(I->getName());
      }
    }

  // Prune out any defined symbols from the undefined symbols set...
  for (std::set<std::string>::iterator I = UndefinedSymbols.begin();
       I != UndefinedSymbols.end(); )
    if (DefinedSymbols.count(*I))
      UndefinedSymbols.erase(I++);  // This symbol really is defined!
    else
      ++I; // Keep this symbol in the undefined symbols list
}

/// LinkInArchive - opens an archive library and link in all objects which
/// provide symbols that are currently undefined.
///
/// Inputs:
///  Filename - The pathname of the archive.
///
/// Return Value:
///  TRUE  - An error occurred.
///  FALSE - No errors.
bool
Linker::LinkInArchive(const sys::Path &Filename, bool &is_native) {

  // Make sure this is an archive file we're dealing with
  if (!Filename.isArchive())
    return error("File '" + Filename.toString() + "' is not an archive.");

  // Open the archive file
  verbose("Linking archive file '" + Filename.toString() + "'");

  // Find all of the symbols currently undefined in the bitcode program.
  // If all the symbols are defined, the program is complete, and there is
  // no reason to link in any archive files.
  std::set<std::string> UndefinedSymbols;
  GetAllUndefinedSymbols(Composite, UndefinedSymbols);

  if (UndefinedSymbols.empty()) {
    verbose("No symbols undefined, skipping library '" +
            Filename.toString() + "'");
    return false;  // No need to link anything in!
  }

  std::string ErrMsg;
  std::auto_ptr<Archive> AutoArch (
    Archive::OpenAndLoadSymbols(Filename,&ErrMsg));

  Archive* arch = AutoArch.get();

  if (!arch)
    return error("Cannot read archive '" + Filename.toString() +
                 "': " + ErrMsg);
  if (!arch->isBitcodeArchive()) {
    is_native = true;
    return false;
  }
  is_native = false;

  // Save a set of symbols that are not defined by the archive. Since we're
  // entering a loop, there's no point searching for these multiple times. This
  // variable is used to "set_subtract" from the set of undefined symbols.
  std::set<std::string> NotDefinedByArchive;

  // Save the current set of undefined symbols, because we may have to make
  // multiple passes over the archive:
  std::set<std::string> CurrentlyUndefinedSymbols;

  do {
    CurrentlyUndefinedSymbols = UndefinedSymbols;

    // Find the modules we need to link into the target module
    std::set<ModuleProvider*> Modules;
    if (!arch->findModulesDefiningSymbols(UndefinedSymbols, Modules, &ErrMsg))
      return error("Cannot find symbols in '" + Filename.toString() +
                   "': " + ErrMsg);

    // If we didn't find any more modules to link this time, we are done
    // searching this archive.
    if (Modules.empty())
      break;

    // Any symbols remaining in UndefinedSymbols after
    // findModulesDefiningSymbols are ones that the archive does not define. So
    // we add them to the NotDefinedByArchive variable now.
    NotDefinedByArchive.insert(UndefinedSymbols.begin(),
        UndefinedSymbols.end());

    // Loop over all the ModuleProviders that we got back from the archive
    for (std::set<ModuleProvider*>::iterator I=Modules.begin(), E=Modules.end();
         I != E; ++I) {

      // Get the module we must link in.
      std::string moduleErrorMsg;
      std::auto_ptr<Module> AutoModule((*I)->releaseModule( &moduleErrorMsg ));
      if (!moduleErrorMsg.empty())
        return error("Could not load a module: " + moduleErrorMsg);

      Module* aModule = AutoModule.get();

      if (aModule != NULL) {
        verbose("  Linking in module: " + aModule->getModuleIdentifier());

        // Link it in
        if (LinkInModule(aModule, &moduleErrorMsg)) {
          return error("Cannot link in module '" +
                       aModule->getModuleIdentifier() + "': " + moduleErrorMsg);
        }
      }
    }

    // Get the undefined symbols from the aggregate module. This recomputes the
    // symbols we still need after the new modules have been linked in.
    GetAllUndefinedSymbols(Composite, UndefinedSymbols);

    // At this point we have two sets of undefined symbols: UndefinedSymbols
    // which holds the undefined symbols from all the modules, and
    // NotDefinedByArchive which holds symbols we know the archive doesn't
    // define. There's no point searching for symbols that we won't find in the
    // archive so we subtract these sets.
    set_subtract(UndefinedSymbols, NotDefinedByArchive);

    // If there's no symbols left, no point in continuing to search the
    // archive.
    if (UndefinedSymbols.empty())
      break;
  } while (CurrentlyUndefinedSymbols != UndefinedSymbols);

  return false;
}
<commit_msg>Properly populate lists of defined/undefined symbols in presence of aliases<commit_after>//===- lib/Linker/LinkArchives.cpp - Link LLVM objects and libraries ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains routines to handle linking together LLVM bitcode files,
// and to handle annoying things like static libraries.
//
//===----------------------------------------------------------------------===//

#include "llvm/Linker.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/Bitcode/Archive.h"
#include "llvm/Config/config.h"
#include <memory>
#include <set>
using namespace llvm;

/// GetAllUndefinedSymbols - calculates the set of undefined symbols that still
/// exist in an LLVM module. This is a bit tricky because there may be two
/// symbols with the same name but different LLVM types that will be resolved to
/// each other but aren't currently (thus we need to treat it as resolved).
///
/// Inputs:
///  M - The module in which to find undefined symbols.
///
/// Outputs:
///  UndefinedSymbols - A set of C++ strings containing the name of all
///                     undefined symbols.
///
static void
GetAllUndefinedSymbols(Module *M, std::set<std::string> &UndefinedSymbols) {
  std::set<std::string> DefinedSymbols;
  UndefinedSymbols.clear();

  // If the program doesn't define a main, try pulling one in from a .a file.
  // This is needed for programs where the main function is defined in an
  // archive, such f2c'd programs.
  Function *Main = M->getFunction("main");
  if (Main == 0 || Main->isDeclaration())
    UndefinedSymbols.insert("main");

  for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
    if (I->hasName()) {
      if (I->isDeclaration())
        UndefinedSymbols.insert(I->getName());
      else if (!I->hasInternalLinkage()) {
        assert(!I->hasDLLImportLinkage()
               && "Found dllimported non-external symbol!");
        DefinedSymbols.insert(I->getName());
      }
    }

  for (Module::global_iterator I = M->global_begin(), E = M->global_end();
       I != E; ++I)
    if (I->hasName()) {
      if (I->isDeclaration())
        UndefinedSymbols.insert(I->getName());
      else if (!I->hasInternalLinkage()) {
        assert(!I->hasDLLImportLinkage()
               && "Found dllimported non-external symbol!");
        DefinedSymbols.insert(I->getName());
      }
    }

  for (Module::alias_iterator I = M->alias_begin(), E = M->alias_end();
       I != E; ++I)
    if (I->hasName()) {
      const GlobalValue *Aliased = I->getAliasedGlobal();
      if (Aliased->isDeclaration())
        UndefinedSymbols.insert(I->getName());
      else
        DefinedSymbols.insert(I->getName());
    }

  // Prune out any defined symbols from the undefined symbols set...
  for (std::set<std::string>::iterator I = UndefinedSymbols.begin();
       I != UndefinedSymbols.end(); )
    if (DefinedSymbols.count(*I))
      UndefinedSymbols.erase(I++);  // This symbol really is defined!
    else
      ++I; // Keep this symbol in the undefined symbols list
}

/// LinkInArchive - opens an archive library and link in all objects which
/// provide symbols that are currently undefined.
///
/// Inputs:
///  Filename - The pathname of the archive.
///
/// Return Value:
///  TRUE  - An error occurred.
///  FALSE - No errors.
bool
Linker::LinkInArchive(const sys::Path &Filename, bool &is_native) {
  // Make sure this is an archive file we're dealing with
  if (!Filename.isArchive())
    return error("File '" + Filename.toString() + "' is not an archive.");

  // Open the archive file
  verbose("Linking archive file '" + Filename.toString() + "'");

  // Find all of the symbols currently undefined in the bitcode program.
  // If all the symbols are defined, the program is complete, and there is
  // no reason to link in any archive files.
  std::set<std::string> UndefinedSymbols;
  GetAllUndefinedSymbols(Composite, UndefinedSymbols);

  if (UndefinedSymbols.empty()) {
    verbose("No symbols undefined, skipping library '" +
            Filename.toString() + "'");
    return false;  // No need to link anything in!
  }

  std::string ErrMsg;
  std::auto_ptr<Archive> AutoArch (
    Archive::OpenAndLoadSymbols(Filename,&ErrMsg));

  Archive* arch = AutoArch.get();

  if (!arch)
    return error("Cannot read archive '" + Filename.toString() +
                 "': " + ErrMsg);
  if (!arch->isBitcodeArchive()) {
    is_native = true;
    return false;
  }
  is_native = false;

  // Save a set of symbols that are not defined by the archive. Since we're
  // entering a loop, there's no point searching for these multiple times. This
  // variable is used to "set_subtract" from the set of undefined symbols.
  std::set<std::string> NotDefinedByArchive;

  // Save the current set of undefined symbols, because we may have to make
  // multiple passes over the archive:
  std::set<std::string> CurrentlyUndefinedSymbols;

  do {
    CurrentlyUndefinedSymbols = UndefinedSymbols;

    // Find the modules we need to link into the target module
    std::set<ModuleProvider*> Modules;
    if (!arch->findModulesDefiningSymbols(UndefinedSymbols, Modules, &ErrMsg))
      return error("Cannot find symbols in '" + Filename.toString() +
                   "': " + ErrMsg);

    // If we didn't find any more modules to link this time, we are done
    // searching this archive.
    if (Modules.empty())
      break;

    // Any symbols remaining in UndefinedSymbols after
    // findModulesDefiningSymbols are ones that the archive does not define. So
    // we add them to the NotDefinedByArchive variable now.
    NotDefinedByArchive.insert(UndefinedSymbols.begin(),
        UndefinedSymbols.end());

    // Loop over all the ModuleProviders that we got back from the archive
    for (std::set<ModuleProvider*>::iterator I=Modules.begin(), E=Modules.end();
         I != E; ++I) {

      // Get the module we must link in.
      std::string moduleErrorMsg;
      std::auto_ptr<Module> AutoModule((*I)->releaseModule( &moduleErrorMsg ));
      if (!moduleErrorMsg.empty())
        return error("Could not load a module: " + moduleErrorMsg);

      Module* aModule = AutoModule.get();

      if (aModule != NULL) {
        verbose("  Linking in module: " + aModule->getModuleIdentifier());

        // Link it in
        if (LinkInModule(aModule, &moduleErrorMsg)) {
          return error("Cannot link in module '" +
                       aModule->getModuleIdentifier() + "': " + moduleErrorMsg);
        }
      }
    }

    // Get the undefined symbols from the aggregate module. This recomputes the
    // symbols we still need after the new modules have been linked in.
    GetAllUndefinedSymbols(Composite, UndefinedSymbols);

    // At this point we have two sets of undefined symbols: UndefinedSymbols
    // which holds the undefined symbols from all the modules, and
    // NotDefinedByArchive which holds symbols we know the archive doesn't
    // define. There's no point searching for symbols that we won't find in the
    // archive so we subtract these sets.
    set_subtract(UndefinedSymbols, NotDefinedByArchive);

    // If there's no symbols left, no point in continuing to search the
    // archive.
    if (UndefinedSymbols.empty())
      break;
  } while (CurrentlyUndefinedSymbols != UndefinedSymbols);

  return false;
}
<|endoftext|>


<commit_before>#include <build-bot/bot.h>

#include <boost/filesystem.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>

namespace fs = boost::filesystem;
using namespace dsn::build_bot;

namespace dsn {
namespace build_bot {
    namespace priv {
        class Bot : public dsn::log::Base<Bot> {
        protected:
            boost::property_tree::ptree m_settings;

            bool loadConfig(const std::string& config_file)
            {
                BOOST_LOG_SEV(log, severity::info) << "Loading configuration from " << config_file;

                fs::path path(config_file);
                if (!fs::exists(path)) {
                    BOOST_LOG_SEV(log, severity::error) << "Config file " << config_file << " doesn't exist!";
                    return false;
                }

                if (!fs::is_regular_file(path)) {
                    BOOST_LOG_SEV(log, severity::error) << "Config file " << config_file << " isn't a regular file!";
                    return false;
                }

                try {
                    boost::property_tree::read_ini(config_file, m_settings);
                }

                catch (boost::property_tree::ini_parser_error& ex) {
                    BOOST_LOG_SEV(log, severity::error) << "Failed to parse config file " << config_file << ": " << ex.what();
                    return false;
                }

                return true;
            }

        public:
            bool init(const std::string& config_file)
            {
                if (!loadConfig(config_file))
                    return false;

                return true;
            }
        };
    }
}
}

const std::string dsn::build_bot::Bot::DEFAULT_CONFIG_FILE{ "etc/build-bot/bot.conf" };

Bot::Bot()
    : m_impl(new priv::Bot())
{
}

Bot::~Bot()
{
}

bool Bot::init(const std::string& config_file)
{
    return m_impl->init(config_file);
}
<commit_msg>Initialize named pipe<commit_after>#include <build-bot/bot.h>

#include <sys/types.h>
#include <sys/stat.h>

#include <boost/filesystem.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>

namespace fs = boost::filesystem;
using namespace dsn::build_bot;

namespace dsn {
namespace build_bot {
    namespace priv {
        class Bot : public dsn::log::Base<Bot> {
        protected:
            boost::property_tree::ptree m_settings;

            bool loadConfig(const std::string& config_file)
            {
                BOOST_LOG_SEV(log, severity::info) << "Loading configuration from " << config_file;

                fs::path path(config_file);
                if (!fs::exists(path)) {
                    BOOST_LOG_SEV(log, severity::error) << "Config file " << config_file << " doesn't exist!";
                    return false;
                }

                if (!fs::is_regular_file(path)) {
                    BOOST_LOG_SEV(log, severity::error) << "Config file " << config_file << " isn't a regular file!";
                    return false;
                }

                try {
                    boost::property_tree::read_ini(config_file, m_settings);
                }

                catch (boost::property_tree::ini_parser_error& ex) {
                    BOOST_LOG_SEV(log, severity::error) << "Failed to parse config file " << config_file << ": " << ex.what();
                    return false;
                }

                return true;
            }

            bool initFifo()
            {
                std::string fifoName;
                try {
                    fifoName = m_settings.get<std::string>("fifo.name");
                }

                catch (boost::property_tree::ptree_error& ex) {
                    BOOST_LOG_SEV(log, severity::error) << "Failed to get FIFO settings from configuration: " << ex.what();
                    return false;
                }

                fs::path path(fifoName);
                if (!fs::exists(path)) {
                    BOOST_LOG_SEV(log, severity::warning) << "FIFO " << fifoName << " doesn't exist; trying to create it!";
                    if (mkfifo(fifoName.c_str(), 0666) == -1) {
                        BOOST_LOG_SEV(log, severity::error) << "Failed to create FIFO " << fifoName << ": " << strerror(errno);
                        return false;
                    }
                }

                return true;
            }

        public:
            bool init(const std::string& config_file)
            {
                if (!loadConfig(config_file))
                    return false;

                if (!initFifo())
                    return false;

                return true;
            }
        };
    }
}
}

const std::string dsn::build_bot::Bot::DEFAULT_CONFIG_FILE{ "etc/build-bot/bot.conf" };

Bot::Bot()
    : m_impl(new priv::Bot())
{
}

Bot::~Bot()
{
}

bool Bot::init(const std::string& config_file)
{
    return m_impl->init(config_file);
}
<|endoftext|>


<commit_before>// Copyright 2010-2021 Google LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "ortools/linear_solver/sat_proto_solver.h"

#include <cstdint>
#include <vector>

#include "absl/status/statusor.h"
#include "ortools/linear_solver/linear_solver.pb.h"
#include "ortools/linear_solver/model_validator.h"
#include "ortools/linear_solver/sat_solver_utils.h"
#include "ortools/port/proto_utils.h"
#include "ortools/sat/cp_model.pb.h"
#include "ortools/sat/cp_model_solver.h"
#include "ortools/sat/lp_utils.h"
#include "ortools/sat/sat_parameters.pb.h"
#include "ortools/util/logging.h"
#include "ortools/util/time_limit.h"

namespace operations_research {

namespace {

#if defined(PROTOBUF_INTERNAL_IMPL)
using google::protobuf::Message;
#else
using google::protobuf::Message;
#endif

// Proto-lite disables some features of protos (see
// go/abp-libraries/proto2-lite) and messages inherit from MessageLite directly
// instead of inheriting from Message (which is itself a specialization of
// MessageLite).
constexpr bool kProtoLiteSatParameters =
    !std::is_base_of<Message, sat::SatParameters>::value;

MPSolverResponseStatus ToMPSolverResponseStatus(sat::CpSolverStatus status,
                                                bool has_objective) {
  switch (status) {
    case sat::CpSolverStatus::UNKNOWN:
      return MPSOLVER_NOT_SOLVED;
    case sat::CpSolverStatus::MODEL_INVALID:
      return MPSOLVER_MODEL_INVALID;
    case sat::CpSolverStatus::FEASIBLE:
      return has_objective ? MPSOLVER_FEASIBLE : MPSOLVER_OPTIMAL;
    case sat::CpSolverStatus::INFEASIBLE:
      return MPSOLVER_INFEASIBLE;
    case sat::CpSolverStatus::OPTIMAL:
      return MPSOLVER_OPTIMAL;
    default: {
    }
  }
  return MPSOLVER_ABNORMAL;
}
}  // namespace

absl::StatusOr<MPSolutionResponse> SatSolveProto(
    MPModelRequest request, std::atomic<bool>* interrupt_solve,
    std::function<void(const std::string&)> logging_callback,
    std::function<void(const MPSolution&)> solution_callback) {
  sat::SatParameters params;
  params.set_log_search_progress(request.enable_internal_solver_output());
  if (request.has_solver_specific_parameters()) {
    // See EncodeSatParametersAsString() documentation.
    if (kProtoLiteSatParameters) {
      if (!params.MergeFromString(request.solver_specific_parameters())) {
        return absl::InvalidArgumentError(
            "solver_specific_parameters is not a valid binary stream of the "
            "SatParameters proto");
      }
    } else {
      if (!ProtobufTextFormatMergeFromString(
              request.solver_specific_parameters(), &params)) {
        return absl::InvalidArgumentError(
            "solver_specific_parameters is not a valid textual representation "
            "of the SatParameters proto");
      }
    }
  }
  if (request.has_solver_time_limit_seconds()) {
    params.set_max_time_in_seconds(request.solver_time_limit_seconds());
  }

  // TODO(user): We do not support all the parameters here. In particular the
  // logs before the solver is called will not be appended to the response. Fix
  // that, and remove code duplication for the logger config. One way should be
  // to not touch/configure anything if the logger is already created while
  // calling SolveCpModel() and call a common config function from here or from
  // inside Solve()?
  SolverLogger logger;
  if (logging_callback != nullptr) {
    logger.AddInfoLoggingCallback(logging_callback);
  }
  logger.EnableLogging(params.log_search_progress());
  logger.SetLogToStdOut(params.log_to_stdout());

  MPSolutionResponse response;
  if (!ExtractValidMPModelInPlaceOrPopulateResponseStatus(&request,
                                                          &response)) {
    if (logger.LoggingIsEnabled()) {
      // This is needed for our benchmark scripts.
      sat::CpSolverResponse cp_response;
      cp_response.set_status(sat::CpSolverStatus::MODEL_INVALID);
      SOLVER_LOG(&logger, CpSolverResponseStats(cp_response));
    }
    return response;
  }

  // Note(user): the LP presolvers API is a bit weird and keep a reference to
  // the given GlopParameters, so we need to make sure it outlive them.
  const glop::GlopParameters glop_params;
  MPModelProto* const mp_model = request.mutable_model();
  std::vector<std::unique_ptr<glop::Preprocessor>> for_postsolve;
  if (!params.enumerate_all_solutions()) {
    const auto status =
        ApplyMipPresolveSteps(glop_params, mp_model, &for_postsolve, &logger);
    if (status == MPSolverResponseStatus::MPSOLVER_INFEASIBLE) {
      if (params.log_search_progress()) {
        // This is needed for our benchmark scripts.
        sat::CpSolverResponse cp_response;
        cp_response.set_status(sat::CpSolverStatus::INFEASIBLE);
        LOG(INFO) << CpSolverResponseStats(cp_response);
      }
      response.set_status(MPSolverResponseStatus::MPSOLVER_INFEASIBLE);
      response.set_status_str("Problem proven infeasible during MIP presolve");
      return response;
    }
  }

  // We need to do that before the automatic detection of integers.
  RemoveNearZeroTerms(params, mp_model, &logger);

  SOLVER_LOG(&logger, "");
  SOLVER_LOG(&logger, "Scaling to pure integer problem.");

  const int num_variables = mp_model->variable_size();
  std::vector<double> var_scaling(num_variables, 1.0);
  if (params.mip_automatically_scale_variables()) {
    var_scaling = sat::DetectImpliedIntegers(mp_model, &logger);
  }
  if (params.mip_var_scaling() != 1.0) {
    const std::vector<double> other_scaling = sat::ScaleContinuousVariables(
        params.mip_var_scaling(), params.mip_max_bound(), mp_model);
    for (int i = 0; i < var_scaling.size(); ++i) {
      var_scaling[i] *= other_scaling[i];
    }
  }

  sat::CpModelProto cp_model;
  if (!ConvertMPModelProtoToCpModelProto(params, *mp_model, &cp_model,
                                         &logger)) {
    if (params.log_search_progress()) {
      // This is needed for our benchmark scripts.
      sat::CpSolverResponse cp_response;
      cp_response.set_status(sat::CpSolverStatus::MODEL_INVALID);
      LOG(INFO) << CpSolverResponseStats(cp_response);
    }
    response.set_status(MPSOLVER_MODEL_INVALID);
    response.set_status_str("Failed to convert model into CP-SAT model");
    return response;
  }
  DCHECK_EQ(cp_model.variables().size(), var_scaling.size());
  DCHECK_EQ(cp_model.variables().size(), mp_model->variable().size());

  // Copy and scale the hint if there is one.
  if (request.model().has_solution_hint()) {
    auto* cp_model_hint = cp_model.mutable_solution_hint();
    const int size = request.model().solution_hint().var_index().size();
    for (int i = 0; i < size; ++i) {
      const int var = request.model().solution_hint().var_index(i);
      if (var >= var_scaling.size()) continue;

      // To handle weird hint input values, we cap any large value to +/-
      // mip_max_bound() which is also the min/max value of any variable once
      // scaled.
      double value =
          request.model().solution_hint().var_value(i) * var_scaling[var];
      if (std::abs(value) > params.mip_max_bound()) {
        value = value > 0 ? params.mip_max_bound() : -params.mip_max_bound();
      }

      cp_model_hint->add_vars(var);
      cp_model_hint->add_values(static_cast<int64_t>(std::round(value)));
    }
  }

  // We no longer need the request. Reclaim its memory.
  const int old_num_variables = mp_model->variable().size();
  const int old_num_constraints = mp_model->constraint().size();
  request.Clear();

  // Configure model.
  sat::Model sat_model;
  sat_model.Register<SolverLogger>(&logger);
  sat_model.Add(NewSatParameters(params));
  if (interrupt_solve != nullptr) {
    sat_model.GetOrCreate<TimeLimit>()->RegisterExternalBooleanAsLimit(
        interrupt_solve);
  }

  auto post_solve = [&](const sat::CpSolverResponse& cp_response) {
    MPSolution mp_solution;
    mp_solution.set_objective_value(cp_response.objective_value());
    // Postsolve the bound shift and scaling.
    glop::ProblemSolution glop_solution((glop::RowIndex(old_num_constraints)),
                                        (glop::ColIndex(old_num_variables)));
    for (int v = 0; v < glop_solution.primal_values.size(); ++v) {
      glop_solution.primal_values[glop::ColIndex(v)] =
          static_cast<double>(cp_response.solution(v)) / var_scaling[v];
    }
    for (int i = for_postsolve.size(); --i >= 0;) {
      for_postsolve[i]->RecoverSolution(&glop_solution);
    }
    for (int v = 0; v < glop_solution.primal_values.size(); ++v) {
      mp_solution.add_variable_value(
          glop_solution.primal_values[glop::ColIndex(v)]);
    }
    return mp_solution;
  };

  if (solution_callback != nullptr) {
    sat_model.Add(sat::NewFeasibleSolutionObserver(
        [&](const sat::CpSolverResponse& cp_response) {
          solution_callback(post_solve(cp_response));
        }));
  }

  // Solve.
  const sat::CpSolverResponse cp_response =
      sat::SolveCpModel(cp_model, &sat_model);

  // Convert the response.
  //
  // TODO(user): Implement the row and column status.
  response.set_status(
      ToMPSolverResponseStatus(cp_response.status(), cp_model.has_objective()));
  if (response.status() == MPSOLVER_FEASIBLE ||
      response.status() == MPSOLVER_OPTIMAL) {
    response.set_objective_value(cp_response.objective_value());
    response.set_best_objective_bound(cp_response.best_objective_bound());
    MPSolution post_solved_solution = post_solve(cp_response);
    *response.mutable_variable_value() =
        std::move(*post_solved_solution.mutable_variable_value());
  }

  return response;
}

std::string EncodeSatParametersAsString(const sat::SatParameters& parameters) {
  if (kProtoLiteSatParameters) {
    // Here we use SerializeToString() instead of SerializeAsString() since the
    // later ignores errors and returns an empty string instead (which can be a
    // valid value when no fields are set).
    std::string bytes;
    CHECK(parameters.SerializeToString(&bytes));
    return bytes;
  }

  return parameters.ShortDebugString();
}

}  // namespace operations_research
<commit_msg>Enable collecting all solutions found in the linear solver wrapper using the CP-SAT backend<commit_after>// Copyright 2010-2021 Google LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "ortools/linear_solver/sat_proto_solver.h"

#include <cstdint>
#include <vector>

#include "absl/status/statusor.h"
#include "ortools/linear_solver/linear_solver.pb.h"
#include "ortools/linear_solver/model_validator.h"
#include "ortools/linear_solver/sat_solver_utils.h"
#include "ortools/port/proto_utils.h"
#include "ortools/sat/cp_model.pb.h"
#include "ortools/sat/cp_model_solver.h"
#include "ortools/sat/lp_utils.h"
#include "ortools/sat/sat_parameters.pb.h"
#include "ortools/util/logging.h"
#include "ortools/util/time_limit.h"

namespace operations_research {

namespace {

#if defined(PROTOBUF_INTERNAL_IMPL)
using google::protobuf::Message;
#else
using google::protobuf::Message;
#endif

// Proto-lite disables some features of protos (see
// go/abp-libraries/proto2-lite) and messages inherit from MessageLite directly
// instead of inheriting from Message (which is itself a specialization of
// MessageLite).
constexpr bool kProtoLiteSatParameters =
    !std::is_base_of<Message, sat::SatParameters>::value;

MPSolverResponseStatus ToMPSolverResponseStatus(sat::CpSolverStatus status,
                                                bool has_objective) {
  switch (status) {
    case sat::CpSolverStatus::UNKNOWN:
      return MPSOLVER_NOT_SOLVED;
    case sat::CpSolverStatus::MODEL_INVALID:
      return MPSOLVER_MODEL_INVALID;
    case sat::CpSolverStatus::FEASIBLE:
      return has_objective ? MPSOLVER_FEASIBLE : MPSOLVER_OPTIMAL;
    case sat::CpSolverStatus::INFEASIBLE:
      return MPSOLVER_INFEASIBLE;
    case sat::CpSolverStatus::OPTIMAL:
      return MPSOLVER_OPTIMAL;
    default: {
    }
  }
  return MPSOLVER_ABNORMAL;
}
}  // namespace

absl::StatusOr<MPSolutionResponse> SatSolveProto(
    MPModelRequest request, std::atomic<bool>* interrupt_solve,
    std::function<void(const std::string&)> logging_callback,
    std::function<void(const MPSolution&)> solution_callback) {
  sat::SatParameters params;
  params.set_log_search_progress(request.enable_internal_solver_output());
  if (request.has_solver_specific_parameters()) {
    // See EncodeSatParametersAsString() documentation.
    if (kProtoLiteSatParameters) {
      if (!params.MergeFromString(request.solver_specific_parameters())) {
        return absl::InvalidArgumentError(
            "solver_specific_parameters is not a valid binary stream of the "
            "SatParameters proto");
      }
    } else {
      if (!ProtobufTextFormatMergeFromString(
              request.solver_specific_parameters(), &params)) {
        return absl::InvalidArgumentError(
            "solver_specific_parameters is not a valid textual representation "
            "of the SatParameters proto");
      }
    }
  }
  if (request.has_solver_time_limit_seconds()) {
    params.set_max_time_in_seconds(request.solver_time_limit_seconds());
  }

  // TODO(user): We do not support all the parameters here. In particular the
  // logs before the solver is called will not be appended to the response. Fix
  // that, and remove code duplication for the logger config. One way should be
  // to not touch/configure anything if the logger is already created while
  // calling SolveCpModel() and call a common config function from here or from
  // inside Solve()?
  SolverLogger logger;
  if (logging_callback != nullptr) {
    logger.AddInfoLoggingCallback(logging_callback);
  }
  logger.EnableLogging(params.log_search_progress());
  logger.SetLogToStdOut(params.log_to_stdout());

  MPSolutionResponse response;
  if (!ExtractValidMPModelInPlaceOrPopulateResponseStatus(&request,
                                                          &response)) {
    if (logger.LoggingIsEnabled()) {
      // This is needed for our benchmark scripts.
      sat::CpSolverResponse cp_response;
      cp_response.set_status(sat::CpSolverStatus::MODEL_INVALID);
      SOLVER_LOG(&logger, CpSolverResponseStats(cp_response));
    }
    return response;
  }

  // Note(user): the LP presolvers API is a bit weird and keep a reference to
  // the given GlopParameters, so we need to make sure it outlive them.
  const glop::GlopParameters glop_params;
  MPModelProto* const mp_model = request.mutable_model();
  std::vector<std::unique_ptr<glop::Preprocessor>> for_postsolve;
  if (!params.enumerate_all_solutions()) {
    const auto status =
        ApplyMipPresolveSteps(glop_params, mp_model, &for_postsolve, &logger);
    if (status == MPSolverResponseStatus::MPSOLVER_INFEASIBLE) {
      if (params.log_search_progress()) {
        // This is needed for our benchmark scripts.
        sat::CpSolverResponse cp_response;
        cp_response.set_status(sat::CpSolverStatus::INFEASIBLE);
        LOG(INFO) << CpSolverResponseStats(cp_response);
      }
      response.set_status(MPSolverResponseStatus::MPSOLVER_INFEASIBLE);
      response.set_status_str("Problem proven infeasible during MIP presolve");
      return response;
    }
  }

  // We need to do that before the automatic detection of integers.
  RemoveNearZeroTerms(params, mp_model, &logger);

  SOLVER_LOG(&logger, "");
  SOLVER_LOG(&logger, "Scaling to pure integer problem.");

  const int num_variables = mp_model->variable_size();
  std::vector<double> var_scaling(num_variables, 1.0);
  if (params.mip_automatically_scale_variables()) {
    var_scaling = sat::DetectImpliedIntegers(mp_model, &logger);
  }
  if (params.mip_var_scaling() != 1.0) {
    const std::vector<double> other_scaling = sat::ScaleContinuousVariables(
        params.mip_var_scaling(), params.mip_max_bound(), mp_model);
    for (int i = 0; i < var_scaling.size(); ++i) {
      var_scaling[i] *= other_scaling[i];
    }
  }

  sat::CpModelProto cp_model;
  if (!ConvertMPModelProtoToCpModelProto(params, *mp_model, &cp_model,
                                         &logger)) {
    if (params.log_search_progress()) {
      // This is needed for our benchmark scripts.
      sat::CpSolverResponse cp_response;
      cp_response.set_status(sat::CpSolverStatus::MODEL_INVALID);
      LOG(INFO) << CpSolverResponseStats(cp_response);
    }
    response.set_status(MPSOLVER_MODEL_INVALID);
    response.set_status_str("Failed to convert model into CP-SAT model");
    return response;
  }
  DCHECK_EQ(cp_model.variables().size(), var_scaling.size());
  DCHECK_EQ(cp_model.variables().size(), mp_model->variable().size());

  // Copy and scale the hint if there is one.
  if (request.model().has_solution_hint()) {
    auto* cp_model_hint = cp_model.mutable_solution_hint();
    const int size = request.model().solution_hint().var_index().size();
    for (int i = 0; i < size; ++i) {
      const int var = request.model().solution_hint().var_index(i);
      if (var >= var_scaling.size()) continue;

      // To handle weird hint input values, we cap any large value to +/-
      // mip_max_bound() which is also the min/max value of any variable once
      // scaled.
      double value =
          request.model().solution_hint().var_value(i) * var_scaling[var];
      if (std::abs(value) > params.mip_max_bound()) {
        value = value > 0 ? params.mip_max_bound() : -params.mip_max_bound();
      }

      cp_model_hint->add_vars(var);
      cp_model_hint->add_values(static_cast<int64_t>(std::round(value)));
    }
  }

  // We no longer need the request. Reclaim its memory.
  const int old_num_variables = mp_model->variable().size();
  const int old_num_constraints = mp_model->constraint().size();
  request.Clear();

  // Configure model.
  sat::Model sat_model;
  sat_model.Register<SolverLogger>(&logger);
  sat_model.Add(NewSatParameters(params));
  if (interrupt_solve != nullptr) {
    sat_model.GetOrCreate<TimeLimit>()->RegisterExternalBooleanAsLimit(
        interrupt_solve);
  }

  auto post_solve = [&](const sat::CpSolverResponse& cp_response) {
    MPSolution mp_solution;
    mp_solution.set_objective_value(cp_response.objective_value());
    // Postsolve the bound shift and scaling.
    glop::ProblemSolution glop_solution((glop::RowIndex(old_num_constraints)),
                                        (glop::ColIndex(old_num_variables)));
    for (int v = 0; v < glop_solution.primal_values.size(); ++v) {
      glop_solution.primal_values[glop::ColIndex(v)] =
          static_cast<double>(cp_response.solution(v)) / var_scaling[v];
    }
    for (int i = for_postsolve.size(); --i >= 0;) {
      for_postsolve[i]->RecoverSolution(&glop_solution);
    }
    for (int v = 0; v < glop_solution.primal_values.size(); ++v) {
      mp_solution.add_variable_value(
          glop_solution.primal_values[glop::ColIndex(v)]);
    }
    return mp_solution;
  };

  if (solution_callback != nullptr) {
    sat_model.Add(sat::NewFeasibleSolutionObserver(
        [&](const sat::CpSolverResponse& cp_response) {
          solution_callback(post_solve(cp_response));
        }));
  }

  // Solve.
  const sat::CpSolverResponse cp_response =
      sat::SolveCpModel(cp_model, &sat_model);

  // Convert the response.
  //
  // TODO(user): Implement the row and column status.
  response.set_status(
      ToMPSolverResponseStatus(cp_response.status(), cp_model.has_objective()));
  if (response.status() == MPSOLVER_FEASIBLE ||
      response.status() == MPSOLVER_OPTIMAL) {
    response.set_objective_value(cp_response.objective_value());
    response.set_best_objective_bound(cp_response.best_objective_bound());
    MPSolution post_solved_solution = post_solve(cp_response);
    *response.mutable_variable_value() =
        std::move(*post_solved_solution.mutable_variable_value());
  }

  // Copy and postsolve any additional solutions.
  //
  // TODO(user): Remove the postsolve hack of copying to a response.
  for (int i = 0; i < cp_response.additional_solutions().size(); ++i) {
    sat::CpSolverResponse temp;
    *temp.mutable_solution() = cp_response.additional_solutions(i).values();
    MPSolution post_solved_solution = post_solve(temp);
    *(response.add_additional_solutions()->mutable_variable_value()) =
        std::move(*post_solved_solution.mutable_variable_value());
  }

  return response;
}

std::string EncodeSatParametersAsString(const sat::SatParameters& parameters) {
  if (kProtoLiteSatParameters) {
    // Here we use SerializeToString() instead of SerializeAsString() since the
    // later ignores errors and returns an empty string instead (which can be a
    // valid value when no fields are set).
    std::string bytes;
    CHECK(parameters.SerializeToString(&bytes));
    return bytes;
  }

  return parameters.ShortDebugString();
}

}  // namespace operations_research
<|endoftext|>


<commit_before>//
//
// MIT License
//
// Copyright (c) 2017 Stellacore Corporation.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//

/*! \file
\brief  This file contains main application program demoRaw10
*/

#include "libapp/Usage.h"

#include "build/version.h"
#include "libio/stream.h"

#include "libdat/grid.h"
#include "libdat/info.h"
#include "libimg/cfa.h"
#include "libimg/io.h"
#include "libimg/raw10.h"
#include "libimg/stats.h"
#include "libprob/mean.h"

#include "libprob/CdfForward.h"
#include "libprob/Frac9.h"

#include "libapp/Timer.h"

namespace
{
	//! Report file save status
	void
	reportSave
		( bool const & okaySave
		, std::string const & pathOut
		)
	{
		if (okaySave)
		{
			io::out() << "Success: saved to '" << pathOut << "'\n";
		}
		else
		{
			io::err() << "ERROR: couldn't save to '" << pathOut << "'\n";
		}
	}
}

//! Read a 'raw10' formated binary (e.g. from Raspberry Pi cameras)
int
main
	( int const argc
	, char const * const * const argv
	)
{
	// Don't mix stdio & streams (for performance)
	//std::ios::sync_with_stdio(false);

	// check args
	app::Usage usage;
	usage.setSummary
		( "Read (Raspberry Pi Camera) 'raw10' image format and save components"
		);
	usage.addArg("PathInput", "Input data file <raw10 format>");
	// ...
	if (usage.argStatus(argc, argv) != app::Usage::Valid)
	{
		std::string const fname(argv[0]);
		io::err()
			<< std::endl << build::version::buildInfo(argv[0]) << std::endl
			<< usage.infoString(fname) << std::endl;
		return 1;
	}

	// parse input argument
	int argnum(0);
	std::string const pathRaw(argv[++argnum]);
	std::string const pathOutPix{ "uGrid.png" };
	std::string const pathOutFlt{ "fGrid.pgm" };

	app::Timer timer;

	// load file (active) data into memory
	timer.start("load.quads");
	img::raw10::Sizes const raspi(img::raw10::RasPiV2{});
	dat::grid<img::raw10::FourPix> const rawQuads
		{ img::io::loadFourPixGrid(pathRaw, raspi) };
	timer.stop();

	// convert to uint8 image
	timer.start("decode.uint8");
	dat::grid<uint8_t> const uGrid
		{ img::convert::pixelGridFor<uint8_t>(rawQuads) };
	timer.stop();

	// convert to float image
	timer.start("decode.float");
	dat::grid<float> const fGrid
		{ img::convert::pixelGridFor<float>(rawQuads) };
	timer.stop();

	// split into individual channels
	timer.start("bands.split");
	std::array<dat::grid<uint8_t>, 4u> const bands
		{ img::cfa::channelsFromRGGB<uint8_t>(uGrid) };
	timer.stop();

	// compute statistics
	timer.start("minmax.uint8");
	dat::MinMax<uint8_t> const uMinMax
		{ img::stats::activeMinMax<uint8_t>(uGrid.begin(), uGrid.end()) };
	timer.stop();
	timer.start("minmax.float");
	dat::MinMax<float> const fMinMax
		{ img::stats::activeMinMax<float>(fGrid.begin(), fGrid.end()) };
	timer.stop();

	// save to files
	timer.start("save.uint8(png)");
	bool const okayPix{ img::io::savePng(uGrid, pathOutPix) };
	timer.start("save.float(pgm)");
	bool const okayFlt{ img::io::savePgmAutoScale(fGrid, pathOutFlt) };
	timer.stop();
	timer.start("save.bands(pgm)");
	std::array<std::string, 4u> const bandNames
		{ "band0.pgm", "band1.pgm", "band2.pgm", "band3.pgm" };
	std::array<bool, 4u> const okayBands
		{ img::io::savePgm(bands[0], bandNames[0])
		, img::io::savePgm(bands[1], bandNames[1])
		, img::io::savePgm(bands[2], bandNames[2])
		, img::io::savePgm(bands[3], bandNames[3])
		};
	timer.stop();

	// report actions
	io::out() << dat::infoString(pathRaw, "pathRaw") << '\n';
	io::out() << '\n';

	io::out() << dat::infoString(uGrid, "uGrid") << '\n';
	io::out() << dat::infoString(uMinMax, "uMinMax") << '\n';
	io::out() << '\n';

	io::out() << dat::infoString(fGrid, "fGrid") << '\n';
	io::out() << dat::infoString(fMinMax, "fMinMax") << '\n';
	io::out() << '\n';

	// Analyse invidiual band data
	std::array<double, 4u> bMedians{};
	for (size_t nn{0u} ; nn < okayBands.size() ; ++nn)
	{
		static dat::Range<double> const uRange{ 0., 255. };
		static math::Partition const uPart(uRange, 256u);
		prob::CdfForward const cdf
			{ prob::CdfForward::fromSamps
				(bands[nn].begin(), bands[nn].end(), uPart)
			};
		prob::Frac9 const bFracs(cdf);
		bMedians[nn] = bFracs.median();
		//io::out() << dat::infoString(bFracs, "bFracs") << '\n';
	}
	double const bTgt
		{ prob::mean::geometric(bMedians.begin(), bMedians.end()) };
	std::array<double, 4u> const bGains
		{ bTgt/bMedians[0]
		, bTgt/bMedians[1]
		, bTgt/bMedians[2]
		, bTgt/bMedians[3]
		};
	// create grayscale image
//	grayFastFrom2x2(... need 2x2 generic gains ...);

	io::out() << dat::infoString(bMedians, "bMedians") << '\n';
	io::out() << dat::infoString(bGains, "bGains") << '\n';
	io::out() << dat::infoString(bTgt, "bTgt") << '\n';

	io::out() << dat::infoString(timer, "processing times") << '\n';
	io::out() << std::endl;

	reportSave(okayPix, pathOutPix);
	reportSave(okayFlt, pathOutFlt);
	reportSave(okayBands[0], bandNames[0]);
	reportSave(okayBands[1], bandNames[1]);
	reportSave(okayBands[2], bandNames[2]);
	reportSave(okayBands[3], bandNames[3]);
	io::out() << std::endl;

	return 0;
}

<commit_msg>testimg/demoRaw10 added output of low bits image<commit_after>//
//
// MIT License
//
// Copyright (c) 2017 Stellacore Corporation.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
// KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//

/*! \file
\brief  This file contains main application program demoRaw10
*/

#include "libapp/Usage.h"

#include "build/version.h"
#include "libio/stream.h"

#include "libdat/grid.h"
#include "libdat/info.h"
#include "libimg/cfa.h"
#include "libimg/io.h"
#include "libimg/raw10.h"
#include "libimg/stats.h"
#include "libprob/mean.h"

#include "libprob/CdfForward.h"
#include "libprob/Frac9.h"

#include "libapp/Timer.h"

namespace
{
	//! Report file save status
	void
	reportSave
		( bool const & okaySave
		, std::string const & pathOut
		)
	{
		if (okaySave)
		{
			io::out() << "Success: saved to '" << pathOut << "'\n";
		}
		else
		{
			io::err() << "ERROR: couldn't save to '" << pathOut << "'\n";
		}
	}

	//! Median values for each channel
	template <typename PixType>
	std::array<double, 4u>
	bandMediansFrom
		( std::array<dat::grid<PixType>, 4u> const bands
		)
	{
		std::array<double, 4u> bMedians{};
		for (size_t nn{0u} ; nn < bands.size() ; ++nn)
		{
			static dat::Range<double> const uRange{ 0., 255. };
			static math::Partition const uPart(uRange, 256u);
			prob::CdfForward const cdf
				{ prob::CdfForward::fromSamps
					(bands[nn].begin(), bands[nn].end(), uPart)
				};
			prob::Frac9 const bFracs(cdf);
			bMedians[nn] = bFracs.median();
			//io::out() << dat::infoString(bFracs, "bFracs") << '\n';
		}
		return bMedians;
	}

	//! Display cell contents
	std::string
	infoString
		( img::cfa::Cell<float> const & cell
		, std::string const & title = {}
		)
	{
		std::ostringstream oss;
		if (! title.empty())
		{
			oss << title << std::endl;
		}
		static std::string const pad{ "   " };
		oss
			<< pad << dat::infoString(cell.theElems[0][0], "cell[0][0]")
			<< pad << dat::infoString(cell.theElems[0][0], "cell[0][0]")
			<< std::endl
			<< pad << dat::infoString(cell.theElems[1][0], "cell[1][0]")
			<< pad << dat::infoString(cell.theElems[1][0], "cell[1][0]")
			;
		return oss.str();
	}
}

//! Read a 'raw10' formated binary (e.g. from Raspberry Pi cameras)
int
main
	( int const argc
	, char const * const * const argv
	)
{
	// Don't mix stdio & streams (for performance)
	//std::ios::sync_with_stdio(false);

	// check args
	app::Usage usage;
	usage.setSummary
		( "Read (Raspberry Pi Camera) 'raw10' image format and save components"
		);
	usage.addArg("PathInput", "Input data file <raw10 format>");
	// ...
	if (usage.argStatus(argc, argv) != app::Usage::Valid)
	{
		std::string const fname(argv[0]);
		io::err()
			<< std::endl << build::version::buildInfo(argv[0]) << std::endl
			<< usage.infoString(fname) << std::endl;
		return 1;
	}

	// parse input argument
	int argnum(0);
	std::string const pathRaw(argv[++argnum]);
	std::string const pathOutPix{ "uGrid.png" };
	std::string const pathOutFlt{ "fGrid.pgm" };
	std::string const pathOutGray{ "gGrid.pgm" };

	app::Timer timer;

	// load file (active) data into memory
	timer.start("load.quads");
	img::raw10::Sizes const raspi(img::raw10::RasPiV2{});
	dat::grid<img::raw10::FourPix> const rawQuads
		{ img::io::loadFourPixGrid(pathRaw, raspi) };
	timer.stop();

	// convert to uint8 image
	timer.start("decode.uint8");
	dat::grid<uint8_t> const uGrid
		{ img::convert::pixelGridFor<uint8_t>(rawQuads) };
	timer.stop();

	// convert to float image
	timer.start("decode.float");
	dat::grid<float> const fGrid
		{ img::convert::pixelGridFor<float>(rawQuads) };
	timer.stop();

	// split into individual channels
	timer.start("bands.split");
	std::array<dat::grid<uint8_t>, 4u> const bands
		{ img::cfa::channelsFromRGGB<uint8_t>(uGrid) };
	timer.stop();

	// compute statistics
	timer.start("minmax.uint8");
	dat::MinMax<uint8_t> const uMinMax
		{ img::stats::activeMinMax<uint8_t>(uGrid.begin(), uGrid.end()) };
	timer.stop();
	timer.start("minmax.float");
	dat::MinMax<float> const fMinMax
		{ img::stats::activeMinMax<float>(fGrid.begin(), fGrid.end()) };
	timer.stop();

	// save to files
	timer.start("save.uint8(png)");
	bool const okayPix{ img::io::savePng(uGrid, pathOutPix) };
	timer.start("save.float(pgm)");
	bool const okayFlt{ img::io::savePgmAutoScale(fGrid, pathOutFlt) };
	timer.stop();
	timer.start("save.bands(pgm)");
	std::array<std::string, 4u> const bandNames
		{ "band0.pgm", "band1.pgm", "band2.pgm", "band3.pgm" };
	std::array<bool, 4u> const okayBands
		{ img::io::savePgm(bands[0], bandNames[0])
		, img::io::savePgm(bands[1], bandNames[1])
		, img::io::savePgm(bands[2], bandNames[2])
		, img::io::savePgm(bands[3], bandNames[3])
		};
	timer.stop();

	// report actions
	io::out() << dat::infoString(pathRaw, "pathRaw") << '\n';
	io::out() << '\n';

	io::out() << dat::infoString(uGrid, "uGrid") << '\n';
	io::out() << dat::infoString(uMinMax, "uMinMax") << '\n';
	io::out() << '\n';

	io::out() << dat::infoString(fGrid, "fGrid") << '\n';
	io::out() << dat::infoString(fMinMax, "fMinMax") << '\n';
	io::out() << '\n';

	// Analyse invidiual band data
	std::array<double, 4u> const bMedians{ bandMediansFrom(bands) };
	double const bTgt
		{ prob::mean::geometric(bMedians.begin(), bMedians.end()) };
	img::cfa::Cell<float> cellGains
		{ static_cast<float>(bTgt/bMedians[0])
		, static_cast<float>(bTgt/bMedians[1])
		, static_cast<float>(bTgt/bMedians[2])
		, static_cast<float>(bTgt/bMedians[3])
		};
	// create grayscale image
	dat::grid<float> const gGrid{ img::cfa::grayGridFor(fGrid, cellGains) };
	std::array<dat::grid<float>, 4u> const gBands
		{ img::cfa::channelsFromRGGB<float>(gGrid) };
	std::array<double, 4u> const gMedians{ bandMediansFrom(gBands) };
	bool const okayGray{ img::io::savePgmAutoScale(gGrid, pathOutGray) };

	io::out() << dat::infoString(bMedians, "bMedians") << '\n';
	io::out() << infoString(cellGains, "cellGains") << '\n';
	io::out() << dat::infoString(bTgt, "bTgt") << '\n';
	io::out() << dat::infoString(gMedians, "gMedians") << '\n';

	io::out() << dat::infoString(timer, "processing times") << '\n';
	io::out() << std::endl;

	reportSave(okayPix, pathOutPix);
	reportSave(okayFlt, pathOutFlt);
	reportSave(okayGray, pathOutGray);
	reportSave(okayBands[0], bandNames[0]);
	reportSave(okayBands[1], bandNames[1]);
	reportSave(okayBands[2], bandNames[2]);
	reportSave(okayBands[3], bandNames[3]);
	io::out() << std::endl;

	dat::grid<uint16_t> const sGrid
		{ img::convert::pixelGridFor<uint16_t>(rawQuads) };
	dat::MinMax<uint16_t> const sMinMax
		{ img::stats::activeMinMax<uint16_t>(sGrid.begin(), sGrid.end()) };
	dat::grid<uint8_t> loGrid(sGrid.hwSize());
	dat::grid<uint8_t>::iterator itN{ loGrid.begin() };
	for (dat::grid<uint16_t>::const_iterator
		itS{ sGrid.begin() } ; sGrid.end() != itS ; ++itS, ++itN)
	{
		uint16_t const & sElem = *itS;
		uint8_t & loElem = *itN;
		loElem = (uint8_t)((sElem % 4) << 6u);
	//	loElem = (uint8_t)((sElem & 0xFF00) >> 8u);
	}
	img::io::savePng(loGrid, "loGrid.png");
	io::out() << dat::infoString(sMinMax, "sMinMax") << '\n';

	return 0;
}

<|endoftext|>


<commit_before>/// \file libuobject/main.cc

#include <libport/cstdio>
#include <libport/unistd.h>
#include <cerrno>

#include <iostream>
#include <list>
#include <sstream>

#include <libport/cli.hh>
#include <libport/containers.hh>
#include <libport/package-info.hh>
#include <libport/program-name.hh>
#include <libport/sysexits.hh>

#include <urbi/package-info.hh>
#include <urbi/uexternal.hh>
#include <urbi/umain.hh>
#include <urbi/uobject.hh>
#include <urbi/usyncclient.hh>

using libport::program_name;

namespace urbi
{

  namespace
  {

    /// Find in baseURBIStarter::list an object named \a named.
    /// Report errors to \a client.
    /// \return a pointer to the object found, 0 otherwise.
    static
    baseURBIStarter*
    find_object(UAbstractClient& client,
                const std::string& name)
    {
      typedef baseURBIStarter::list_type::iterator iterator;
      iterator i_end = baseURBIStarter::list().end();
      iterator found = i_end;
      for (iterator i = baseURBIStarter::list().begin(); i != i_end; ++i)
        if ((*i)->name == name)
        {
          if (found != i_end)
            client.printf("Double object definition %s\n", name.c_str());
          else
            found = i;
        }

      if (found == i_end)
      {
        client.printf("Unknown object definition %s\n", name.c_str());
        return 0;
      }
      else
        return *found;
    }
  }

  UCallbackAction
  dispatcher(const UMessage& msg)
  {
    typedef UTable::callbacks_type callbacks_type;
    //check message type
    if (msg.type != MESSAGE_DATA || msg.value->type != DATA_LIST)
    {
      msg.client.printf("Component Error: "
			"unknown message content, type %d\n",
			msg.type);
      return URBI_CONTINUE;
    }

    UList& array = *msg.value->list;

    if (array.size() < 2)
    {
      msg.client.printf("Component Error: Invalid number "
			"of arguments in the server message: %lu\n",
			static_cast<unsigned long>(array.size()));
      return URBI_CONTINUE;
    }

    if (array[0].type != DATA_DOUBLE)
    {
      msg.client.printf("Component Error: "
			"invalid server message type %d\n",
			array[0].type);
      return URBI_CONTINUE;
    }

    switch ((USystemExternalMessage)(int)array[0])
    {
      case UEM_ASSIGNVALUE:
      {
        if (array.size() != 3)
        {
          msg.client.printf("Component Error: Invalid number "
                            "of arguments in the server message: %lu"
                            " (expected 3)\n",
                            static_cast<unsigned long>(array.size()));
          return URBI_CONTINUE;
        }
        UVarTable::iterator varmapfind = varmap().find(array[1]);
        if (varmapfind != varmap().end())
          for (std::list<UVar*>::iterator it = varmapfind->second.begin();
               it != varmapfind->second.end();
               ++it)
            (*it)->__update(array[2]);

        if (callbacks_type* cs = monitormap().find0(array[1]))
          for (callbacks_type::iterator i = cs->begin();
               i != cs->end(); ++i)
          {
            // test of return value here
            UList u;
            u.array.push_back(new UValue());
            u[0].storage = (*i)->storage;
            (*i)->__evalcall(u);
          }
      }
      break;

      case UEM_EVALFUNCTION:
      {
	callbacks_type tmpfun = functionmap()[array[1]];
        const std::string var = array[2];
	callbacks_type::iterator tmpfunit = tmpfun.begin();
	array.setOffset(3);
	UValue retval = (*tmpfunit)->__evalcall(array);
	array.setOffset(0);
	switch (retval.type)
        {
        case DATA_BINARY:
	  // Send it
	  if (UClient* client = urbi::getDefaultClient())
          {
            // URBI_SEND_COMMAND does not now how to send binary since it
            // depends on the kernel version.
            client->startPack();
            *client << " var  " << var << "=";
            client->send(retval);
            *client << ";";
            client->endPack();
          }
	  else
            // Send void if no client. Would block anyway.
	    goto case_void;
          break;

        case DATA_VOID:
        case_void:
          URBI_SEND_COMMAND("var " << var);
          break;

        default:
          URBI_SEND_COMMAND("var " << var << "=" << retval);
          break;
        }
      }
      break;

      case UEM_EMITEVENT:
        if (callbacks_type* cs = eventmap().find0(array[1]))
          for (callbacks_type::iterator i = cs->begin();
               i != cs->end();
               ++i)
          {
            array.setOffset(2);
            (*i)->__evalcall(array);
            array.setOffset(0);
          }
      break;

      case UEM_ENDEVENT:
        if (callbacks_type* cs = eventendmap().find0(array[1]))
          for (callbacks_type::iterator i = cs->begin();
               i != cs->end();
               ++i)
          {
            array.setOffset(2);
            (*i)->__evalcall(array);
            array.setOffset(0);
          }
      break;

      case UEM_NEW:
        if (baseURBIStarter* o = find_object(msg.client,
                                             (std::string)array[2]))
          o->copy((std::string) array[1]);
      break;

      case UEM_DELETE:
        if (baseURBIStarter* o = find_object(msg.client,
                                             (std::string)array[1]))
        {
          // remove the object from objectlist or terminate
          // the component if there is nothing left
          if (baseURBIStarter::list().size() == 1)
            exit(0);
          else
            // delete the object
            delete o;
        }
        break;

      default:
        msg.client.printf("Component Error: "
                          "unknown server message type number %d\n",
                          (int)array[0]);
        return URBI_CONTINUE;
    }
    // Send a terminating ';' since code send by the UObject API uses '|'.
    URBI_SEND_COMMAND("");
    return URBI_CONTINUE;
  }

  UCallbackAction
  debug(const UMessage& msg)
  {
    std::stringstream mesg;
    mesg << msg;
    msg.client.printf("DEBUG: got a message: %s\n",  mesg.str().c_str());
    return URBI_CONTINUE;
  }

  UCallbackAction
  static endProgram(const UMessage& msg)
  {
    std::stringstream mesg;
    mesg << msg;
    msg.client.printf("ERROR: got a disconnection message: %s\n",
                      mesg.str().c_str());
    exit(1);
    return URBI_CONTINUE; //stupid gcc
  }

  static
  void
  usage()
  {
    std::cout <<
      "usage:\n" << libport::program_name() << " [OPTION]...\n"
      "\n"
      "Options:\n"
      "  -b, --buffer SIZE     input buffer size"
		 << " [" << UAbstractClient::URBI_BUFLEN << "]\n"
      "  -h, --help            display this message and exit\n"
      "  -H, --host ADDR       server host name   [localhost]\n"
      "      --server          put remote in server mode\n"
      "  -p, --port PORT       tcp port URBI will listen to"
		 << " [" << UAbstractClient::URBI_PORT << "]\n"
      "  -r, --port-file FILE  file containing the port to listen to\n"
      "  -v, --version         print version information and exit\n"
      "  -d, --disconnect      exit program if disconnected(defaults)\n"
      "  -s, --stay-alive      do not exit program if disconnected\n"
		 << libport::exit (EX_OK);
  }

  static
  void
  version()
  {
    std::cout << urbi::package_info() << std::endl
              << libport::exit (EX_OK);
  }

  int
  initialize(const std::string& host, int port, size_t buflen,
	     bool exitOnDisconnect, bool server)
  {
    std::cerr << program_name()
	      << ": " << urbi::package_info() << std::endl
	      << program_name()
	      << ": Remote Component Running on "
	      << host << " " << port << std::endl;

    new USyncClient(host, port, buflen, server);

    if (exitOnDisconnect)
    {
      if (!getDefaultClient() || getDefaultClient()->error())
	std::cerr << "ERROR: failed to connect, exiting..." << std::endl
		  << libport::exit(1);
      getDefaultClient()->setClientErrorCallback(callback(&endProgram));
    }
   if (!getDefaultClient() || getDefaultClient()->error())
      return 1;

#ifdef LIBURBIDEBUG
    getDefaultClient()->setWildcardCallback(callback(&debug));
#else
    getDefaultClient()->setErrorCallback(callback(&debug));
#endif

    getDefaultClient()->setCallback(&dispatcher,
				    externalModuleTag.c_str());

    // Wait for client to be connected if in server mode.
    while (getDefaultClient()
           && !getDefaultClient()->error()
           && !getDefaultClient()->init())
      usleep(20000);

    // Waiting for connectionID.
    while (getDefaultClient()
           && getDefaultClient()->connectionID() == "")
      usleep(5000);

    dummyUObject = new UObject(0);
    baseURBIStarter::init();
    // Send a ';' since UObject likely sent a serie of piped commands.
    URBI_SEND_COMMAND("");
    return 0;
  }

  namespace
  {
    static
    void
    argument_with_option(const char* longopt,
                         char shortopt,
                         const std::string& val)
    {
      std::cerr
        << program_name()
        << ": warning: arguments without options are deprecated"
        << std::endl
        << "use `-" << shortopt << ' ' << val << '\''
        << " or `--" << longopt << ' ' << val << "' instead"
        << std::endl
        << "Try `" << program_name() << " --help' for more information."
        << std::endl;
    }

  }

  int
  main(const libport::cli_args_type& args, bool block, bool)
  {
    std::string host = "localhost";
    bool exitOnDisconnect = true;
    int port = UAbstractClient::URBI_PORT;
    bool server = false;
    size_t buflen = UAbstractClient::URBI_BUFLEN;

    // The number of the next (non-option) argument.
    unsigned argp = 1;
    for (unsigned i = 1; i < args.size(); ++i)
    {
      const std::string& arg = args[i];
      if (arg == "--buffer" || arg == "-b")
	buflen = libport::convert_argument<size_t>(args, i++);
      else if (arg == "--disconnect" || arg == "-d")
	exitOnDisconnect = true;
      else if (arg == "--stay-alive" || arg == "-s")
	exitOnDisconnect = false;
      else if (arg == "--help" || arg == "-h")
	usage();
      else if (arg == "--host" || arg == "-H")
	host = libport::convert_argument<std::string>(args, i++);
      else if (arg == "--port" || arg == "-p")
	port = libport::convert_argument<unsigned>(args, i++);
      else if (arg == "--port-file" || arg == "-r")
	port =
          (libport::file_contents_get<int>
           (libport::convert_argument<const char*>(args, i++)));
      else if (arg == "--server")
	server = true;
      else if (arg == "--version" || arg == "-v")
	version();
      else if (arg[0] == '-')
	libport::invalid_option(arg);
      else
	// A genuine argument.
	switch (argp++)
	{
	  case 1:
            argument_with_option("host", 'H', args[i]);
	    host = args[i];
	    break;
	  case 2:
            argument_with_option("port", 'p', args[i]);
	    port = libport::convert_argument<unsigned> ("port", args[i].c_str());
	    break;
	  default:
	    std::cerr << "unexpected argument: " << arg << std::endl
		      << libport::exit(EX_USAGE);
	}
    }

   initialize(host, port, buflen, exitOnDisconnect, server);

   if (block)
     while (true)
       usleep(30000000);
    return 0;
  }

}
<commit_msg>libuobject: factoring.<commit_after>/// \file libuobject/main.cc

#include <libport/cstdio>
#include <libport/unistd.h>
#include <cerrno>

#include <iostream>
#include <list>
#include <sstream>

#include <libport/cli.hh>
#include <libport/containers.hh>
#include <libport/foreach.hh>
#include <libport/package-info.hh>
#include <libport/program-name.hh>
#include <libport/sysexits.hh>

#include <urbi/package-info.hh>
#include <urbi/uexternal.hh>
#include <urbi/umain.hh>
#include <urbi/uobject.hh>
#include <urbi/usyncclient.hh>

using libport::program_name;

namespace urbi
{

  namespace
  {

    /// Find in baseURBIStarter::list an object named \a named.
    /// Report errors to \a client.
    /// \return a pointer to the object found, 0 otherwise.
    static
    baseURBIStarter*
    find_object(UAbstractClient& client,
                const std::string& name)
    {
      typedef baseURBIStarter::list_type::iterator iterator;
      iterator i_end = baseURBIStarter::list().end();
      iterator found = i_end;
      for (iterator i = baseURBIStarter::list().begin(); i != i_end; ++i)
        if ((*i)->name == name)
        {
          if (found != i_end)
            client.printf("Double object definition %s\n", name.c_str());
          else
            found = i;
        }

      if (found == i_end)
      {
        client.printf("Unknown object definition %s\n", name.c_str());
        return 0;
      }
      else
        return *found;
    }

    /// Look for the function args[1] in \a t, and make a call to the
    /// associated callback with arguments (args[2], args[3], etc.).
    static
    void
    eval_call(UTable& t, UList& args)
    {
      if (UTable::callbacks_type* cs = t.find0(args[1]))
      {
        args.setOffset(2);
        foreach (UGenericCallback* c, *cs)
          c->__evalcall(args);
        args.setOffset(0);
      }
    }

  }

  UCallbackAction
  dispatcher(const UMessage& msg)
  {
    typedef UTable::callbacks_type callbacks_type;
    //check message type
    if (msg.type != MESSAGE_DATA || msg.value->type != DATA_LIST)
    {
      msg.client.printf("Component Error: "
			"unknown message content, type %d\n",
			msg.type);
      return URBI_CONTINUE;
    }

    UList& array = *msg.value->list;

    if (array.size() < 2)
    {
      msg.client.printf("Component Error: Invalid number "
			"of arguments in the server message: %lu\n",
			static_cast<unsigned long>(array.size()));
      return URBI_CONTINUE;
    }

    if (array[0].type != DATA_DOUBLE)
    {
      msg.client.printf("Component Error: "
			"invalid server message type %d\n",
			array[0].type);
      return URBI_CONTINUE;
    }

    switch ((USystemExternalMessage)(int)array[0])
    {
      case UEM_ASSIGNVALUE:
      {
        if (array.size() != 3)
        {
          msg.client.printf("Component Error: Invalid number "
                            "of arguments in the server message: %lu"
                            " (expected 3)\n",
                            static_cast<unsigned long>(array.size()));
          return URBI_CONTINUE;
        }
        UVarTable::iterator varmapfind = varmap().find(array[1]);
        if (varmapfind != varmap().end())
          for (std::list<UVar*>::iterator it = varmapfind->second.begin();
               it != varmapfind->second.end();
               ++it)
            (*it)->__update(array[2]);

        if (callbacks_type* cs = monitormap().find0(array[1]))
          for (callbacks_type::iterator i = cs->begin();
               i != cs->end(); ++i)
          {
            // test of return value here
            UList u;
            u.array.push_back(new UValue());
            u[0].storage = (*i)->storage;
            (*i)->__evalcall(u);
          }
      }
      break;

      case UEM_EVALFUNCTION:
      {
	callbacks_type tmpfun = functionmap()[array[1]];
        const std::string var = array[2];
	callbacks_type::iterator tmpfunit = tmpfun.begin();
	array.setOffset(3);
	UValue retval = (*tmpfunit)->__evalcall(array);
	array.setOffset(0);
	switch (retval.type)
        {
        case DATA_BINARY:
	  // Send it
	  if (UClient* client = urbi::getDefaultClient())
          {
            // URBI_SEND_COMMAND does not now how to send binary since it
            // depends on the kernel version.
            client->startPack();
            *client << " var  " << var << "=";
            client->send(retval);
            *client << ";";
            client->endPack();
          }
	  else
            // Send void if no client. Would block anyway.
	    goto case_void;
          break;

        case DATA_VOID:
        case_void:
          URBI_SEND_COMMAND("var " << var);
          break;

        default:
          URBI_SEND_COMMAND("var " << var << "=" << retval);
          break;
        }
      }
      break;

      case UEM_EMITEVENT:
        eval_call(eventmap(), array);
      break;

      case UEM_ENDEVENT:
        eval_call(eventendmap(), array);
      break;

      case UEM_NEW:
        if (baseURBIStarter* o = find_object(msg.client,
                                             (std::string)array[2]))
          o->copy((std::string) array[1]);
      break;

      case UEM_DELETE:
        if (baseURBIStarter* o = find_object(msg.client,
                                             (std::string)array[1]))
        {
          // remove the object from objectlist or terminate
          // the component if there is nothing left
          if (baseURBIStarter::list().size() == 1)
            exit(0);
          else
            // delete the object
            delete o;
        }
        break;

      default:
        msg.client.printf("Component Error: "
                          "unknown server message type number %d\n",
                          (int)array[0]);
        return URBI_CONTINUE;
    }
    // Send a terminating ';' since code send by the UObject API uses '|'.
    URBI_SEND_COMMAND("");
    return URBI_CONTINUE;
  }

  UCallbackAction
  debug(const UMessage& msg)
  {
    std::stringstream mesg;
    mesg << msg;
    msg.client.printf("DEBUG: got a message: %s\n",  mesg.str().c_str());
    return URBI_CONTINUE;
  }

  UCallbackAction
  static endProgram(const UMessage& msg)
  {
    std::stringstream mesg;
    mesg << msg;
    msg.client.printf("ERROR: got a disconnection message: %s\n",
                      mesg.str().c_str());
    exit(1);
    return URBI_CONTINUE; //stupid gcc
  }

  static
  void
  usage()
  {
    std::cout <<
      "usage:\n" << libport::program_name() << " [OPTION]...\n"
      "\n"
      "Options:\n"
      "  -b, --buffer SIZE     input buffer size"
		 << " [" << UAbstractClient::URBI_BUFLEN << "]\n"
      "  -h, --help            display this message and exit\n"
      "  -H, --host ADDR       server host name   [localhost]\n"
      "      --server          put remote in server mode\n"
      "  -p, --port PORT       tcp port URBI will listen to"
		 << " [" << UAbstractClient::URBI_PORT << "]\n"
      "  -r, --port-file FILE  file containing the port to listen to\n"
      "  -v, --version         print version information and exit\n"
      "  -d, --disconnect      exit program if disconnected(defaults)\n"
      "  -s, --stay-alive      do not exit program if disconnected\n"
		 << libport::exit (EX_OK);
  }

  static
  void
  version()
  {
    std::cout << urbi::package_info() << std::endl
              << libport::exit (EX_OK);
  }

  int
  initialize(const std::string& host, int port, size_t buflen,
	     bool exitOnDisconnect, bool server)
  {
    std::cerr << program_name()
	      << ": " << urbi::package_info() << std::endl
	      << program_name()
	      << ": Remote Component Running on "
	      << host << " " << port << std::endl;

    new USyncClient(host, port, buflen, server);

    if (exitOnDisconnect)
    {
      if (!getDefaultClient() || getDefaultClient()->error())
	std::cerr << "ERROR: failed to connect, exiting..." << std::endl
		  << libport::exit(1);
      getDefaultClient()->setClientErrorCallback(callback(&endProgram));
    }
   if (!getDefaultClient() || getDefaultClient()->error())
      return 1;

#ifdef LIBURBIDEBUG
    getDefaultClient()->setWildcardCallback(callback(&debug));
#else
    getDefaultClient()->setErrorCallback(callback(&debug));
#endif

    getDefaultClient()->setCallback(&dispatcher,
				    externalModuleTag.c_str());

    // Wait for client to be connected if in server mode.
    while (getDefaultClient()
           && !getDefaultClient()->error()
           && !getDefaultClient()->init())
      usleep(20000);

    // Waiting for connectionID.
    while (getDefaultClient()
           && getDefaultClient()->connectionID() == "")
      usleep(5000);

    dummyUObject = new UObject(0);
    baseURBIStarter::init();
    // Send a ';' since UObject likely sent a serie of piped commands.
    URBI_SEND_COMMAND("");
    return 0;
  }

  namespace
  {
    static
    void
    argument_with_option(const char* longopt,
                         char shortopt,
                         const std::string& val)
    {
      std::cerr
        << program_name()
        << ": warning: arguments without options are deprecated"
        << std::endl
        << "use `-" << shortopt << ' ' << val << '\''
        << " or `--" << longopt << ' ' << val << "' instead"
        << std::endl
        << "Try `" << program_name() << " --help' for more information."
        << std::endl;
    }

  }

  int
  main(const libport::cli_args_type& args, bool block, bool)
  {
    std::string host = "localhost";
    bool exitOnDisconnect = true;
    int port = UAbstractClient::URBI_PORT;
    bool server = false;
    size_t buflen = UAbstractClient::URBI_BUFLEN;

    // The number of the next (non-option) argument.
    unsigned argp = 1;
    for (unsigned i = 1; i < args.size(); ++i)
    {
      const std::string& arg = args[i];
      if (arg == "--buffer" || arg == "-b")
	buflen = libport::convert_argument<size_t>(args, i++);
      else if (arg == "--disconnect" || arg == "-d")
	exitOnDisconnect = true;
      else if (arg == "--stay-alive" || arg == "-s")
	exitOnDisconnect = false;
      else if (arg == "--help" || arg == "-h")
	usage();
      else if (arg == "--host" || arg == "-H")
	host = libport::convert_argument<std::string>(args, i++);
      else if (arg == "--port" || arg == "-p")
	port = libport::convert_argument<unsigned>(args, i++);
      else if (arg == "--port-file" || arg == "-r")
	port =
          (libport::file_contents_get<int>
           (libport::convert_argument<const char*>(args, i++)));
      else if (arg == "--server")
	server = true;
      else if (arg == "--version" || arg == "-v")
	version();
      else if (arg[0] == '-')
	libport::invalid_option(arg);
      else
	// A genuine argument.
	switch (argp++)
	{
	  case 1:
            argument_with_option("host", 'H', args[i]);
	    host = args[i];
	    break;
	  case 2:
            argument_with_option("port", 'p', args[i]);
	    port = libport::convert_argument<unsigned> ("port", args[i].c_str());
	    break;
	  default:
	    std::cerr << "unexpected argument: " << arg << std::endl
		      << libport::exit(EX_USAGE);
	}
    }

   initialize(host, port, buflen, exitOnDisconnect, server);

   if (block)
     while (true)
       usleep(30000000);
    return 0;
  }

}
<|endoftext|>