<commit_before>#include "process.hpp"
#include <cstdlib>
#include <unistd.h>
#include <signal.h>
#include <stdexcept>

Process::Data::Data(): id(-1) {}

Process::id_type Process::open(const std::string &command, const std::string &path) {
  if(open_stdin)
    stdin_fd=std::unique_ptr<fd_type>(new fd_type);
  if(read_stdout)
    stdout_fd=std::unique_ptr<fd_type>(new fd_type);
  if(read_stderr)
    stderr_fd=std::unique_ptr<fd_type>(new fd_type);

  int stdin_p[2], stdout_p[2], stderr_p[2];

  if(stdin_fd && pipe(stdin_p)!=0) {
    close(stdin_p[0]);close(stdin_p[1]);
    return -1;
  }
  if(stdout_fd && pipe(stdout_p)!=0) {
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    close(stdout_p[0]);close(stdout_p[1]);
    return -1;
  }
  if(stderr_fd && pipe(stderr_p)!=0) {
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    if(stdout_fd) {close(stdout_p[0]);close(stdout_p[1]);}
    close(stderr_p[0]);close(stderr_p[1]);
    return -1;
  }

  id_type pid = fork();

  if (pid < 0) {
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    if(stdout_fd) {close(stdout_p[0]);close(stdout_p[1]);}
    if(stderr_fd) {close(stderr_p[0]);close(stderr_p[1]);}
    return pid;
  }
  else if (pid == 0) {
    if(stdin_fd) dup2(stdin_p[0], 0);
    if(stdout_fd) dup2(stdout_p[1], 1);
    if(stderr_fd) dup2(stderr_p[1], 2);
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    if(stdout_fd) {close(stdout_p[0]);close(stdout_p[1]);}
    if(stderr_fd) {close(stderr_p[0]);close(stderr_p[1]);}

    //Based on http://stackoverflow.com/a/899533/3808293
    int fd_max=sysconf(_SC_OPEN_MAX);
    for(int fd=3;fd<fd_max;fd++)
      close(fd);

    setpgid(0, 0);
    //TODO: See here on how to emulate tty for colors: http://stackoverflow.com/questions/1401002/trick-an-application-into-thinking-its-stdin-is-interactive-not-a-pipe
    //TODO: One solution is: echo "command;exit"|script -q /dev/null

    if(!path.empty()) {
      auto path_escaped=path;
      size_t pos=0;
      //Based on https://www.reddit.com/r/cpp/comments/3vpjqg/a_new_platform_independent_process_library_for_c11/cxsxyb7
      while((pos=path_escaped.find('\"', pos))!=std::string::npos) {
        path_escaped.insert(pos, "\\");
        pos+=2;
      }
      execl("/bin/sh", "sh", "-c", ("cd \""+path_escaped+"\" && "+command).c_str(), NULL);
    }
    else
      execl("/bin/sh", "sh", "-c", command.c_str(), NULL);

    _exit(EXIT_FAILURE);
  }

  if(stdin_fd) close(stdin_p[0]);
  if(stdout_fd) close(stdout_p[1]);
  if(stderr_fd) close(stderr_p[1]);

  if(stdin_fd) *stdin_fd = stdin_p[1];
  if(stdout_fd) *stdout_fd = stdout_p[0];
  if(stderr_fd) *stderr_fd = stderr_p[0];

  closed=false;
  data.id=pid;
  return pid;
}

void Process::async_read() {
  if(data.id<=0)
    return;
  if(stdout_fd) {
    stdout_thread=std::thread([this](){
      char buffer[buffer_size];
      ssize_t n;
      while ((n=read(*stdout_fd, buffer, buffer_size)) > 0)
        read_stdout(buffer, static_cast<size_t>(n));
    });
  }
  if(stderr_fd) {
    stderr_thread=std::thread([this](){
      char buffer[buffer_size];
      ssize_t n;
      while ((n=read(*stderr_fd, buffer, buffer_size)) > 0)
        read_stderr(buffer, static_cast<size_t>(n));
    });
  }
}

int Process::get_exit_status() {
  if(data.id<=0)
    return -1;
  int exit_status;
  waitpid(data.id, &exit_status, 0);
  close_mutex.lock();
  closed=true;
  close_mutex.unlock();

  close_fds();

  return exit_status;
}

void Process::close_fds() {
  if(stdout_thread.joinable())
    stdout_thread.join();
  if(stderr_thread.joinable())
    stderr_thread.join();

  if(stdin_fd)
    close_stdin();
  if(stdout_fd) {
    close(*stdout_fd);
    stdout_fd.reset();
  }
  if(stderr_fd) {
    close(*stderr_fd);
    stderr_fd.reset();
  }
}

bool Process::write(const char *bytes, size_t n) {
  if(!open_stdin)
    throw std::invalid_argument("Can't write to an unopened stdin pipe. Please set open_stdin=true when constructing the process.");
  stdin_mutex.lock();
  if(stdin_fd) {
    if(::write(*stdin_fd, bytes, n)>=0) {
      stdin_mutex.unlock();
      return true;
    }
    else {
      stdin_mutex.unlock();
      return false;
    }
  }
  stdin_mutex.unlock();
  return false;
}

void Process::close_stdin() {
  stdin_mutex.lock();
  if(stdin_fd) {
    close(*stdin_fd);
    stdin_fd.reset();
  }
  stdin_mutex.unlock();
}

void Process::kill(bool force) {
  close_mutex.lock();
  if(data.id>0 && !closed) {
    if(force)
      ::kill(-data.id, SIGTERM);
    else
      ::kill(-data.id, SIGINT);
  }
  close_mutex.unlock();
}

void Process::kill(id_type id, bool force) {
  if(id<=0)
    return;
  if(force)
    ::kill(-id, SIGTERM);
  else
    ::kill(-id, SIGINT);
}
<commit_msg>Corrected path escaping<commit_after>#include "process.hpp"
#include <cstdlib>
#include <unistd.h>
#include <signal.h>
#include <stdexcept>

Process::Data::Data(): id(-1) {}

Process::id_type Process::open(const std::string &command, const std::string &path) {
  if(open_stdin)
    stdin_fd=std::unique_ptr<fd_type>(new fd_type);
  if(read_stdout)
    stdout_fd=std::unique_ptr<fd_type>(new fd_type);
  if(read_stderr)
    stderr_fd=std::unique_ptr<fd_type>(new fd_type);

  int stdin_p[2], stdout_p[2], stderr_p[2];

  if(stdin_fd && pipe(stdin_p)!=0) {
    close(stdin_p[0]);close(stdin_p[1]);
    return -1;
  }
  if(stdout_fd && pipe(stdout_p)!=0) {
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    close(stdout_p[0]);close(stdout_p[1]);
    return -1;
  }
  if(stderr_fd && pipe(stderr_p)!=0) {
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    if(stdout_fd) {close(stdout_p[0]);close(stdout_p[1]);}
    close(stderr_p[0]);close(stderr_p[1]);
    return -1;
  }

  id_type pid = fork();

  if (pid < 0) {
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    if(stdout_fd) {close(stdout_p[0]);close(stdout_p[1]);}
    if(stderr_fd) {close(stderr_p[0]);close(stderr_p[1]);}
    return pid;
  }
  else if (pid == 0) {
    if(stdin_fd) dup2(stdin_p[0], 0);
    if(stdout_fd) dup2(stdout_p[1], 1);
    if(stderr_fd) dup2(stderr_p[1], 2);
    if(stdin_fd) {close(stdin_p[0]);close(stdin_p[1]);}
    if(stdout_fd) {close(stdout_p[0]);close(stdout_p[1]);}
    if(stderr_fd) {close(stderr_p[0]);close(stderr_p[1]);}

    //Based on http://stackoverflow.com/a/899533/3808293
    int fd_max=sysconf(_SC_OPEN_MAX);
    for(int fd=3;fd<fd_max;fd++)
      close(fd);

    setpgid(0, 0);
    //TODO: See here on how to emulate tty for colors: http://stackoverflow.com/questions/1401002/trick-an-application-into-thinking-its-stdin-is-interactive-not-a-pipe
    //TODO: One solution is: echo "command;exit"|script -q /dev/null

    if(!path.empty()) {
      auto path_escaped=path;
      size_t pos=0;
      //Based on https://www.reddit.com/r/cpp/comments/3vpjqg/a_new_platform_independent_process_library_for_c11/cxsxyb7
      while((pos=path_escaped.find('\'', pos))!=std::string::npos) {
        path_escaped.replace(pos, 1, "'\\''");
        pos+=4;
      }
      execl("/bin/sh", "sh", "-c", ("cd \'"+path_escaped+"\' && "+command).c_str(), NULL);
    }
    else
      execl("/bin/sh", "sh", "-c", command.c_str(), NULL);

    _exit(EXIT_FAILURE);
  }

  if(stdin_fd) close(stdin_p[0]);
  if(stdout_fd) close(stdout_p[1]);
  if(stderr_fd) close(stderr_p[1]);

  if(stdin_fd) *stdin_fd = stdin_p[1];
  if(stdout_fd) *stdout_fd = stdout_p[0];
  if(stderr_fd) *stderr_fd = stderr_p[0];

  closed=false;
  data.id=pid;
  return pid;
}

void Process::async_read() {
  if(data.id<=0)
    return;
  if(stdout_fd) {
    stdout_thread=std::thread([this](){
      char buffer[buffer_size];
      ssize_t n;
      while ((n=read(*stdout_fd, buffer, buffer_size)) > 0)
        read_stdout(buffer, static_cast<size_t>(n));
    });
  }
  if(stderr_fd) {
    stderr_thread=std::thread([this](){
      char buffer[buffer_size];
      ssize_t n;
      while ((n=read(*stderr_fd, buffer, buffer_size)) > 0)
        read_stderr(buffer, static_cast<size_t>(n));
    });
  }
}

int Process::get_exit_status() {
  if(data.id<=0)
    return -1;
  int exit_status;
  waitpid(data.id, &exit_status, 0);
  close_mutex.lock();
  closed=true;
  close_mutex.unlock();

  close_fds();

  return exit_status;
}

void Process::close_fds() {
  if(stdout_thread.joinable())
    stdout_thread.join();
  if(stderr_thread.joinable())
    stderr_thread.join();

  if(stdin_fd)
    close_stdin();
  if(stdout_fd) {
    close(*stdout_fd);
    stdout_fd.reset();
  }
  if(stderr_fd) {
    close(*stderr_fd);
    stderr_fd.reset();
  }
}

bool Process::write(const char *bytes, size_t n) {
  if(!open_stdin)
    throw std::invalid_argument("Can't write to an unopened stdin pipe. Please set open_stdin=true when constructing the process.");
  stdin_mutex.lock();
  if(stdin_fd) {
    if(::write(*stdin_fd, bytes, n)>=0) {
      stdin_mutex.unlock();
      return true;
    }
    else {
      stdin_mutex.unlock();
      return false;
    }
  }
  stdin_mutex.unlock();
  return false;
}

void Process::close_stdin() {
  stdin_mutex.lock();
  if(stdin_fd) {
    close(*stdin_fd);
    stdin_fd.reset();
  }
  stdin_mutex.unlock();
}

void Process::kill(bool force) {
  close_mutex.lock();
  if(data.id>0 && !closed) {
    if(force)
      ::kill(-data.id, SIGTERM);
    else
      ::kill(-data.id, SIGINT);
  }
  close_mutex.unlock();
}

void Process::kill(id_type id, bool force) {
  if(id<=0)
    return;
  if(force)
    ::kill(-id, SIGTERM);
  else
    ::kill(-id, SIGINT);
}
<|endoftext|>


<commit_before>// Main.cpp

#include "StdAfx.h"

#if defined( _7ZIP_LARGE_PAGES)
#include "../../../../C/Alloc.h"
#endif

#include "Common/MyInitGuid.h"
#include "Windows/ErrorMsg.h"
#include "Windows/PropVariantConv.h"
#include "7zip/UI/Common/ArchiveCommandLine.h"

#include "lib7z.h"
#include "MLListCallbackWrapper.h"
#include "MLExtractCallbackWrapper.h"
#include "MLUpdateCallbackWrapper.h"

#include <vector>
#include <string>
#include <sstream>

namespace lib7z
{

static void GetAttribString(DWORD wa, bool isDir, char *s)
{
    if (isDir) wa |= FILE_ATTRIBUTE_DIRECTORY;
    s[0] = ((wa & FILE_ATTRIBUTE_DIRECTORY) != 0) ? 'D': '.';
    s[1] = ((wa & FILE_ATTRIBUTE_READONLY)  != 0) ? 'R': '.';
    s[2] = ((wa & FILE_ATTRIBUTE_HIDDEN)    != 0) ? 'H': '.';
    s[3] = ((wa & FILE_ATTRIBUTE_SYSTEM)    != 0) ? 'S': '.';
    s[4] = ((wa & FILE_ATTRIBUTE_ARCHIVE)   != 0) ? 'A': '.';
    s[5] = 0;
}

LIB7ZRC MLListArchive(std::wstring archiveNameW, std::vector<DirectoryItem> &retValue, MLListCallback &callback)
{
    UString archiveName = archiveNameW.c_str();
    NWindows::NFile::NFind::CFileInfo fi;
    if (!fi.Find(archiveName) || fi.IsDir())
    {
      return Lib7zReturnCode::CANTFINDARCHIVE;
    }

    HRESULT result;

    CCodecs codecs;
    if (codecs.Load() != S_OK)
    {
        return Lib7zReturnCode::CANTLOADCODECS;
    }

    CIntVector formatIndices;
    CObjectVector<COpenType> types;
    MLListCallbackWrapper openCallback(callback);
    COpenOptions openOptions;
    CObjectVector<CProperty> props;

    openOptions.codecs = &codecs;
    openOptions.filePath = archiveName;
    openOptions.excludedFormats = &formatIndices;
    openOptions.types = &types;
    openOptions.props = &props;

    CArchiveLink archiveLink;
    RINOK(archiveLink.Open2(openOptions, &openCallback));

    const CArc &arc = archiveLink.Arcs.Back();
    IInArchive *archive = arc.Archive;
    UInt32 numItems;
    RINOK(archive->GetNumberOfItems(&numItems));
    for (UInt32 i = 0; i < numItems; i++)
    {
        UString sPath;
        RINOK(arc.GetItemPath(i, sPath));

        bool isFolder = false;
        NWindows::NCOM::CPropVariant propIsFolder;
        RINOK(arc.Archive->GetProperty(i, kpidIsDir, &propIsFolder));
        if (propIsFolder.vt == VT_BOOL)
        {
            isFolder = VARIANT_BOOLToBool(propIsFolder.boolVal);
        }

        NWindows::NCOM::CPropVariant propSize;
        RINOK(arc.Archive->GetProperty(i, kpidSize, &propSize));
        UInt64 size = -1;
        if (propSize.vt != VT_EMPTY) ConvertPropVariantToUInt64(propSize, size);

        NWindows::NCOM::CPropVariant propSizePacked;
        RINOK(arc.Archive->GetProperty(i, kpidPackSize, &propSizePacked));
        UInt64 sizePacked = -1;
        if (propSizePacked.vt != VT_EMPTY) ConvertPropVariantToUInt64(propSizePacked, sizePacked);

        UInt32 iAttrs;
        NWindows::NCOM::CPropVariant propAttrs;
        RINOK(arc.Archive->GetProperty(i, kpidAttrib, &propAttrs));
        iAttrs = (propAttrs.vt == VT_EMPTY ? 0 : propAttrs.ulVal);
        char s[8];
        GetAttribString(iAttrs, isFolder, s);

        NWindows::NCOM::CPropVariant propTime;
        RINOK(arc.Archive->GetProperty(i, kpidMTime, &propTime));
        char ftime[32];
        if ((propTime.filetime.dwLowDateTime == 0) && (propTime.filetime.dwHighDateTime == 0)) {
            ftime[0] = 0;
        }
        else
        {
            FILETIME localFileTime;
            FileTimeToLocalFileTime(&propTime.filetime, &localFileTime);
            if (!ConvertFileTimeToString(localFileTime, ftime, true, true)) ftime[0] = 0;
            //format is: YYYY-MM-DD hh:mm:ss
        }

        NWindows::NCOM::CPropVariant propEncrypted;
        RINOK(arc.Archive->GetProperty(i, kpidEncrypted, &propEncrypted));
        bool encrypted = false;
        if (propEncrypted.boolVal) {
            encrypted = true;
        }

        DirectoryItem di(std::wstring(sPath), size, sizePacked, std::string(ftime), std::string(s), encrypted);
        retValue.push_back(di);
    }

    return 0;
}

LIB7ZRC MLExtractFromArchive(std::wstring archiveNameW, std::wstring outDirW, std::vector<std::wstring> files,
                        MLExtractCallback &callback, std::wstring workDir)
{
    UString archiveName = archiveNameW.c_str();
    UString outDir = outDirW.c_str();

    NWindows::NFile::NFind::CFileInfo fi;
    if (!fi.Find(archiveName) || fi.IsDir())
    {
        return Lib7zReturnCode::CANTFINDARCHIVE;
    }

    HRESULT result;

    CCodecs codecs;
    if (codecs.Load() != S_OK)
    {
        return Lib7zReturnCode::CANTLOADCODECS;
    }

    CIntVector formatIndices;
    CObjectVector<COpenType> types;
    CObjectVector<CProperty> props;
    MLListCallbackWrapper openCallback(callback);
    COpenOptions openOptions;
    openOptions.codecs = &codecs;
    openOptions.filePath = archiveName;
    openOptions.types = &types;
    openOptions.excludedFormats = &formatIndices;
    openOptions.props = &props;

    CArchiveLink archiveLink;
    RINOK(archiveLink.Open2(openOptions, &openCallback));
    const CArc &arc = archiveLink.Arcs.Back();
    IInArchive *archive = arc.Archive;

    CRecordVector<UInt32> realIndices;
    UInt32 numItems;
    RINOK(archive->GetNumberOfItems(&numItems));

    std::vector<std::wstring> files2;
    for (std::vector<std::wstring>::iterator it = files.begin(); it < files.end(); it++)
    {
        files2.push_back(*it + L"/");
    }

    for (UInt32 i = 0; i < numItems; i++)
    {
        UString filePath;
        RINOK(arc.GetItemPath(i, filePath));
        if (files.size())
        {
            // firstly simply check if given items in on the list (files)
            if (std::find(files.begin(), files.end(), std::wstring(filePath)) == files.end()) {
                // not found

                // now check if it is substring (subdirectory) of files on the list (using files2)
                bool found = false;
                for (std::vector<std::wstring>::iterator it = files.begin(); it < files.end(); it++)
                {
                    auto res = std::mismatch(it->begin(), it->end(), std::wstring(filePath).begin());
                    if (res.first == it->end())
                        found = true;
                        break;
                }
                if (!found) continue;
            }
        }
        realIndices.Add(i);
    }
    //if (realIndices.Size() == 0)
    //{
        //return ecs->ThereAreNoFiles();
    //}

    if (!outDir.IsEmpty() && !NWindows::NFile::NDir::CreateComplexDir(outDir))
    {
        return Lib7zReturnCode::CANTCREATEOUTDIR;
    }

    UStringVector removePathParts;
    MLExtractCallbackWrapper *ecs = new MLExtractCallbackWrapper(callback);
    CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback();
    CExtractNtOptions ntOptions;
    extractCallbackSpec->Init(ntOptions,
                              NULL,
                              &arc,
                              ecs,
                              false, false,
                              outDir,
                              removePathParts, false,
                              0);
    result = archive->Extract(&realIndices.Front(), realIndices.Size(), false, extractCallbackSpec);
    callback.FinishArchive();

    return result;
}

LIB7ZRC MLGenericCommand(std::wstring command, std::wstring archiveNameW, std::vector<std::wstring> filesW, MLUpdateCallback &cb,
                     bool encryptHeader, int compressionLevel, std::wstring workDir)
{
    UString archiveName = archiveNameW.c_str();
    std::vector<UString> files;
    for (std::vector<std::wstring>::iterator it = filesW.begin(); it < filesW.end(); it++)
    {
        files.push_back(UString(it->c_str()));
    }

    CCodecs codecs;
    if (codecs.Load() != S_OK)
    {
        return Lib7zReturnCode::CANTLOADCODECS;
    }

    UStringVector commandStrings;
    commandStrings.Add(command.c_str());
    std::wstringstream wstr;
    wstr << L"-mx" << compressionLevel;
    //commandStrings.Add((L"-mx" + std::to_wstring(compressionLevel)).c_str());
    commandStrings.Add(wstr.str().c_str());
    if (encryptHeader)
    {
        commandStrings.Add(L"-mhe");
    }
    commandStrings.Add(archiveName);
    for (std::vector<UString>::iterator it = files.begin(); it < files.end(); it++)
    {
        commandStrings.Add(*it);
    }
    CArcCmdLineOptions options;
    CArcCmdLineParser parser;
    parser.Parse1(commandStrings, options);
    parser.Parse2(options);

    CObjectVector<COpenType> formatIndices;
    CUpdateOptions &uo = options.UpdateOptions;
    MLListCallbackWrapper openCallback(cb);
    MLUpdateCallbackWrapper callback(cb) ;

    if (!uo.InitFormatIndex(&codecs, formatIndices, options.ArchiveName))
    {
        return Lib7zReturnCode::UOINITFAILED;
    }

    uo.WorkingDir = workDir.c_str();
    CUpdateErrorInfo errorInfo;

    HRESULT res = UpdateArchive(&codecs,
                                formatIndices,
                                options.ArchiveName,
                                options.Censor,
								uo,
                                errorInfo,
								&openCallback,
								&callback,
								true);

    return res;
}

LIB7ZRC MLAddToArchive(std::wstring archiveNameW, std::vector<std::wstring> filesW, MLUpdateCallback &cb,
                      bool encryptHeader, int compressionLevel, std::wstring workDir)
{
    return MLGenericCommand(L"a", archiveNameW, filesW, cb, encryptHeader, compressionLevel, workDir);
}

LIB7ZRC MLDeleteFromArchive(std::wstring archiveNameW, std::vector<std::wstring> filesW, MLUpdateCallback &cb,
                        std::wstring workDir)
{
    return MLGenericCommand(L"d", archiveNameW, filesW, cb, false, 9, workDir);
}

}
<commit_msg>Fix for issue with only first dir being extracted when several dirs was selected - other only get created but without extracting their content<commit_after>// Main.cpp

#include "StdAfx.h"

#if defined( _7ZIP_LARGE_PAGES)
#include "../../../../C/Alloc.h"
#endif

#include "Common/MyInitGuid.h"
#include "Windows/ErrorMsg.h"
#include "Windows/PropVariantConv.h"
#include "7zip/UI/Common/ArchiveCommandLine.h"

#include "lib7z.h"
#include "MLListCallbackWrapper.h"
#include "MLExtractCallbackWrapper.h"
#include "MLUpdateCallbackWrapper.h"

#include <vector>
#include <string>
#include <sstream>

namespace lib7z
{

static void GetAttribString(DWORD wa, bool isDir, char *s)
{
    if (isDir) wa |= FILE_ATTRIBUTE_DIRECTORY;
    s[0] = ((wa & FILE_ATTRIBUTE_DIRECTORY) != 0) ? 'D': '.';
    s[1] = ((wa & FILE_ATTRIBUTE_READONLY)  != 0) ? 'R': '.';
    s[2] = ((wa & FILE_ATTRIBUTE_HIDDEN)    != 0) ? 'H': '.';
    s[3] = ((wa & FILE_ATTRIBUTE_SYSTEM)    != 0) ? 'S': '.';
    s[4] = ((wa & FILE_ATTRIBUTE_ARCHIVE)   != 0) ? 'A': '.';
    s[5] = 0;
}

LIB7ZRC MLListArchive(std::wstring archiveNameW, std::vector<DirectoryItem> &retValue, MLListCallback &callback)
{
    UString archiveName = archiveNameW.c_str();
    NWindows::NFile::NFind::CFileInfo fi;
    if (!fi.Find(archiveName) || fi.IsDir())
    {
      return Lib7zReturnCode::CANTFINDARCHIVE;
    }

    HRESULT result;

    CCodecs codecs;
    if (codecs.Load() != S_OK)
    {
        return Lib7zReturnCode::CANTLOADCODECS;
    }

    CIntVector formatIndices;
    CObjectVector<COpenType> types;
    MLListCallbackWrapper openCallback(callback);
    COpenOptions openOptions;
    CObjectVector<CProperty> props;

    openOptions.codecs = &codecs;
    openOptions.filePath = archiveName;
    openOptions.excludedFormats = &formatIndices;
    openOptions.types = &types;
    openOptions.props = &props;

    CArchiveLink archiveLink;
    RINOK(archiveLink.Open2(openOptions, &openCallback));

    const CArc &arc = archiveLink.Arcs.Back();
    IInArchive *archive = arc.Archive;
    UInt32 numItems;
    RINOK(archive->GetNumberOfItems(&numItems));
    for (UInt32 i = 0; i < numItems; i++)
    {
        UString sPath;
        RINOK(arc.GetItemPath(i, sPath));

        bool isFolder = false;
        NWindows::NCOM::CPropVariant propIsFolder;
        RINOK(arc.Archive->GetProperty(i, kpidIsDir, &propIsFolder));
        if (propIsFolder.vt == VT_BOOL)
        {
            isFolder = VARIANT_BOOLToBool(propIsFolder.boolVal);
        }

        NWindows::NCOM::CPropVariant propSize;
        RINOK(arc.Archive->GetProperty(i, kpidSize, &propSize));
        UInt64 size = -1;
        if (propSize.vt != VT_EMPTY) ConvertPropVariantToUInt64(propSize, size);

        NWindows::NCOM::CPropVariant propSizePacked;
        RINOK(arc.Archive->GetProperty(i, kpidPackSize, &propSizePacked));
        UInt64 sizePacked = -1;
        if (propSizePacked.vt != VT_EMPTY) ConvertPropVariantToUInt64(propSizePacked, sizePacked);

        UInt32 iAttrs;
        NWindows::NCOM::CPropVariant propAttrs;
        RINOK(arc.Archive->GetProperty(i, kpidAttrib, &propAttrs));
        iAttrs = (propAttrs.vt == VT_EMPTY ? 0 : propAttrs.ulVal);
        char s[8];
        GetAttribString(iAttrs, isFolder, s);

        NWindows::NCOM::CPropVariant propTime;
        RINOK(arc.Archive->GetProperty(i, kpidMTime, &propTime));
        char ftime[32];
        if ((propTime.filetime.dwLowDateTime == 0) && (propTime.filetime.dwHighDateTime == 0)) {
            ftime[0] = 0;
        }
        else
        {
            FILETIME localFileTime;
            FileTimeToLocalFileTime(&propTime.filetime, &localFileTime);
            if (!ConvertFileTimeToString(localFileTime, ftime, true, true)) ftime[0] = 0;
            //format is: YYYY-MM-DD hh:mm:ss
        }

        NWindows::NCOM::CPropVariant propEncrypted;
        RINOK(arc.Archive->GetProperty(i, kpidEncrypted, &propEncrypted));
        bool encrypted = false;
        if (propEncrypted.boolVal) {
            encrypted = true;
        }

        DirectoryItem di(std::wstring(sPath), size, sizePacked, std::string(ftime), std::string(s), encrypted);
        retValue.push_back(di);
    }

    return 0;
}

LIB7ZRC MLExtractFromArchive(std::wstring archiveNameW, std::wstring outDirW, std::vector<std::wstring> files,
                        MLExtractCallback &callback, std::wstring workDir)
{
    UString archiveName = archiveNameW.c_str();
    UString outDir = outDirW.c_str();

    NWindows::NFile::NFind::CFileInfo fi;
    if (!fi.Find(archiveName) || fi.IsDir())
    {
        return Lib7zReturnCode::CANTFINDARCHIVE;
    }

    HRESULT result;

    CCodecs codecs;
    if (codecs.Load() != S_OK)
    {
        return Lib7zReturnCode::CANTLOADCODECS;
    }

    CIntVector formatIndices;
    CObjectVector<COpenType> types;
    CObjectVector<CProperty> props;
    MLListCallbackWrapper openCallback(callback);
    COpenOptions openOptions;
    openOptions.codecs = &codecs;
    openOptions.filePath = archiveName;
    openOptions.types = &types;
    openOptions.excludedFormats = &formatIndices;
    openOptions.props = &props;

    CArchiveLink archiveLink;
    RINOK(archiveLink.Open2(openOptions, &openCallback));
    const CArc &arc = archiveLink.Arcs.Back();
    IInArchive *archive = arc.Archive;

    CRecordVector<UInt32> realIndices;
    UInt32 numItems;
    RINOK(archive->GetNumberOfItems(&numItems));

    std::vector<std::wstring> files2;
    for (std::vector<std::wstring>::iterator it = files.begin(); it < files.end(); it++)
    {
        files2.push_back(*it + L"/");
    }

    for (UInt32 i = 0; i < numItems; i++)
    {
        UString filePath;
        RINOK(arc.GetItemPath(i, filePath));
        if (files.size())
        {
            // firstly simply check if given items in on the list (files)
            if (std::find(files.begin(), files.end(), std::wstring(filePath)) == files.end()) {
                // not found

                // now check if it is substring (subdirectory) of files on the list (using files2)
                bool found = false;
                for (std::vector<std::wstring>::iterator it = files.begin(); it < files.end(); it++)
                {
                    auto res = std::mismatch(it->begin(), it->end(), std::wstring(filePath).begin());
                    if (res.first == it->end())
                    {
                        found = true;
                        break;
                    }
                }
                if (!found) continue;
            }
        }
        realIndices.Add(i);
    }
    //if (realIndices.Size() == 0)
    //{
        //return ecs->ThereAreNoFiles();
    //}

    if (!outDir.IsEmpty() && !NWindows::NFile::NDir::CreateComplexDir(outDir))
    {
        return Lib7zReturnCode::CANTCREATEOUTDIR;
    }

    UStringVector removePathParts;
    MLExtractCallbackWrapper *ecs = new MLExtractCallbackWrapper(callback);
    CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback();
    CExtractNtOptions ntOptions;
    extractCallbackSpec->Init(ntOptions,
                              NULL,
                              &arc,
                              ecs,
                              false, false,
                              outDir,
                              removePathParts, false,
                              0);
    result = archive->Extract(&realIndices.Front(), realIndices.Size(), false, extractCallbackSpec);
    callback.FinishArchive();
    return result;
}

LIB7ZRC MLGenericCommand(std::wstring command, std::wstring archiveNameW, std::vector<std::wstring> filesW, MLUpdateCallback &cb,
                     bool encryptHeader, int compressionLevel, std::wstring workDir)
{
    UString archiveName = archiveNameW.c_str();
    std::vector<UString> files;
    for (std::vector<std::wstring>::iterator it = filesW.begin(); it < filesW.end(); it++)
    {
        files.push_back(UString(it->c_str()));
    }

    CCodecs codecs;
    if (codecs.Load() != S_OK)
    {
        return Lib7zReturnCode::CANTLOADCODECS;
    }

    UStringVector commandStrings;
    commandStrings.Add(command.c_str());
    std::wstringstream wstr;
    wstr << L"-mx" << compressionLevel;
    //commandStrings.Add((L"-mx" + std::to_wstring(compressionLevel)).c_str());
    commandStrings.Add(wstr.str().c_str());
    if (encryptHeader)
    {
        commandStrings.Add(L"-mhe");
    }
    commandStrings.Add(archiveName);
    for (std::vector<UString>::iterator it = files.begin(); it < files.end(); it++)
    {
        commandStrings.Add(*it);
    }
    CArcCmdLineOptions options;
    CArcCmdLineParser parser;
    parser.Parse1(commandStrings, options);
    parser.Parse2(options);

    CObjectVector<COpenType> formatIndices;
    CUpdateOptions &uo = options.UpdateOptions;
    MLListCallbackWrapper openCallback(cb);
    MLUpdateCallbackWrapper callback(cb) ;

    if (!uo.InitFormatIndex(&codecs, formatIndices, options.ArchiveName))
    {
        return Lib7zReturnCode::UOINITFAILED;
    }

    uo.WorkingDir = workDir.c_str();
    CUpdateErrorInfo errorInfo;

    HRESULT res = UpdateArchive(&codecs,
                                formatIndices,
                                options.ArchiveName,
                                options.Censor,
								uo,
                                errorInfo,
								&openCallback,
								&callback,
								true);

    return res;
}

LIB7ZRC MLAddToArchive(std::wstring archiveNameW, std::vector<std::wstring> filesW, MLUpdateCallback &cb,
                      bool encryptHeader, int compressionLevel, std::wstring workDir)
{
    return MLGenericCommand(L"a", archiveNameW, filesW, cb, encryptHeader, compressionLevel, workDir);
}

LIB7ZRC MLDeleteFromArchive(std::wstring archiveNameW, std::vector<std::wstring> filesW, MLUpdateCallback &cb,
                        std::wstring workDir)
{
    return MLGenericCommand(L"d", archiveNameW, filesW, cb, false, 9, workDir);
}

}
<|endoftext|>


<commit_before>/*
helpers.cpp, Robert Oeffner 2017

*/

#include "helpers.h"

std::vector< std::vector<double> > GetColumns(sqlite3* db, std::string sqlxprs)
{
  // get column from sql expression and return it
  char *zErrMsg;
  char **result;
  int rc;
  int nrow, ncol;
  int db_open;
  rc = sqlite3_get_table(
    db,              /* An open database */
    sqlxprs.c_str(),       /* SQL to be executed */
    &result,       /* Result written to a char *[]  that this points to */
    &nrow,             /* Number of result rows written here */
    &ncol,          /* Number of result columns written here */
    &zErrMsg          /* Error msg written here */
    );
/* If SQL table is structured as:
  Name        | Age
  -----------------------
  Alice       | 43
  Bob         | 28
  Cindy       | 21

  then &result will look like:

  result[0] = "Name";
  result[1] = "Age";
  result[2] = "Alice";
  result[3] = "43";
  result[4] = "Bob";
  result[5] = "28";
  result[6] = "Cindy";
  result[7] = "21";
*/
  std::vector< std::vector<double> > columns;
  columns.clear();
  columns.resize(ncol);

  for (int n = 0; n < ncol; n++)
  {
    columns[n].resize(nrow);
  }
  if (rc == SQLITE_OK) {
    for (int i = 0; i < nrow*ncol; i++)
    {
      int col = i % ncol;
      int row = floor(i / ncol);
      if (result[ncol + i]) // skip column names
      {
        std::string val(result[ncol + i]);
        columns[col][row] = atof(val.c_str());
      }
    }
  }
  sqlite3_free_table(result);

  return columns;
}

/* Caclulate a histogram from the col array with bins number of bins and values between
minbin and maxbin
*/
std::vector<histobin> CalcHistogram(std::vector< std::vector<double> > Yvals,
                                     int bins, double minbin, double maxbin)
{
  std::vector<histobin> histo;

  histo.resize(bins);
  double bindomain = maxbin - minbin;
  double binwidth = bindomain / bins;
  int accumcount = 0;
  for (unsigned i = 0; i < histo.size(); i++)
  {
    double upper = binwidth * (i + 1) + minbin;
    double middle = binwidth * (i + 0.5) + minbin;
    double lower = binwidth * i + minbin;
    histo[i].binval = middle;
    histo[i].count = 0;

    for (unsigned j = 0; j < Yvals[0].size(); j++)
    {
      if (Yvals[0][j] >= lower && Yvals[0][j] < upper)
      {
        histo[i].count++;
        accumcount++;
      }
    }
    histo[i].accumcount = accumcount;
  }

  return histo;
};

/* Caclulate interpolation values for scatter data within bin values between
minbin and maxbin
*/
std::vector<interpolatebin> CalcInterpolations(std::vector< std::vector<double> > XYvals,
                                               int bins, double minbin, double maxbin)
{
  std::vector< std::vector<double> > shiftval;
  shiftval.resize(2);
  shiftval[0].resize(bins);
  shiftval[1].resize(bins);
  //double shiftconst = 123.321;

  std::vector<interpolatebin> interpol;
  interpol.resize(bins);
  double bindomain = maxbin - minbin;
  double binwidth = bindomain / bins;
  for (unsigned i = 0; i < interpol.size(); i++)
  {
    double upper = binwidth * (i + 1) + minbin;
    double middle = binwidth * (i + 0.5) + minbin;
    double lower = binwidth * i + minbin;
    interpol[i].xval = middle;
    interpol[i].count = 0;
    // first calculate shiftconst used for avoiding numerical instability
    // by assigning it to the mean value of values in the bin
    double shiftconst = 0;
    for (unsigned j = 0; j < XYvals[0].size(); j++)
    {
      if (XYvals[0][j] >= lower && XYvals[0][j] < upper)
      {
        shiftconst = XYvals[1][j];
        interpol[i].count++;
      }
    }
    if (interpol[i].count)
      shiftconst /= interpol[i].count;

    shiftval[0][i] = shiftval[1][i] = 0.0;
    for (unsigned j = 0; j < XYvals[0].size(); j++)
    {
      if (XYvals[0][j] >= lower && XYvals[0][j] < upper)
      {
        double shifted = XYvals[1][j] - shiftconst;
        shiftval[0][i] += shifted; // avoid numerical instability close to zero
        shiftval[1][i] += shifted*shifted;
        interpol[i].yval += XYvals[1][j];
      }
    }
    interpol[i].yval /= interpol[i].count;
    interpol[i].sigma = sqrt( ( shiftval[1][i]
      - (shiftval[0][i] * shiftval[0][i])/interpol[i].count)/ interpol[i].count);
    // Margin of Error (MOE) of a mean value is based on Z*sigma/sqrt(N)
    // Z=1.96 corresponds to 95% confidence
    interpol[i].sem = interpol[i].sigma/sqrt(interpol[i].count);
  }

  return interpol;
}

<commit_msg>comment with Zscore confidence table<commit_after>/*
helpers.cpp, Robert Oeffner 2017

*/

#include "helpers.h"

std::vector< std::vector<double> > GetColumns(sqlite3* db, std::string sqlxprs)
{
  // get column from sql expression and return it
  char *zErrMsg;
  char **result;
  int rc;
  int nrow, ncol;
  int db_open;
  rc = sqlite3_get_table(
    db,              /* An open database */
    sqlxprs.c_str(),       /* SQL to be executed */
    &result,       /* Result written to a char *[]  that this points to */
    &nrow,             /* Number of result rows written here */
    &ncol,          /* Number of result columns written here */
    &zErrMsg          /* Error msg written here */
    );
/* If SQL table is structured as:
  Name        | Age
  -----------------------
  Alice       | 43
  Bob         | 28
  Cindy       | 21

  then &result will look like:

  result[0] = "Name";
  result[1] = "Age";
  result[2] = "Alice";
  result[3] = "43";
  result[4] = "Bob";
  result[5] = "28";
  result[6] = "Cindy";
  result[7] = "21";
*/
  std::vector< std::vector<double> > columns;
  columns.clear();
  columns.resize(ncol);

  for (int n = 0; n < ncol; n++)
  {
    columns[n].resize(nrow);
  }
  if (rc == SQLITE_OK) {
    for (int i = 0; i < nrow*ncol; i++)
    {
      int col = i % ncol;
      int row = floor(i / ncol);
      if (result[ncol + i]) // skip column names
      {
        std::string val(result[ncol + i]);
        columns[col][row] = atof(val.c_str());
      }
    }
  }
  sqlite3_free_table(result);

  return columns;
}

/* Caclulate a histogram from the col array with bins number of bins and values between
minbin and maxbin
*/
std::vector<histobin> CalcHistogram(std::vector< std::vector<double> > Yvals,
                                     int bins, double minbin, double maxbin)
{
  std::vector<histobin> histo;

  histo.resize(bins);
  double bindomain = maxbin - minbin;
  double binwidth = bindomain / bins;
  int accumcount = 0;
  for (unsigned i = 0; i < histo.size(); i++)
  {
    double upper = binwidth * (i + 1) + minbin;
    double middle = binwidth * (i + 0.5) + minbin;
    double lower = binwidth * i + minbin;
    histo[i].binval = middle;
    histo[i].count = 0;

    for (unsigned j = 0; j < Yvals[0].size(); j++)
    {
      if (Yvals[0][j] >= lower && Yvals[0][j] < upper)
      {
        histo[i].count++;
        accumcount++;
      }
    }
    histo[i].accumcount = accumcount;
  }

  return histo;
};

/* Caclulate interpolation values for scatter data within bin values between
minbin and maxbin
*/
std::vector<interpolatebin> CalcInterpolations(std::vector< std::vector<double> > XYvals,
                                               int bins, double minbin, double maxbin)
{
  std::vector< std::vector<double> > shiftval;
  shiftval.resize(2);
  shiftval[0].resize(bins);
  shiftval[1].resize(bins);
  //double shiftconst = 123.321;

  std::vector<interpolatebin> interpol;
  interpol.resize(bins);
  double bindomain = maxbin - minbin;
  double binwidth = bindomain / bins;
  for (unsigned i = 0; i < interpol.size(); i++)
  {
    double upper = binwidth * (i + 1) + minbin;
    double middle = binwidth * (i + 0.5) + minbin;
    double lower = binwidth * i + minbin;
    interpol[i].xval = middle;
    interpol[i].count = 0;
    // first calculate shiftconst used for avoiding numerical instability
    // by assigning it to the mean value of values in the bin
    double shiftconst = 0;
    for (unsigned j = 0; j < XYvals[0].size(); j++)
    {
      if (XYvals[0][j] >= lower && XYvals[0][j] < upper)
      {
        shiftconst = XYvals[1][j];
        interpol[i].count++;
      }
    }
    if (interpol[i].count)
      shiftconst /= interpol[i].count;

    shiftval[0][i] = shiftval[1][i] = 0.0;
    for (unsigned j = 0; j < XYvals[0].size(); j++)
    {
      if (XYvals[0][j] >= lower && XYvals[0][j] < upper)
      {
        double shifted = XYvals[1][j] - shiftconst;
        shiftval[0][i] += shifted; // avoid numerical instability close to zero
        shiftval[1][i] += shifted*shifted;
        interpol[i].yval += XYvals[1][j];
      }
    }
    interpol[i].yval /= interpol[i].count;
    interpol[i].sigma = sqrt( ( shiftval[1][i]
      - (shiftval[0][i] * shiftval[0][i])/interpol[i].count)/ interpol[i].count);
/*
Margin of Error (MOE) of a mean value is based on Z*sigma/sqrt(N) Z=1.96 corresponds to 95% confidence
Z-Score Confidence Limit (%)
3       99.73
2.58    99
2.33    98
2.17    97
2.05    96
2.0     95.45
1.96    95
1.64    90

*/

    interpol[i].sem = interpol[i].sigma/sqrt(interpol[i].count);
  }

  return interpol;
}

<|endoftext|>


<commit_before>//===-- fork.cpp ----------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Intercept calls to fork()
//
//===----------------------------------------------------------------------===//

#include <unistd.h>

#include "ipcopt.h"

#include "debug.h"
#include "getfromlibc.h"
#include "system.h"
#include "wrapper.h"

BEGIN_EXTERN_C
pid_t __real_fork(void) { CALL_REAL(fork); }

pid_t __internal_fork(void) {
  // Re-registered all fd's before
  // passing to children.
  // This is bad, but makes it easy to avoid
  // racing child's reregistration against our closing them.
  register_inherited_fds();
  pid_t p = __real_fork();

  switch (p) {
  case -1:
    ipclog("Error in fork()!\n");
    break;
  case 0:
    // child
    ipclog("FORK! Parent is: %d\n", getppid());
    break;
  default:
    // parent
    ipclog("Fork! New child is: %d\n", p);
  }

  return p;
}

END_EXTERN_C
<commit_msg>libipc: Avoid calling functions if we don't use their output.<commit_after>//===-- fork.cpp ----------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Intercept calls to fork()
//
//===----------------------------------------------------------------------===//

#include <unistd.h>

#include "ipcopt.h"

#include "debug.h"
#include "getfromlibc.h"
#include "system.h"
#include "wrapper.h"

BEGIN_EXTERN_C
pid_t __real_fork(void) { CALL_REAL(fork); }

pid_t __internal_fork(void) {
  // Re-registered all fd's before
  // passing to children.
  // This is bad, but makes it easy to avoid
  // racing child's reregistration against our closing them.
  register_inherited_fds();
  pid_t p = __real_fork();

  switch (p) {
  case -1:
    ipclog("Error in fork()!\n");
    break;
  case 0:
    // child
#if USE_DEBUG_LOGGER
    ipclog("FORK! Parent is: %d\n", getppid());
#endif
    break;
  default:
    // parent
    ipclog("Fork! New child is: %d\n", p);
  }

  return p;
}

END_EXTERN_C
<|endoftext|>


<commit_before>#pragma once

template <class TFunc>
class scoped_type : noncopyable
{
public:
    scoped_type(TFunc f)
    : m_deferred(f)
    {
    }

    ~scoped_type()
    {
        m_deferred()
    }

private:
    m_deferred;
};

template <class TFunc>
scoped_type<TFunc> scoped(TFunc f)
{
    return scoped_type(TFunc);
}

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

class timer
{
public:
    timer(std::clock_t time=std::clock()): m_time(time) {}

    std::clock_t m_time;

    friend ostream& operator<<(ostream& o, const timer& t)
    {
        return o << t.m_time;
    }
};

class print: noncopyable
{
public:
    printer(ostream& stream=std::cout):m_stream(stream) {}

    template <class T>
    const T& operator(const T& what)
    {
        m_stream << what;
        return *this;
    }
    ostream& m_stream;
};

//------------------------------------------------------------------------------
// composition
template <class F, class G>
decltype(auto) compose(F&& f, G&& g)
{
    return [=](auto x) { return f(g(x)); };
}

template <class F1, class F2, class F3>
decltype(auto) compose(F1&& f1, F2&& f2, F3&& f3)
{
    return [=](auto x) { return F1(F2(F3(x))); };
}

/// .... more versions

void test()
{
    scoped(compose(timer(), print));
    scoped(profile(__func__), [](profile& p){ p.exit_scope(__func__) });
    scoped(profile(__func__));
    scoped([](){ cout << 'finished: ' << __func__ << endl; });

    auto wrapper = [](auto what){
        cout << "started: " << what << endl;
        return [](){ cout << "finished: " << what << endl; }
    }
    scoped(wrapper);

}<commit_msg>scoped updated<commit_after>/******************************************************************************

Copyright (c) Dmitry Dolzhenko

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.

*******************************************************************************/

#pragma once

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

// include local:

// include std:

// forward declarations:

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

namespace limo
{

    template <class TFunc> class scoped_type : noncopyable
    {
    public:
        scoped_type(TFunc f): m_deferred(f) {}
        ~scoped_type() { m_deferred(); }
    private:
        TFunc m_deferred;
    };

    template <class TFunc> scoped_type<TFunc> scoped(TFunc f)
    {
        return scoped_type(TFunc);
    }

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

    class timer
    {
    public:
        timer(std::clock_t time=std::clock()): m_time(time) {}

        std::clock_t time() const { return m_time; }

        friend ostream& operator<<(ostream& o, const timer& t)
        {
            return o << t.m_time;
        }

    private:
        std::clock_t m_time;
    };

    class printer : noncopyable
    {
    public:
        printer(ostream& stream=std::cout):m_stream(stream) {}

        template <class T>
        const T& operator(const T& what)
        {
            m_stream << what;
            return *this;
        }
    private:
        ostream& m_stream;
    };

    //------------------------------------------------------------------------------
    // composition
    template <class F, class G>
    decltype(auto) compose(F&& f, G&& g)
    {
        return [=](auto x) { return f(g(x)); };
    }

    template <class F1, class F2, class F3>
    decltype(auto) compose(F1&& f1, F2&& f2, F3&& f3)
    {
        return [=](auto x) { return F1(F2(F3(x))); };
    }

    /// .... more versions

    //------------------------------------------------------------------------------
    // profiler

    // global variable
    typedef std::map<std::difference_type, profile_data> data_type;
    data_type __profile_data;

    decltype(auto) profiler(const char* id)
    {
        auto current = id-nullptr;
        auto t = timer();
        return [current, t]() { __profile_data[m_current].update(timer.time()); }
    }

    void print_stats()
    {
        for(const auto& x : __profile_data)
        {
            // print calls totaltime etc...
        }
    }

    /// This is test
    void test()
    {
        // this will create a timer and print it at the end of scope(function)
        scoped(compose(timer(), print));

        // this will calculate calls and total time of this function
        scoped(profiler(__func__));

        // this will print finished func name after function is finished
        scoped([](){ cout << 'finished: ' << __func__ << endl; });

        auto wrapper = [](auto what){
            cout << "started: " << what << endl;
            return [](){ cout << "finished: " << what << endl; }
        }

        // this will print start function now and after finis will print fincished function
        scoped(wrapper);

        /// your code code
        /// ...
    }

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

} // namespace limo
<|endoftext|>


<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014, 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include <abaclade.hxx>
#include "binary/detail/file_init_data.hxx"

#if ABC_HOST_API_POSIX
   #include <errno.h> // E* errno
   #include <fcntl.h> // O_* fcntl()
   #include <sys/stat.h> // S_* stat()
   #include <unistd.h> // *_FILENO isatty() open()
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary globals

namespace abc {
namespace io {
namespace binary {

namespace {

std::shared_ptr<file_writer> g_pbfwStdErr;
std::shared_ptr<file_reader> g_pbfrStdIn;
std::shared_ptr<file_writer> g_pbfwStdOut;

/*! Instantiates a binary::base specialization appropriate for the descriptor in *pfid, returning a
shared pointer to it.

pfid
   Data that will be passed to the constructor of the file object.
return
   Shared pointer to the newly created object.
*/
std::shared_ptr<file_base> _construct(detail::file_init_data * pfid) {
   ABC_TRACE_FUNC(pfid);

#if ABC_HOST_API_POSIX
   if (::fstat(pfid->fd.get(), &pfid->statFile)) {
      throw_os_error();
   }
   if (S_ISREG(pfid->statFile.st_mode)) {
      switch (pfid->am.base()) {
         case access_mode::read:
            return std::make_shared<regular_file_reader>(pfid);
         case access_mode::write:
         case access_mode::write_append:
            return std::make_shared<regular_file_writer>(pfid);
         case access_mode::read_write:
            // TODO: regular_file_random
            break;
      }
   }
   if (S_ISCHR(pfid->statFile.st_mode) && ::isatty(pfid->fd.get())) {
      switch (pfid->am.base()) {
         case access_mode::read:
            return std::make_shared<console_reader>(pfid);
         case access_mode::write:
            return std::make_shared<console_writer>(pfid);
         case access_mode::read_write:
         case access_mode::write_append:
            // TODO: use a better exception class.
            ABC_THROW(argument_error, ());
      }
   }
   if (S_ISFIFO(pfid->statFile.st_mode) || S_ISSOCK(pfid->statFile.st_mode)) {
      switch (pfid->am.base()) {
         case access_mode::read:
            return std::make_shared<pipe_reader>(pfid);
         case access_mode::write:
            return std::make_shared<pipe_writer>(pfid);
         case access_mode::read_write:
         case access_mode::write_append:
            // TODO: use a better exception class.
            ABC_THROW(argument_error, ());
      }
   }
#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX
   switch (::GetFileType(pfid->fd.get())) {
      case FILE_TYPE_CHAR: {
         /* Serial line or console.

         Using ::GetConsoleMode() to detect a console handle requires GENERIC_READ access rights,
         which could be a problem with stdout/stderr because we don’t ask for that permission for
         these handles; however, for consoles, “The handles returned by CreateFile,
         CreateConsoleScreenBuffer, and GetStdHandle have the GENERIC_READ and GENERIC_WRITE access
         rights”, so we can trust this to succeed for console handles. */

         DWORD iConsoleMode;
         if (::GetConsoleMode(pfid->fd.get(), &iConsoleMode)) {
            switch (pfid->am.base()) {
               case access_mode::read:
                  return std::make_shared<console_reader>(pfid);
               case access_mode::write:
                  return std::make_shared<console_writer>(pfid);
               case access_mode::read_write:
               case access_mode::write_append:
                  // TODO: use a better exception class.
                  ABC_THROW(argument_error, ());
            }
         }
         break;
      }
      case FILE_TYPE_DISK:
         // Regular file.
         switch (pfid->am.base()) {
            case access_mode::read:
               return std::make_shared<regular_file_reader>(pfid);
            case access_mode::write:
            case access_mode::write_append:
               return std::make_shared<regular_file_writer>(pfid);
            case access_mode::read_write:
               // TODO: regular_file_random
               break;
         }
         break;

      case FILE_TYPE_PIPE:
         // Socket or pipe.
         switch (pfid->am.base()) {
            case access_mode::read:
               return std::make_shared<pipe_reader>(pfid);
            case access_mode::write:
               return std::make_shared<pipe_writer>(pfid);
            case access_mode::read_write:
            case access_mode::write_append:
               // TODO: use a better exception class.
               ABC_THROW(argument_error, ());
         }
         break;

      case FILE_TYPE_UNKNOWN: {
         // Unknown or error.
         DWORD iErr = ::GetLastError();
         if (iErr != ERROR_SUCCESS) {
            throw_os_error(iErr);
         }
         break;
      }
   }
#else //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32
   #error "TODO: HOST_API"
#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32 … else

   // If a file object was not returned in the code above, return a generic file.
   switch (pfid->am.base()) {
      case access_mode::read:
         return std::make_shared<file_reader>(pfid);
      case access_mode::write:
         return std::make_shared<file_writer>(pfid);
      default:
         // TODO: use a better exception class.
         ABC_THROW(argument_error, ());
   }
}

/*! Returns a new binary I/O object controlling the specified file descriptor.

fd
   File descriptor to take ownership of.
am
   Desired access mode.
return
   Pointer to a binary I/O object controlling fd.
*/
std::shared_ptr<file_base> _attach(filedesc && fd, access_mode am) {
   ABC_TRACE_FUNC(/*fd*/);

   detail::file_init_data fid;
   fid.fd = std::move(fd);
   fid.am = am;
   /* There’s no way of knowing (in Win32 or in POSIX, at least) whether a file has been opened with
   asynchronous I/O enabled, so for safety assume it has. */
   fid.bAllowAsync = true;
   /* Since this method is supposed to be used only for standard descriptors, assume that OS
   buffering is on. */
   fid.bBypassCache = false;
   return _construct(&fid);
}

} //namespace

std::shared_ptr<file_writer> stderr() {
   ABC_TRACE_FUNC();

   /* TODO: under Win32, GUI subsystem programs will get nullptr when calling ::GetStdHandle(). To
   avoid exceptions later when performing I/O on it, we need to ::SetStdHandle() with a file opened
   on “NUL”. This mimics the behavior of Linux GUI programs, where all their standard I/O handles
   are open on /dev/null. */

   // TODO: mutex!
   if (!g_pbfwStdErr) {
      g_pbfwStdErr = std::dynamic_pointer_cast<file_writer>(_attach(filedesc(
#if ABC_HOST_API_POSIX
         STDERR_FILENO,
#elif ABC_HOST_API_WIN32
         ::GetStdHandle(STD_ERROR_HANDLE),
#else
   #error "TODO: HOST_API"
#endif
         false
      ), access_mode::write));
   }
   return g_pbfwStdErr;
}

std::shared_ptr<file_reader> stdin() {
   ABC_TRACE_FUNC();

   /* TODO: under Win32, GUI subsystem programs will get nullptr when calling ::GetStdHandle(). To
   avoid exceptions later when performing I/O on it, we need to ::SetStdHandle() with a file opened
   on “NUL”. This mimics the behavior of Linux GUI programs, where all their standard I/O handles
   are open on /dev/null. */

   // TODO: mutex!
   if (!g_pbfrStdIn) {
      g_pbfrStdIn = std::dynamic_pointer_cast<file_reader>(_attach(filedesc(
#if ABC_HOST_API_POSIX
         STDIN_FILENO,
#elif ABC_HOST_API_WIN32
         ::GetStdHandle(STD_INPUT_HANDLE),
#else
   #error "TODO: HOST_API"
#endif
         false
      ), access_mode::read));
   }
   return g_pbfrStdIn;
}

std::shared_ptr<file_writer> stdout() {
   ABC_TRACE_FUNC();

   /* TODO: under Win32, GUI subsystem programs will get nullptr when calling ::GetStdHandle(). To
   avoid exceptions later when performing I/O on it, we need to ::SetStdHandle() with a file opened
   on “NUL”. This mimics the behavior of Linux GUI programs, where all their standard I/O handles
   are open on /dev/null. */

   // TODO: mutex!
   if (!g_pbfwStdOut) {
      g_pbfwStdOut = std::dynamic_pointer_cast<file_writer>(_attach(filedesc(
#if ABC_HOST_API_POSIX
         STDOUT_FILENO,
#elif ABC_HOST_API_WIN32
         ::GetStdHandle(STD_OUTPUT_HANDLE),
#else
   #error "TODO: HOST_API"
#endif
         false
      ), access_mode::write));
   }
   return g_pbfwStdOut;
}

std::shared_ptr<file_base> open(
   os::path const & op, access_mode am, bool bAsync /*= false*/, bool bBypassCache /*= false*/
) {
   ABC_TRACE_FUNC(op, am, bAsync, bBypassCache);

   detail::file_init_data fid;
#if ABC_HOST_API_POSIX
   int iFlags;
   switch (am.base()) {
      case access_mode::read:
         iFlags = O_RDONLY;
         break;
      case access_mode::read_write:
         iFlags = O_RDWR | O_CREAT;
         break;
      case access_mode::write:
         iFlags = O_WRONLY | O_CREAT | O_TRUNC;
         break;
      case access_mode::write_append:
         iFlags = O_APPEND;
         break;
   }
   iFlags |= O_CLOEXEC;
   if (bAsync) {
      iFlags |= O_NONBLOCK;
   }
   #ifdef O_DIRECT
      if (bBypassCache) {
         iFlags |= O_DIRECT;
      }
   #endif
   // Note: this does not compare the new fd against 0; instead it calls fid.fd.operator bool().
   while (!(fid.fd = ::open(op.os_str().c_str(), iFlags, 0666))) {
      int iErr = errno;
      switch (iErr) {
         case EINTR:
            break;
         case ENODEV: // No such device (POSIX.1-2001)
         case ENOENT: // No such file or directory (POSIX.1-2001)
            ABC_THROW(file_not_found_error, (op, iErr));
         default:
            throw_os_error(iErr);
      }
   }
   #ifndef O_DIRECT
      #if ABC_HOST_API_DARWIN
         if (bBypassCache) {
            if (::fcntl(fid.fd.get(), F_NOCACHE, 1) == -1) {
               throw_os_error();
            }
         }
      #else
         #error "TODO: HOST_API"
      #endif
   #endif //ifndef O_DIRECT
#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX
   DWORD iAccess, iShareMode, iAction, iFlags = FILE_ATTRIBUTE_NORMAL;
   switch (am.base()) {
      case access_mode::read:
         iAccess = GENERIC_READ;
         iShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
         iAction = OPEN_EXISTING;
         break;
      case access_mode::read_write:
         iAccess = GENERIC_READ | GENERIC_WRITE;
         iShareMode = FILE_SHARE_READ;
         iAction = OPEN_ALWAYS;
         break;
      case access_mode::write:
         iAccess = GENERIC_WRITE;
         iShareMode = FILE_SHARE_READ;
         iAction = CREATE_ALWAYS;
         break;
      case access_mode::write_append:
         /* This iAccess combination is FILE_GENERIC_WRITE & ~FILE_WRITE_DATA; MSDN states that “for
         local files, write operations will not overwrite existing data”. Requiring fewer
         permissions, this also allows ::CreateFile() to succeed on files with stricter ACLs. */
         iAccess = FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | STANDARD_RIGHTS_WRITE | SYNCHRONIZE;
         iShareMode = FILE_SHARE_READ;
         iAction = OPEN_ALWAYS;
         break;
   }
   if (bAsync) {
      iFlags |= FILE_FLAG_OVERLAPPED;
   }
   if (bBypassCache) {
      // Turn off all caching/buffering and enable FILE_FLAG_NO_BUFFERING.
      iFlags &= ~(FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_RANDOM_ACCESS);
      iFlags |= FILE_FLAG_NO_BUFFERING;
   }
   if (!(fid.fd = ::CreateFile(
      op.os_str().c_str(), iAccess, iShareMode, nullptr, iAction, iFlags, nullptr
   ))) {
      DWORD iErr = ::GetLastError();
      switch (iErr) {
         case ERROR_PATH_NOT_FOUND: // The system cannot find the path specified.
         case ERROR_UNKNOWN_PORT: // The specified port is unknown.
            ABC_THROW(file_not_found_error, (op, iErr));
         default:
            throw_os_error(iErr);
      }
   }
#else //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32
   #error "TODO: HOST_API"
#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32 … else
   fid.am = am;
   fid.bAllowAsync = bAsync;
   fid.bBypassCache = bBypassCache;
   return _construct(&fid);
}

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary::base

namespace abc {
namespace io {
namespace binary {

/*virtual*/ base::~base() {
}

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
<commit_msg>Missed a traceable argument<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014, 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include <abaclade.hxx>
#include "binary/detail/file_init_data.hxx"

#if ABC_HOST_API_POSIX
   #include <errno.h> // E* errno
   #include <fcntl.h> // O_* fcntl()
   #include <sys/stat.h> // S_* stat()
   #include <unistd.h> // *_FILENO isatty() open()
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary globals

namespace abc {
namespace io {
namespace binary {

namespace {

std::shared_ptr<file_writer> g_pbfwStdErr;
std::shared_ptr<file_reader> g_pbfrStdIn;
std::shared_ptr<file_writer> g_pbfwStdOut;

/*! Instantiates a binary::base specialization appropriate for the descriptor in *pfid, returning a
shared pointer to it.

pfid
   Data that will be passed to the constructor of the file object.
return
   Shared pointer to the newly created object.
*/
std::shared_ptr<file_base> _construct(detail::file_init_data * pfid) {
   ABC_TRACE_FUNC(pfid);

#if ABC_HOST_API_POSIX
   if (::fstat(pfid->fd.get(), &pfid->statFile)) {
      throw_os_error();
   }
   if (S_ISREG(pfid->statFile.st_mode)) {
      switch (pfid->am.base()) {
         case access_mode::read:
            return std::make_shared<regular_file_reader>(pfid);
         case access_mode::write:
         case access_mode::write_append:
            return std::make_shared<regular_file_writer>(pfid);
         case access_mode::read_write:
            // TODO: regular_file_random
            break;
      }
   }
   if (S_ISCHR(pfid->statFile.st_mode) && ::isatty(pfid->fd.get())) {
      switch (pfid->am.base()) {
         case access_mode::read:
            return std::make_shared<console_reader>(pfid);
         case access_mode::write:
            return std::make_shared<console_writer>(pfid);
         case access_mode::read_write:
         case access_mode::write_append:
            // TODO: use a better exception class.
            ABC_THROW(argument_error, ());
      }
   }
   if (S_ISFIFO(pfid->statFile.st_mode) || S_ISSOCK(pfid->statFile.st_mode)) {
      switch (pfid->am.base()) {
         case access_mode::read:
            return std::make_shared<pipe_reader>(pfid);
         case access_mode::write:
            return std::make_shared<pipe_writer>(pfid);
         case access_mode::read_write:
         case access_mode::write_append:
            // TODO: use a better exception class.
            ABC_THROW(argument_error, ());
      }
   }
#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX
   switch (::GetFileType(pfid->fd.get())) {
      case FILE_TYPE_CHAR: {
         /* Serial line or console.

         Using ::GetConsoleMode() to detect a console handle requires GENERIC_READ access rights,
         which could be a problem with stdout/stderr because we don’t ask for that permission for
         these handles; however, for consoles, “The handles returned by CreateFile,
         CreateConsoleScreenBuffer, and GetStdHandle have the GENERIC_READ and GENERIC_WRITE access
         rights”, so we can trust this to succeed for console handles. */

         DWORD iConsoleMode;
         if (::GetConsoleMode(pfid->fd.get(), &iConsoleMode)) {
            switch (pfid->am.base()) {
               case access_mode::read:
                  return std::make_shared<console_reader>(pfid);
               case access_mode::write:
                  return std::make_shared<console_writer>(pfid);
               case access_mode::read_write:
               case access_mode::write_append:
                  // TODO: use a better exception class.
                  ABC_THROW(argument_error, ());
            }
         }
         break;
      }
      case FILE_TYPE_DISK:
         // Regular file.
         switch (pfid->am.base()) {
            case access_mode::read:
               return std::make_shared<regular_file_reader>(pfid);
            case access_mode::write:
            case access_mode::write_append:
               return std::make_shared<regular_file_writer>(pfid);
            case access_mode::read_write:
               // TODO: regular_file_random
               break;
         }
         break;

      case FILE_TYPE_PIPE:
         // Socket or pipe.
         switch (pfid->am.base()) {
            case access_mode::read:
               return std::make_shared<pipe_reader>(pfid);
            case access_mode::write:
               return std::make_shared<pipe_writer>(pfid);
            case access_mode::read_write:
            case access_mode::write_append:
               // TODO: use a better exception class.
               ABC_THROW(argument_error, ());
         }
         break;

      case FILE_TYPE_UNKNOWN: {
         // Unknown or error.
         DWORD iErr = ::GetLastError();
         if (iErr != ERROR_SUCCESS) {
            throw_os_error(iErr);
         }
         break;
      }
   }
#else //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32
   #error "TODO: HOST_API"
#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32 … else

   // If a file object was not returned in the code above, return a generic file.
   switch (pfid->am.base()) {
      case access_mode::read:
         return std::make_shared<file_reader>(pfid);
      case access_mode::write:
         return std::make_shared<file_writer>(pfid);
      default:
         // TODO: use a better exception class.
         ABC_THROW(argument_error, ());
   }
}

/*! Returns a new binary I/O object controlling the specified file descriptor.

fd
   File descriptor to take ownership of.
am
   Desired access mode.
return
   Pointer to a binary I/O object controlling fd.
*/
std::shared_ptr<file_base> _attach(filedesc && fd, access_mode am) {
   ABC_TRACE_FUNC(/*fd, */am);

   detail::file_init_data fid;
   fid.fd = std::move(fd);
   fid.am = am;
   /* There’s no way of knowing (in Win32 or in POSIX, at least) whether a file has been opened with
   asynchronous I/O enabled, so for safety assume it has. */
   fid.bAllowAsync = true;
   /* Since this method is supposed to be used only for standard descriptors, assume that OS
   buffering is on. */
   fid.bBypassCache = false;
   return _construct(&fid);
}

} //namespace

std::shared_ptr<file_writer> stderr() {
   ABC_TRACE_FUNC();

   /* TODO: under Win32, GUI subsystem programs will get nullptr when calling ::GetStdHandle(). To
   avoid exceptions later when performing I/O on it, we need to ::SetStdHandle() with a file opened
   on “NUL”. This mimics the behavior of Linux GUI programs, where all their standard I/O handles
   are open on /dev/null. */

   // TODO: mutex!
   if (!g_pbfwStdErr) {
      g_pbfwStdErr = std::dynamic_pointer_cast<file_writer>(_attach(filedesc(
#if ABC_HOST_API_POSIX
         STDERR_FILENO,
#elif ABC_HOST_API_WIN32
         ::GetStdHandle(STD_ERROR_HANDLE),
#else
   #error "TODO: HOST_API"
#endif
         false
      ), access_mode::write));
   }
   return g_pbfwStdErr;
}

std::shared_ptr<file_reader> stdin() {
   ABC_TRACE_FUNC();

   /* TODO: under Win32, GUI subsystem programs will get nullptr when calling ::GetStdHandle(). To
   avoid exceptions later when performing I/O on it, we need to ::SetStdHandle() with a file opened
   on “NUL”. This mimics the behavior of Linux GUI programs, where all their standard I/O handles
   are open on /dev/null. */

   // TODO: mutex!
   if (!g_pbfrStdIn) {
      g_pbfrStdIn = std::dynamic_pointer_cast<file_reader>(_attach(filedesc(
#if ABC_HOST_API_POSIX
         STDIN_FILENO,
#elif ABC_HOST_API_WIN32
         ::GetStdHandle(STD_INPUT_HANDLE),
#else
   #error "TODO: HOST_API"
#endif
         false
      ), access_mode::read));
   }
   return g_pbfrStdIn;
}

std::shared_ptr<file_writer> stdout() {
   ABC_TRACE_FUNC();

   /* TODO: under Win32, GUI subsystem programs will get nullptr when calling ::GetStdHandle(). To
   avoid exceptions later when performing I/O on it, we need to ::SetStdHandle() with a file opened
   on “NUL”. This mimics the behavior of Linux GUI programs, where all their standard I/O handles
   are open on /dev/null. */

   // TODO: mutex!
   if (!g_pbfwStdOut) {
      g_pbfwStdOut = std::dynamic_pointer_cast<file_writer>(_attach(filedesc(
#if ABC_HOST_API_POSIX
         STDOUT_FILENO,
#elif ABC_HOST_API_WIN32
         ::GetStdHandle(STD_OUTPUT_HANDLE),
#else
   #error "TODO: HOST_API"
#endif
         false
      ), access_mode::write));
   }
   return g_pbfwStdOut;
}

std::shared_ptr<file_base> open(
   os::path const & op, access_mode am, bool bAsync /*= false*/, bool bBypassCache /*= false*/
) {
   ABC_TRACE_FUNC(op, am, bAsync, bBypassCache);

   detail::file_init_data fid;
#if ABC_HOST_API_POSIX
   int iFlags;
   switch (am.base()) {
      case access_mode::read:
         iFlags = O_RDONLY;
         break;
      case access_mode::read_write:
         iFlags = O_RDWR | O_CREAT;
         break;
      case access_mode::write:
         iFlags = O_WRONLY | O_CREAT | O_TRUNC;
         break;
      case access_mode::write_append:
         iFlags = O_APPEND;
         break;
   }
   iFlags |= O_CLOEXEC;
   if (bAsync) {
      iFlags |= O_NONBLOCK;
   }
   #ifdef O_DIRECT
      if (bBypassCache) {
         iFlags |= O_DIRECT;
      }
   #endif
   // Note: this does not compare the new fd against 0; instead it calls fid.fd.operator bool().
   while (!(fid.fd = ::open(op.os_str().c_str(), iFlags, 0666))) {
      int iErr = errno;
      switch (iErr) {
         case EINTR:
            break;
         case ENODEV: // No such device (POSIX.1-2001)
         case ENOENT: // No such file or directory (POSIX.1-2001)
            ABC_THROW(file_not_found_error, (op, iErr));
         default:
            throw_os_error(iErr);
      }
   }
   #ifndef O_DIRECT
      #if ABC_HOST_API_DARWIN
         if (bBypassCache) {
            if (::fcntl(fid.fd.get(), F_NOCACHE, 1) == -1) {
               throw_os_error();
            }
         }
      #else
         #error "TODO: HOST_API"
      #endif
   #endif //ifndef O_DIRECT
#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX
   DWORD iAccess, iShareMode, iAction, iFlags = FILE_ATTRIBUTE_NORMAL;
   switch (am.base()) {
      case access_mode::read:
         iAccess = GENERIC_READ;
         iShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
         iAction = OPEN_EXISTING;
         break;
      case access_mode::read_write:
         iAccess = GENERIC_READ | GENERIC_WRITE;
         iShareMode = FILE_SHARE_READ;
         iAction = OPEN_ALWAYS;
         break;
      case access_mode::write:
         iAccess = GENERIC_WRITE;
         iShareMode = FILE_SHARE_READ;
         iAction = CREATE_ALWAYS;
         break;
      case access_mode::write_append:
         /* This iAccess combination is FILE_GENERIC_WRITE & ~FILE_WRITE_DATA; MSDN states that “for
         local files, write operations will not overwrite existing data”. Requiring fewer
         permissions, this also allows ::CreateFile() to succeed on files with stricter ACLs. */
         iAccess = FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | STANDARD_RIGHTS_WRITE | SYNCHRONIZE;
         iShareMode = FILE_SHARE_READ;
         iAction = OPEN_ALWAYS;
         break;
   }
   if (bAsync) {
      iFlags |= FILE_FLAG_OVERLAPPED;
   }
   if (bBypassCache) {
      // Turn off all caching/buffering and enable FILE_FLAG_NO_BUFFERING.
      iFlags &= ~(FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_RANDOM_ACCESS);
      iFlags |= FILE_FLAG_NO_BUFFERING;
   }
   if (!(fid.fd = ::CreateFile(
      op.os_str().c_str(), iAccess, iShareMode, nullptr, iAction, iFlags, nullptr
   ))) {
      DWORD iErr = ::GetLastError();
      switch (iErr) {
         case ERROR_PATH_NOT_FOUND: // The system cannot find the path specified.
         case ERROR_UNKNOWN_PORT: // The specified port is unknown.
            ABC_THROW(file_not_found_error, (op, iErr));
         default:
            throw_os_error(iErr);
      }
   }
#else //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32
   #error "TODO: HOST_API"
#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32 … else
   fid.am = am;
   fid.bAllowAsync = bAsync;
   fid.bBypassCache = bBypassCache;
   return _construct(&fid);
}

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::io::binary::base

namespace abc {
namespace io {
namespace binary {

/*virtual*/ base::~base() {
}

} //namespace binary
} //namespace io
} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>//  Natron
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
 *Created by Alexandre GAUTHIER-FOICHAT on 6/1/2012.
 *contact: immarespond at gmail dot com
 *
 */

#include "Texture.h"

#include <iostream>
#include "Global/GLIncludes.h"
#include "Gui/ViewerGL.h"

Texture::Texture(){
    glGenTextures(1, &_texID);

}
void Texture::fillOrAllocateTexture(const TextureRect& texRect ,DataType type){

    glEnable(GL_TEXTURE_2D);
    glActiveTexture (GL_TEXTURE0);
    glBindTexture (GL_TEXTURE_2D, _texID);
    if(texRect == _textureRect && _type == type){
        if(_type == Texture::BYTE){
            glTexSubImage2D(GL_TEXTURE_2D,
                            0,				// level
                            0, 0,				// xoffset, yoffset
                            w(), h(),
                            GL_BGRA,			// format
                            GL_UNSIGNED_INT_8_8_8_8_REV,		// type
                            0);

        }else if(_type == Texture::FLOAT){
            glTexSubImage2D(GL_TEXTURE_2D,
                            0,				// level
                            0, 0 ,				// xoffset, yoffset
                            w(), h(),
                            GL_RGBA,			// format
                            GL_FLOAT,		// type
                            0);
        }
        checkGLErrors();

    }else{
        _textureRect = texRect;
        _type = type;
        glPixelStorei (GL_UNPACK_ALIGNMENT, 1);

        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        if(type == BYTE){
            glTexImage2D(GL_TEXTURE_2D,
                         0,			// level
                         GL_RGBA8, //internalFormat
                         w(), h(),
                         0,			// border
                         GL_BGRA,		// format
                         GL_UNSIGNED_INT_8_8_8_8_REV,	// type
                         0);			// pixels
        }else if(type == FLOAT){
            glTexImage2D (GL_TEXTURE_2D,
                          0,			// level
                          GL_RGBA32F_ARB, //internalFormat
                          w(), h(),
                          0,			// border
                          GL_RGBA,		// format
                          GL_FLOAT,	// type
                          0);			// pixels
        }

        checkGLErrors();
    }
}
void Texture::updatePartOfTexture(const TextureRect& fullRegion,int zoomedY,DataType type){
    glEnable(GL_TEXTURE_2D);
    glActiveTexture (GL_TEXTURE0);
    glBindTexture (GL_TEXTURE_2D, _texID);
    if(fullRegion != _textureRect || _type == type){
        _textureRect = fullRegion;
        _type = type;
        glPixelStorei (GL_UNPACK_ALIGNMENT, 1);

        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        if(type == BYTE){
            glTexImage2D(GL_TEXTURE_2D,
                         0,			// level
                         GL_RGBA8, //internalFormat
                         w(), h(),
                         0,			// border
                         GL_BGRA,		// format
                         GL_UNSIGNED_INT_8_8_8_8_REV,	// type
                         0);			// pixels
        }else if(type == FLOAT){
            glTexImage2D (GL_TEXTURE_2D,
                          0,			// level
                          GL_RGBA32F_ARB, //internalFormat
                          w(), h(),
                          0,			// border
                          GL_RGBA,		// format
                          GL_FLOAT,	// type
                          0);			// pixels
        }

    }

    if(_type == Texture::BYTE){
        glTexSubImage2D(GL_TEXTURE_2D,
                        0,				// level
                        0, 0,				// xoffset, yoffset
                        w(), zoomedY+1,
                        GL_BGRA,			// format
                        GL_UNSIGNED_INT_8_8_8_8_REV,		// type
                        0);

    }else if(_type == Texture::FLOAT){
        glTexSubImage2D(GL_TEXTURE_2D,
                        0,				// level
                        0, 0 ,				// xoffset, yoffset
                        w(), zoomedY+1,
                        GL_RGBA,			// format
                        GL_FLOAT,		// type
                        0);
    }
    checkGLErrors();

}

Texture::~Texture(){
    glDeleteTextures(1, &_texID);
}

<commit_msg>use GL_CLAMP<commit_after>//  Natron
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
 *Created by Alexandre GAUTHIER-FOICHAT on 6/1/2012.
 *contact: immarespond at gmail dot com
 *
 */

#include "Texture.h"

#include <iostream>
#include "Global/GLIncludes.h"
#include "Gui/ViewerGL.h"

Texture::Texture(){
    glGenTextures(1, &_texID);

}
void Texture::fillOrAllocateTexture(const TextureRect& texRect ,DataType type){

    glEnable(GL_TEXTURE_2D);
    glActiveTexture (GL_TEXTURE0);
    glBindTexture (GL_TEXTURE_2D, _texID);
    if(texRect == _textureRect && _type == type){
        if(_type == Texture::BYTE){
            glTexSubImage2D(GL_TEXTURE_2D,
                            0,				// level
                            0, 0,				// xoffset, yoffset
                            w(), h(),
                            GL_BGRA,			// format
                            GL_UNSIGNED_INT_8_8_8_8_REV,		// type
                            0);

        }else if(_type == Texture::FLOAT){
            glTexSubImage2D(GL_TEXTURE_2D,
                            0,				// level
                            0, 0 ,				// xoffset, yoffset
                            w(), h(),
                            GL_RGBA,			// format
                            GL_FLOAT,		// type
                            0);
        }
        checkGLErrors();

    }else{
        _textureRect = texRect;
        _type = type;
        glPixelStorei (GL_UNPACK_ALIGNMENT, 1);

        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        if(type == BYTE){
            glTexImage2D(GL_TEXTURE_2D,
                         0,			// level
                         GL_RGBA8, //internalFormat
                         w(), h(),
                         0,			// border
                         GL_BGRA,		// format
                         GL_UNSIGNED_INT_8_8_8_8_REV,	// type
                         0);			// pixels
        }else if(type == FLOAT){
            glTexImage2D (GL_TEXTURE_2D,
                          0,			// level
                          GL_RGBA32F_ARB, //internalFormat
                          w(), h(),
                          0,			// border
                          GL_RGBA,		// format
                          GL_FLOAT,	// type
                          0);			// pixels
        }

        checkGLErrors();
    }
}
void Texture::updatePartOfTexture(const TextureRect& fullRegion,int zoomedY,DataType type){
    glEnable(GL_TEXTURE_2D);
    glActiveTexture (GL_TEXTURE0);
    glBindTexture (GL_TEXTURE_2D, _texID);
    if(fullRegion != _textureRect || _type == type){
        _textureRect = fullRegion;
        _type = type;
        glPixelStorei (GL_UNPACK_ALIGNMENT, 1);

        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
        glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
        if(type == BYTE){
            glTexImage2D(GL_TEXTURE_2D,
                         0,			// level
                         GL_RGBA8, //internalFormat
                         w(), h(),
                         0,			// border
                         GL_BGRA,		// format
                         GL_UNSIGNED_INT_8_8_8_8_REV,	// type
                         0);			// pixels
        }else if(type == FLOAT){
            glTexImage2D (GL_TEXTURE_2D,
                          0,			// level
                          GL_RGBA32F_ARB, //internalFormat
                          w(), h(),
                          0,			// border
                          GL_RGBA,		// format
                          GL_FLOAT,	// type
                          0);			// pixels
        }

    }

    if(_type == Texture::BYTE){
        glTexSubImage2D(GL_TEXTURE_2D,
                        0,				// level
                        0, 0,				// xoffset, yoffset
                        w(), zoomedY+1,
                        GL_BGRA,			// format
                        GL_UNSIGNED_INT_8_8_8_8_REV,		// type
                        0);

    }else if(_type == Texture::FLOAT){
        glTexSubImage2D(GL_TEXTURE_2D,
                        0,				// level
                        0, 0 ,				// xoffset, yoffset
                        w(), zoomedY+1,
                        GL_RGBA,			// format
                        GL_FLOAT,		// type
                        0);
    }
    checkGLErrors();

}

Texture::~Texture(){
    glDeleteTextures(1, &_texID);
}

<|endoftext|>