<commit_before>/*
 * Copyright (C) 2015 Nagisa Sekiguchi
 *
 * 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 <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <string>

#include <parser/Lexer.h>

Lexer::Lexer(unsigned int initSize, bool fixed) :
        fp(0),
        bufSize((fixed || initSize > DEFAULT_SIZE) ? initSize : DEFAULT_SIZE),
        buf(new unsigned char[this->bufSize]),
        cursor(this->buf), limit(this->buf), marker(0),
        lineNum(1), endOfFile(false), modeStack(1) {
    this->buf[0] = '\0';    // terminate null character.
    this->modeStack.push_back(yycSTMT);
}

Lexer::Lexer(unsigned int initSize, FILE *fp) :
        Lexer(initSize) {
    this->fp = fp;
}

Lexer::Lexer(FILE *fp) : Lexer(DEFAULT_SIZE, fp) {
}

Lexer::Lexer(const char *src) :
        Lexer(strlen(src) + 1, true) {
    memcpy(this->buf, src, this->bufSize);
    this->limit += this->bufSize - 1;
}

Lexer::Lexer(const Lexer &lexer) :
        Lexer(lexer.getUsedSize(), true) {
    memcpy(this->buf, lexer.buf, this->bufSize);
    this->limit += this->bufSize - 1;
}

Lexer::~Lexer() {
    delete[] this->buf;
    this->buf = 0;
}

void Lexer::expandBuf(unsigned int needSize) {
    unsigned int usedSize = this->getUsedSize();
    unsigned int size = usedSize + needSize;
    if(size > this->bufSize) {
        unsigned int newSize = this->bufSize;
        do {
            newSize *= 2;
        } while(newSize < size);
        unsigned int pos = this->getPos();
        unsigned int markerPos = this->marker - this->buf;
        unsigned char *newBuf = new unsigned char[newSize];
        memcpy(newBuf, this->buf, usedSize);
        delete[] this->buf;
        this->buf = newBuf;
        this->bufSize = newSize;
        this->cursor = this->buf + pos;
        this->limit = this->buf + usedSize - 1;
        this->marker = this->buf + markerPos;
    }
}

bool Lexer::fill(int n) {
    if(this->endOfFile && (this->limit - this->cursor) <= 0) {
        return false;
    }

    if(this->fp == 0) {
        if(this->limit - this->cursor <= 0) {
            this->endOfFile = true;
        }
        return true;
    }
    int needSize = n - (this->limit - this->cursor);
    assert(needSize > -1);
    this->expandBuf(needSize);
    int readSize = fread(this->limit, needSize, 1, this->fp);
    this->limit += readSize;
    *this->limit = '\0';
    if(readSize < needSize) {
        this->endOfFile = true;
    }
    return true;
}

unsigned int Lexer::getPos() const {
    return this->cursor - this->buf;
}

unsigned int Lexer::getBufSize() const {
    return this->bufSize;
}

unsigned int Lexer::getUsedSize() const {
    return this->limit - this->buf + 1;
}

// helper macro definition.
#define RET(k) do { kind = k; goto END; } while(0)

#define SKIP() goto INIT

#define ERROR() do { RET(INVALID); } while(0)

#define POP_MODE() \
    do {\
        if(this->modeStack.size() > 1) {\
            this->modeStack.pop_back();\
        } else {\
            ERROR();\
        }\
    } while(0)

#define PUSH_MODE(m) this->modeStack.push_back(yyc ## m)

#define MODE(m) \
    do {\
        if(this->modeStack.size() > 0) {\
            this->modeStack[this->modeStack.size() - 1] = yyc ## m;\
        } else {\
            ERROR();\
        }\
    } while(0)

#define INC_LINE_NUM() this->lineNum++

#define YYGETCONDITION() this->modeStack.back()

TokenKind Lexer::nextToken(Token &token) {
    /*!re2c
      re2c:define:YYGETCONDITION = YYGETCONDITION;
      re2c:define:YYCTYPE = "unsigned char";
      re2c:define:YYCURSOR = this->cursor;
      re2c:define:YYLIMIT = this->limit;
      re2c:define:YYMARKER = this->marker;
      re2c:define:YYFILL:naked = 1;
      re2c:define:YYFILL@len = #;
      re2c:define:YYFILL = "if(!this->fill(#)) { RET(EOS); }";
      re2c:yyfill:enable = 1;
      re2c:indent:top = 1;
      re2c:indent:string = "    ";

      NUM = '0' | [1-9] [0-9]*;
      DIGITS = [0-9]+;
      FLOAT_SUFFIX =  [eE] [+-]? NUM;
      FLOAT = NUM '.' DIGITS FLOAT_SUFFIX?;

      SQUOTE_CHAR = [^\r\n'\\] | '\\' [btnfr'\\];
      VAR_NAME = [a-zA-Z] [_0-9a-zA-Z]* | '_' [_0-9a-zA-Z]+;
      SPECIAL_NAMES = [@];

      STRING_LITERAL = ['] SQUOTE_CHAR* ['];
      BQUOTE_LITERAL = [`] ('\\' '`' | [^\n\r])+ [`];
      APPLIED_NAME = '$' VAR_NAME;
      SPECIAL_NAME = '$' SPECIAL_NAMES;

      INNER_NAME = APPLIED_NAME | '${' VAR_NAME '}';
      INNER_SPECIAL_NAME = SPECIAL_NAME | '${' SPECIAL_NAMES '}';

      CMD_START_CHAR = '\\' . | [^ \t\r\n;'"`|&<>(){}$#![\]0-9];
      CMD_CHAR       = '\\' . | [^ \t\r\n;'"`|&<>(){}$#![\]];

      LINE_END = ';';
      NEW_LINE = [\r\n];
      COMMENT = '#' [^\r\n]*;
      OTHER = .;
    */

INIT:
    unsigned int startPos = this->getPos();
    TokenKind kind = INVALID;
    /*!re2c
      <STMT,EXPR> 'assert'     { MODE(EXPR); RET(ASSERT); }
      <STMT,EXPR> 'catch'      { MODE(EXPR); RET(CATCH); }
      <STMT,EXPR> 'class'      { MODE(EXPR); RET(CLASS); }
      <STMT,EXPR> 'continue'   { MODE(EXPR); RET(CONTINUE); }
      <STMT,EXPR> 'do'         { MODE(EXPR); RET(DO); }
      <STMT,EXPR> 'else'       { MODE(EXPR); RET(ELSE); }
      <STMT,EXPR> 'extends'    { MODE(EXPR); RET(EXTENDS); }
      <STMT,EXPR> 'export-env' { MODE(EXPR); RET(EXPORT_ENV); }
      <STMT,EXPR> 'finally'    { MODE(EXPR); RET(FINALLY); }
      <STMT,EXPR> 'for'        { MODE(EXPR); RET(FOR); }
      <STMT,EXPR> 'function'   { MODE(EXPR); RET(FUNCTION); }
      <STMT,EXPR> 'if'         { MODE(EXPR); RET(IF); }
      <STMT,EXPR> 'import-env' { MODE(EXPR); RET(IMPORT_ENV); }
      <STMT,EXPR> 'let'        { MODE(EXPR); RET(LET); }
      <STMT,EXPR> 'new'        { MODE(EXPR); RET(NEW); }
      <STMT,EXPR> 'not'        { MODE(EXPR); RET(NOT); }
      <STMT,EXPR> 'return'     { MODE(EXPR); RET(RETURN); }
      <STMT,EXPR> 'try'        { MODE(EXPR); RET(TRY); }
      <STMT,EXPR> 'throw'      { MODE(EXPR); RET(THROW); }
      <STMT,EXPR> 'var'        { MODE(EXPR); RET(VAR); }
      <STMT,EXPR> 'while'      { MODE(EXPR); RET(WHILE); }

      <STMT,EXPR> '+'          { MODE(EXPR); RET(PLUS); }
      <STMT,EXPR> '-'          { MODE(EXPR); RET(MINUS); }

      <STMT,EXPR> NUM          { MODE(EXPR); RET(INT_LITERAL); }
      <STMT,EXPR> FLOAT        { MODE(EXPR); RET(FLOAT_LITERAL); }
      <STMT,EXPR> STRING_LITERAL
                               { MODE(EXPR); RET(STRING_LITERAL); }
      <STMT,EXPR> ["]          { PUSH_MODE(DSTRING); RET(OPEN_DQUOTE); }
      <STMT,EXPR> BQUOTE_LITERAL
                               { MODE(EXPR); RET(BQUOTE_LITERAL); }
      <STMT,EXPR> '$('         { PUSH_MODE(STMT); RET(START_SUB_CMD); }

      <STMT,EXPR> APPLIED_NAME { MODE(EXPR); RET(APPLIED_NAME); }
      <STMT,EXPR> SPECIAL_NAME { MODE(EXPR); RET(SPECIAL_NAME); }

      <STMT,EXPR> '('          { PUSH_MODE(STMT); RET(LP); }
      <STMT,EXPR> ')'          { POP_MODE(); RET(RP); }
      <STMT,EXPR> '['          { MODE(EXPR); RET(LB); }
      <STMT,EXPR> ']'          { MODE(EXPR); RET(RB); }
      <STMT,EXPR> '{'          { PUSH_MODE(STMT); RET(LBC); }
      <STMT,EXPR> '}'          { POP_MODE(); RET(RBC); }
      <STMT,EXPR> '<'          { MODE(EXPR); RET(LA); }
      <STMT,EXPR> '>'          { MODE(EXPR); RET(RA); }

      <STMT> CMD_START_CHAR CMD_CHAR*
                               { PUSH_MODE(CMD); RET(COMMAND); }

      <EXPR> ':'               { RET(COLON); }
      <EXPR> ','               { RET(COMMA); }

      <EXPR> '*'               { RET(MUL); }
      <EXPR> '/'               { RET(DIV); }
      <EXPR> '%'               { RET(MOD); }
      <EXPR> '<='              { RET(LE); }
      <EXPR> '>='              { RET(GE); }
      <EXPR> '=='              { RET(EQ); }
      <EXPR> '!='              { RET(NE); }
      <EXPR> '&'               { RET(AND); }
      <EXPR> '|'               { RET(OR); }
      <EXPR> '^'               { RET(XOR); }
      <EXPR> '&&'              { RET(COND_AND); }
      <EXPR> '||'              { RET(COND_OR); }
      <EXPR> '=~'              { RET(RE_MATCH); }
      <EXPR> '!~'              { RET(RE_UNMATCH); }

      <EXPR> '++'              { RET(INC); }
      <EXPR> '--'              { RET(DEC); }

      <EXPR> '='               { MODE(STMT); RET(ASSIGN); }
      <EXPR> '+='              { MODE(STMT); RET(ADD_ASSIGN); }
      <EXPR> '-='              { MODE(STMT); RET(SUB_ASSIGN); }
      <EXPR> '*='              { MODE(STMT); RET(MUL_ASSIGN); }
      <EXPR> '/='              { MODE(STMT); RET(DIV_ASSIGN); }
      <EXPR> '%='              { MODE(STMT); RET(MOD_ASSIGN); }

      <EXPR> 'as'              { RET(AS); }
      <EXPR> 'Func'            { RET(FUNC); }
      <EXPR> 'in'              { RET(IN); }
      <EXPR> 'is'              { RET(IS); }

      <EXPR> VAR_NAME          { RET(IDENTIFIER); }
      <EXPR> '.'               { RET(ACCESSOR); }

      <STMT,EXPR> LINE_END     { RET(LINE_END); }
      <STMT,EXPR> NEW_LINE     { INC_LINE_NUM(); RET(NEW_LINE); }

      <STMT,EXPR> COMMENT      { SKIP(); }
      <STMT,EXPR> [ \t]+       { SKIP(); }
      <STMT,EXPR> '\\' [\r\n]  { INC_LINE_NUM(); SKIP(); }

      <DSTRING> ["]            { POP_MODE(); RET(CLOSE_DQUOTE);}
      <DSTRING> ([^\r\n`$"\\] | '\\' [$btnfr"`\\])+
                               { POP_MODE(); RET(STR_ELEMENT);}
      <DSTRING> BQUOTE_LITERAL { RET(BQUOTE_LITERAL); }
      <DSTRING> INNER_NAME     { RET(APPLIED_NAME); }
      <DSTRING> INNER_SPECIAL_NAME
                               { RET(SPECIAL_NAME); }
      <DSTRING> '${'           { PUSH_MODE(EXPR); RET(START_INTERP); }
      <DSTRING> '$('           { PUSH_MODE(STMT); RET(START_SUB_CMD); }

      <CMD> CMD_CHAR+          { RET(CMD_ARG_PART); }
      <CMD> STRING_LITERAL     { RET(STRING_LITERAL); }
      <CMD> ["]                { PUSH_MODE(DSTRING); RET(OPEN_DQUOTE); }
      <CMD> BQUOTE_LITERAL     { RET(BQUOTE_LITERAL); }
      <CMD> INNER_NAME         { RET(APPLIED_NAME); }
      <CMD> INNER_SPECIAL_NAME { RET(SPECIAL_NAME); }
      <CMD> '${'               { PUSH_MODE(EXPR); RET(START_INTERP); }
      <CMD> '$('               { PUSH_MODE(STMT); RET(START_SUB_CMD); }
      <CMD> ')'                { POP_MODE(); POP_MODE(); RET(RP); }
      <CMD> [ \t]+             { RET(CMD_SEP); }
      <CMD> ('<' | '>' | '1>' | '1>>' | '>>' | '2>' | '2>>' | '>&' | '&>' | '&>>')
                               { RET(REDIR_OP); }
      <CMD> '2>&1'             { RET(REDIR_OP_NO_ARG); }
      <CMD> '|'                { POP_MODE(); MODE(STMT); RET(PIPE); }
      <CMD> '&'                { RET(BACKGROUND); }
      <CMD> '||'               { POP_MODE(); MODE(STMT); RET(OR_LIST); }
      <CMD> '&&'               { POP_MODE(); MODE(STMT); RET(AND_LIST); }
      <CMD> LINE_END           { POP_MODE(); MODE(STMT); RET(LINE_END); }
      <CMD> NEW_LINE           { POP_MODE(); MODE(STMT); RET(NEW_LINE); }
      <CMD> COMMENT            { SKIP(); }

      <STMT,EXPR,DSTRING,CMD> OTHER { RET(INVALID); }
    */

END:
    token.startPos = startPos;
    token.size = this->getPos() - startPos;
    return kind;
}

void Lexer::setLineNum(unsigned int lineNum) {
    this->lineNum = lineNum;
}

unsigned int Lexer::getLineNum() const {
    return this->lineNum;
}

std::string Lexer::toString(Token &token) {
    assert(token.startPos < this->getUsedSize() &&
            token.startPos + token.size <= this->getUsedSize());
    return std::string(this->buf[token.startPos], token.size);
}

int Lexer::toInt(Token &token) {
    return 0;   //FIXME:
}

<commit_msg>fix line number handling<commit_after>/*
 * Copyright (C) 2015 Nagisa Sekiguchi
 *
 * 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 <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <string>

#include <parser/Lexer.h>

Lexer::Lexer(unsigned int initSize, bool fixed) :
        fp(0),
        bufSize((fixed || initSize > DEFAULT_SIZE) ? initSize : DEFAULT_SIZE),
        buf(new unsigned char[this->bufSize]),
        cursor(this->buf), limit(this->buf), marker(0),
        lineNum(1), endOfFile(false), modeStack(1) {
    this->buf[0] = '\0';    // terminate null character.
    this->modeStack.push_back(yycSTMT);
}

Lexer::Lexer(unsigned int initSize, FILE *fp) :
        Lexer(initSize) {
    this->fp = fp;
}

Lexer::Lexer(FILE *fp) : Lexer(DEFAULT_SIZE, fp) {
}

Lexer::Lexer(const char *src) :
        Lexer(strlen(src) + 1, true) {
    memcpy(this->buf, src, this->bufSize);
    this->limit += this->bufSize - 1;
}

Lexer::Lexer(const Lexer &lexer) :
        Lexer(lexer.getUsedSize(), true) {
    memcpy(this->buf, lexer.buf, this->bufSize);
    this->limit += this->bufSize - 1;
}

Lexer::~Lexer() {
    delete[] this->buf;
    this->buf = 0;
}

void Lexer::expandBuf(unsigned int needSize) {
    unsigned int usedSize = this->getUsedSize();
    unsigned int size = usedSize + needSize;
    if(size > this->bufSize) {
        unsigned int newSize = this->bufSize;
        do {
            newSize *= 2;
        } while(newSize < size);
        unsigned int pos = this->getPos();
        unsigned int markerPos = this->marker - this->buf;
        unsigned char *newBuf = new unsigned char[newSize];
        memcpy(newBuf, this->buf, usedSize);
        delete[] this->buf;
        this->buf = newBuf;
        this->bufSize = newSize;
        this->cursor = this->buf + pos;
        this->limit = this->buf + usedSize - 1;
        this->marker = this->buf + markerPos;
    }
}

bool Lexer::fill(int n) {
    if(this->endOfFile && (this->limit - this->cursor) <= 0) {
        return false;
    }

    if(this->fp == 0) {
        if(this->limit - this->cursor <= 0) {
            this->endOfFile = true;
        }
        return true;
    }
    int needSize = n - (this->limit - this->cursor);
    assert(needSize > -1);
    this->expandBuf(needSize);
    int readSize = fread(this->limit, needSize, 1, this->fp);
    this->limit += readSize;
    *this->limit = '\0';
    if(readSize < needSize) {
        this->endOfFile = true;
    }
    return true;
}

unsigned int Lexer::getPos() const {
    return this->cursor - this->buf;
}

unsigned int Lexer::getBufSize() const {
    return this->bufSize;
}

unsigned int Lexer::getUsedSize() const {
    return this->limit - this->buf + 1;
}

// helper macro definition.
#define RET(k) do { kind = k; goto END; } while(0)

#define SKIP() goto INIT

#define ERROR() do { RET(INVALID); } while(0)

#define POP_MODE() \
    do {\
        if(this->modeStack.size() > 1) {\
            this->modeStack.pop_back();\
        } else {\
            ERROR();\
        }\
    } while(0)

#define PUSH_MODE(m) this->modeStack.push_back(yyc ## m)

#define MODE(m) \
    do {\
        if(this->modeStack.size() > 0) {\
            this->modeStack[this->modeStack.size() - 1] = yyc ## m;\
        } else {\
            ERROR();\
        }\
    } while(0)

#define INC_LINE_NUM() ++this->lineNum

#define FIND_NEW_LINE() \
    do {\
        unsigned int stopPos = this->getPos();\
        for(unsigned int i = startPos; i < stopPos; ++i) {\
            if(this->buf[i] == '\n') { ++this->lineNum; } \
        }\
    } while(0)

#define YYGETCONDITION() this->modeStack.back()

TokenKind Lexer::nextToken(Token &token) {
    /*!re2c
      re2c:define:YYGETCONDITION = YYGETCONDITION;
      re2c:define:YYCTYPE = "unsigned char";
      re2c:define:YYCURSOR = this->cursor;
      re2c:define:YYLIMIT = this->limit;
      re2c:define:YYMARKER = this->marker;
      re2c:define:YYFILL:naked = 1;
      re2c:define:YYFILL@len = #;
      re2c:define:YYFILL = "if(!this->fill(#)) { RET(EOS); }";
      re2c:yyfill:enable = 1;
      re2c:indent:top = 1;
      re2c:indent:string = "    ";

      NUM = '0' | [1-9] [0-9]*;
      DIGITS = [0-9]+;
      FLOAT_SUFFIX =  [eE] [+-]? NUM;
      FLOAT = NUM '.' DIGITS FLOAT_SUFFIX?;

      SQUOTE_CHAR = [^\r\n'\\] | '\\' [btnfr'\\];
      VAR_NAME = [a-zA-Z] [_0-9a-zA-Z]* | '_' [_0-9a-zA-Z]+;
      SPECIAL_NAMES = [@];

      STRING_LITERAL = ['] SQUOTE_CHAR* ['];
      BQUOTE_LITERAL = [`] ('\\' '`' | [^\n\r])+ [`];
      APPLIED_NAME = '$' VAR_NAME;
      SPECIAL_NAME = '$' SPECIAL_NAMES;

      INNER_NAME = APPLIED_NAME | '${' VAR_NAME '}';
      INNER_SPECIAL_NAME = SPECIAL_NAME | '${' SPECIAL_NAMES '}';

      CMD_START_CHAR = '\\' . | [^ \t\r\n;'"`|&<>(){}$#![\]0-9];
      CMD_CHAR       = '\\' . | [^ \t\r\n;'"`|&<>(){}$#![\]];

      LINE_END = ';';
      NEW_LINE = [\r\n];
      COMMENT = '#' [^\r\n]*;
      OTHER = .;
    */

INIT:
    unsigned int startPos = this->getPos();
    TokenKind kind = INVALID;
    /*!re2c
      <STMT,EXPR> 'assert'     { MODE(EXPR); RET(ASSERT); }
      <STMT,EXPR> 'catch'      { MODE(EXPR); RET(CATCH); }
      <STMT,EXPR> 'class'      { MODE(EXPR); RET(CLASS); }
      <STMT,EXPR> 'continue'   { MODE(EXPR); RET(CONTINUE); }
      <STMT,EXPR> 'do'         { MODE(EXPR); RET(DO); }
      <STMT,EXPR> 'else'       { MODE(EXPR); RET(ELSE); }
      <STMT,EXPR> 'extends'    { MODE(EXPR); RET(EXTENDS); }
      <STMT,EXPR> 'export-env' { MODE(EXPR); RET(EXPORT_ENV); }
      <STMT,EXPR> 'finally'    { MODE(EXPR); RET(FINALLY); }
      <STMT,EXPR> 'for'        { MODE(EXPR); RET(FOR); }
      <STMT,EXPR> 'function'   { MODE(EXPR); RET(FUNCTION); }
      <STMT,EXPR> 'if'         { MODE(EXPR); RET(IF); }
      <STMT,EXPR> 'import-env' { MODE(EXPR); RET(IMPORT_ENV); }
      <STMT,EXPR> 'let'        { MODE(EXPR); RET(LET); }
      <STMT,EXPR> 'new'        { MODE(EXPR); RET(NEW); }
      <STMT,EXPR> 'not'        { MODE(EXPR); RET(NOT); }
      <STMT,EXPR> 'return'     { MODE(EXPR); RET(RETURN); }
      <STMT,EXPR> 'try'        { MODE(EXPR); RET(TRY); }
      <STMT,EXPR> 'throw'      { MODE(EXPR); RET(THROW); }
      <STMT,EXPR> 'var'        { MODE(EXPR); RET(VAR); }
      <STMT,EXPR> 'while'      { MODE(EXPR); RET(WHILE); }

      <STMT,EXPR> '+'          { MODE(EXPR); RET(PLUS); }
      <STMT,EXPR> '-'          { MODE(EXPR); RET(MINUS); }

      <STMT,EXPR> NUM          { MODE(EXPR); RET(INT_LITERAL); }
      <STMT,EXPR> FLOAT        { MODE(EXPR); RET(FLOAT_LITERAL); }
      <STMT,EXPR> STRING_LITERAL
                               { MODE(EXPR); RET(STRING_LITERAL); }
      <STMT,EXPR> ["]          { PUSH_MODE(DSTRING); RET(OPEN_DQUOTE); }
      <STMT,EXPR> BQUOTE_LITERAL
                               { MODE(EXPR); RET(BQUOTE_LITERAL); }
      <STMT,EXPR> '$('         { PUSH_MODE(STMT); RET(START_SUB_CMD); }

      <STMT,EXPR> APPLIED_NAME { MODE(EXPR); RET(APPLIED_NAME); }
      <STMT,EXPR> SPECIAL_NAME { MODE(EXPR); RET(SPECIAL_NAME); }

      <STMT,EXPR> '('          { PUSH_MODE(STMT); RET(LP); }
      <STMT,EXPR> ')'          { POP_MODE(); RET(RP); }
      <STMT,EXPR> '['          { MODE(EXPR); RET(LB); }
      <STMT,EXPR> ']'          { MODE(EXPR); RET(RB); }
      <STMT,EXPR> '{'          { PUSH_MODE(STMT); RET(LBC); }
      <STMT,EXPR> '}'          { POP_MODE(); RET(RBC); }
      <STMT,EXPR> '<'          { MODE(EXPR); RET(LA); }
      <STMT,EXPR> '>'          { MODE(EXPR); RET(RA); }

      <STMT> CMD_START_CHAR CMD_CHAR*
                               { PUSH_MODE(CMD); FIND_NEW_LINE(); RET(COMMAND); }

      <EXPR> ':'               { RET(COLON); }
      <EXPR> ','               { RET(COMMA); }

      <EXPR> '*'               { RET(MUL); }
      <EXPR> '/'               { RET(DIV); }
      <EXPR> '%'               { RET(MOD); }
      <EXPR> '<='              { RET(LE); }
      <EXPR> '>='              { RET(GE); }
      <EXPR> '=='              { RET(EQ); }
      <EXPR> '!='              { RET(NE); }
      <EXPR> '&'               { RET(AND); }
      <EXPR> '|'               { RET(OR); }
      <EXPR> '^'               { RET(XOR); }
      <EXPR> '&&'              { RET(COND_AND); }
      <EXPR> '||'              { RET(COND_OR); }
      <EXPR> '=~'              { RET(RE_MATCH); }
      <EXPR> '!~'              { RET(RE_UNMATCH); }

      <EXPR> '++'              { RET(INC); }
      <EXPR> '--'              { RET(DEC); }

      <EXPR> '='               { MODE(STMT); RET(ASSIGN); }
      <EXPR> '+='              { MODE(STMT); RET(ADD_ASSIGN); }
      <EXPR> '-='              { MODE(STMT); RET(SUB_ASSIGN); }
      <EXPR> '*='              { MODE(STMT); RET(MUL_ASSIGN); }
      <EXPR> '/='              { MODE(STMT); RET(DIV_ASSIGN); }
      <EXPR> '%='              { MODE(STMT); RET(MOD_ASSIGN); }

      <EXPR> 'as'              { RET(AS); }
      <EXPR> 'Func'            { RET(FUNC); }
      <EXPR> 'in'              { RET(IN); }
      <EXPR> 'is'              { RET(IS); }

      <EXPR> VAR_NAME          { RET(IDENTIFIER); }
      <EXPR> '.'               { RET(ACCESSOR); }

      <STMT,EXPR> LINE_END     { RET(LINE_END); }
      <STMT,EXPR> NEW_LINE     { INC_LINE_NUM(); RET(NEW_LINE); }

      <STMT,EXPR> COMMENT      { SKIP(); }
      <STMT,EXPR> [ \t]+       { SKIP(); }
      <STMT,EXPR> '\\' [\r\n]  { INC_LINE_NUM(); SKIP(); }

      <DSTRING> ["]            { POP_MODE(); RET(CLOSE_DQUOTE);}
      <DSTRING> ([^\r\n`$"\\] | '\\' [$btnfr"`\\])+
                               { POP_MODE(); RET(STR_ELEMENT);}
      <DSTRING> BQUOTE_LITERAL { RET(BQUOTE_LITERAL); }
      <DSTRING> INNER_NAME     { RET(APPLIED_NAME); }
      <DSTRING> INNER_SPECIAL_NAME
                               { RET(SPECIAL_NAME); }
      <DSTRING> '${'           { PUSH_MODE(EXPR); RET(START_INTERP); }
      <DSTRING> '$('           { PUSH_MODE(STMT); RET(START_SUB_CMD); }

      <CMD> CMD_CHAR+          { FIND_NEW_LINE();  RET(CMD_ARG_PART); }
      <CMD> STRING_LITERAL     { RET(STRING_LITERAL); }
      <CMD> ["]                { PUSH_MODE(DSTRING); RET(OPEN_DQUOTE); }
      <CMD> BQUOTE_LITERAL     { RET(BQUOTE_LITERAL); }
      <CMD> INNER_NAME         { RET(APPLIED_NAME); }
      <CMD> INNER_SPECIAL_NAME { RET(SPECIAL_NAME); }
      <CMD> '${'               { PUSH_MODE(EXPR); RET(START_INTERP); }
      <CMD> '$('               { PUSH_MODE(STMT); RET(START_SUB_CMD); }
      <CMD> ')'                { POP_MODE(); POP_MODE(); RET(RP); }
      <CMD> [ \t]+             { RET(CMD_SEP); }
      <CMD> ('<' | '>' | '1>' | '1>>' | '>>' | '2>' | '2>>' | '>&' | '&>' | '&>>')
                               { RET(REDIR_OP); }
      <CMD> '2>&1'             { RET(REDIR_OP_NO_ARG); }
      <CMD> '|'                { POP_MODE(); MODE(STMT); RET(PIPE); }
      <CMD> '&'                { RET(BACKGROUND); }
      <CMD> '||'               { POP_MODE(); MODE(STMT); RET(OR_LIST); }
      <CMD> '&&'               { POP_MODE(); MODE(STMT); RET(AND_LIST); }
      <CMD> LINE_END           { POP_MODE(); MODE(STMT); RET(LINE_END); }
      <CMD> NEW_LINE           { POP_MODE(); MODE(STMT); RET(NEW_LINE); }
      <CMD> COMMENT            { SKIP(); }

      <STMT,EXPR,DSTRING,CMD> OTHER { RET(INVALID); }
    */

END:
    token.startPos = startPos;
    token.size = this->getPos() - startPos;
    return kind;
}

void Lexer::setLineNum(unsigned int lineNum) {
    this->lineNum = lineNum;
}

unsigned int Lexer::getLineNum() const {
    return this->lineNum;
}

std::string Lexer::toString(Token &token) {
    assert(token.startPos < this->getUsedSize() &&
            token.startPos + token.size <= this->getUsedSize());
    return std::string(this->buf[token.startPos], token.size);
}

int Lexer::toInt(Token &token) {
    return 0;   //FIXME:
}

<|endoftext|>


<commit_before>#include "MainWindow.h"
#include "ui_MainWindow.h"

#include "CuteNodeWidget.h"
#include "NodeScene.h"
#include "NodeView.h"

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
    , _scene{std::make_unique<NodeScene>(QRectF(0.0, 0.0, 3000.0, 3000.0))}
    , _ui{std::make_unique<Ui::MainWindow>()}
{
    _ui->setupUi(this);

    _scene->addItem(new CuteNodeWidget);

    _ui->nodeView->rect();
    _ui->nodeView->setScene(_scene.get());
    _ui->nodeView->centerOn(0.0, 0.0);
    _ui->nodeView->setDragMode(QGraphicsView::RubberBandDrag);
    _ui->nodeView->setRenderHints(QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing);
    _ui->nodeView->show();

    connect(_ui->actionToggleSnap, &QAction::triggered, _scene.get(), &NodeScene::ToggleGridSnapping);
}

MainWindow::~MainWindow()
{
}
<commit_msg>Added a few more nodes<commit_after>#include "MainWindow.h"
#include "ui_MainWindow.h"

#include "CuteNodeWidget.h"
#include "NodeScene.h"
#include "NodeView.h"

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
    , _scene{std::make_unique<NodeScene>(QRectF(0.0, 0.0, 3000.0, 3000.0))}
    , _ui{std::make_unique<Ui::MainWindow>()}
{
    _ui->setupUi(this);

    for (int i=0; i<5; ++i)
    {
        CuteNodeWidget* node = new CuteNodeWidget;
        node->setPos(i*300.0, 300.0);
        _scene->addItem(node);
    }

    _ui->nodeView->setScene(_scene.get());
    _ui->nodeView->centerOn(0.0, 0.0);
    _ui->nodeView->setDragMode(QGraphicsView::RubberBandDrag);
    _ui->nodeView->setRenderHints(QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing);
    _ui->nodeView->show();

    connect(_ui->actionToggleSnap, &QAction::triggered, _scene.get(), &NodeScene::ToggleGridSnapping);
}

MainWindow::~MainWindow()
{
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2014, 2015, 2016, 2017, 2018 CNRS
// Authors: Florent Lamiraux, Joseph Mirabel, Diane Bury
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core 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 Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#include <hpp/core/continuous-validation.hh>

#include <limits>
#include <pinocchio/multibody/geometry.hpp>
#include <hpp/util/debug.hh>
#include <hpp/core/collision-path-validation-report.hh>
#include <hpp/core/straight-path.hh>
#include <hpp/core/path-vector.hh>
#include <hpp/core/continuous-validation/initializer.hh>
#include <hpp/core/continuous-validation/solid-solid-collision.hh>

#include <iterator>
namespace hpp {
  namespace core {
    using continuousValidation::BodyPairCollisions_t;
    using continuousValidation::SolidSolidCollision;

    /// Validate interval centered on a path parameter
    /// \param bodyPairCollisions a reference to the pair with smallest interval.
    /// \param config Configuration at abscissa tmin on the path.
    /// \param t parameter value in the path interval of definition
    /// \retval interval interval validated for all validation elements
    /// \retval report reason why the interval is not valid,
    /// \return true if the configuration is collision free for this parameter
    ///         value, false otherwise.
    bool ContinuousValidation::validateConfiguration(BodyPairCollisions_t& bodyPairCollisions,
        const Configuration_t &config, const value_type &t,
        interval_t &interval, PathValidationReportPtr_t &report)
    {
      interval.first = -std::numeric_limits <value_type>::infinity ();
      interval.second = std::numeric_limits <value_type>::infinity ();

      robot_->currentConfiguration (config);
      robot_->computeFramesForwardKinematics ();
      robot_->updateGeometryPlacements ();
      hpp::pinocchio::DeviceSync robot (robot_);
      robot.currentConfiguration (config);
      robot.computeForwardKinematics();
      robot.updateGeometryPlacements();
      BodyPairCollisions_t::iterator smallestInterval = bodyPairCollisions.begin();
      if (!validateIntervals<BodyPairCollisions_t, CollisionValidationReportPtr_t>
            (bodyPairCollisions, t, interval, report,
             smallestInterval, robot.d()))
        return false;
      // Put the smallest interval first so that, at next iteration,
      // collision pairs with large interval are not computed.
      if (bodyPairCollisions.size() > 1 && smallestInterval != bodyPairCollisions.begin())
        std::iter_swap (bodyPairCollisions.begin(), smallestInterval);
      return true;
    }

    bool ContinuousValidation::validate(const PathPtr_t &path, bool reverse, PathPtr_t &validPart,
                                              PathValidationReportPtr_t &report)
    {
      if (PathVectorPtr_t pv = HPP_DYNAMIC_PTR_CAST(PathVector, path))
      {
        PathVectorPtr_t validPathVector = PathVector::create(path->outputSize(), path->outputDerivativeSize());
        validPart = validPathVector;
        PathPtr_t localValidPart;
        if (reverse)
        {
          value_type param = path->length();
          std::deque<PathPtr_t> paths;
          for (std::size_t i = pv->numberPaths() + 1; i != 0; --i)
          {
            PathPtr_t localPath(pv->pathAtRank(i - 1));
            if (validate(localPath, reverse, localValidPart, report))
            {
              paths.push_front(localPath->copy());
              param -= localPath->length();
            }
            else
            {
              report->parameter += param - localPath->length();
              paths.push_front(localValidPart->copy());
              for (std::deque<PathPtr_t>::const_iterator it = paths.begin();
                  it != paths.end(); ++it)
              {
                validPathVector->appendPath(*it);
              }
              return false;
            }
          }
          return true;
        }
        else
        {
          value_type param = 0;
          for (std::size_t i = 0; i < pv->numberPaths(); ++i)
          {
            PathPtr_t localPath(pv->pathAtRank(i));
            if (validate(localPath, reverse, localValidPart, report))
            {
              validPathVector->appendPath(localPath->copy());
              param += localPath->length();
            }
            else
            {
              report->parameter += param;
              validPathVector->appendPath(localValidPart->copy());
              return false;
            }
          }
          return true;
        }
      }
      BodyPairCollisions_t* bpc;
      if (!bodyPairCollisionPool_.available()) {
        // Add an element
        bpc = new BodyPairCollisions_t(bodyPairCollisions_.size());
        for (std::size_t i = 0; i < bpc->size(); ++i)
          (*bpc)[i] = bodyPairCollisions_[i]->copy();
        bodyPairCollisionPool_.push_back (bpc);
      }
      bpc = bodyPairCollisionPool_.acquire();
      bool ret = validateStraightPath(*bpc, path, reverse, validPart, report);
      bodyPairCollisionPool_.release (bpc);
      return ret;
    }

    void ContinuousValidation::addObstacle(const CollisionObjectConstPtr_t &object)
    {
      for (size_type idx = 0; idx < robot_->nbJoints(); ++idx) {
        JointPtr_t joint = robot_->jointAt (idx);
      BodyPtr_t body = joint->linkedBody ();
        if (body)
        {
          ConstObjectStdVector_t objects;
          objects.push_back(object);
          bodyPairCollisions_.push_back(SolidSolidCollision::create (joint, objects, tolerance_));
          bodyPairCollisionPool_.clear();
        }
      }
    }

    void ContinuousValidation::setPath(BodyPairCollisions_t& bodyPairCollisions,
        const PathPtr_t &path, bool reverse)
    {
      for (BodyPairCollisions_t::iterator itPair = bodyPairCollisions.begin ();
      itPair != bodyPairCollisions.end (); ++itPair) {
        (*itPair)->path (path, reverse);
      }
    }

    void ContinuousValidation::removeObstacleFromJoint(const JointPtr_t &joint, const CollisionObjectConstPtr_t &obstacle)
    {
      assert (joint);
      bool removed = false;
      for (BodyPairCollisions_t::iterator itPair = bodyPairCollisions_.begin();
          itPair != bodyPairCollisions_.end(); ++itPair)
      {
        // If jointA == joint and jointB is the root joint.
        if ((*itPair)->indexJointA() == (size_type)joint->index()
            && (*itPair)->indexJointB() == 0)
        {
          if ((*itPair)->removeObjectTo_b(obstacle))
          {
            removed = true;
            if ((*itPair)->pairs().empty())
            {
              bodyPairCollisions_.erase(itPair);
              bodyPairCollisionPool_.clear();
            }
          }
        }
      }
      if (!removed)
      {
        std::ostringstream oss;
        oss << "ContinuousValidation::removeObstacleFromJoint: obstacle \""
            << obstacle->name() << "\" is not registered as obstacle for joint \"" << joint->name()
            << "\".";
        throw std::runtime_error(oss.str());
      }
    }

    void ContinuousValidation::filterCollisionPairs(const RelativeMotion::matrix_type &relMotion)
    {
      // Loop over collision pairs and remove disabled ones.
      size_type ia, ib;
      for (BodyPairCollisions_t::iterator _colPair = bodyPairCollisions_.begin();
          _colPair != bodyPairCollisions_.end();)
      {
        ia = (*_colPair)->indexJointA ();
        ib = (*_colPair)->indexJointB ();
        if (ia < 0 || ib < 0) {
          ++_colPair;
          continue;
        }
        switch (relMotion(ia, ib))
        {
        case RelativeMotion::Parameterized:
          hppDout(info, "Parameterized collision pairs treated as Constrained");
        case RelativeMotion::Constrained:
          hppDout(info, "Disabling collision pair " << **_colPair);
          disabledBodyPairCollisions_.push_back(*_colPair);
          _colPair = bodyPairCollisions_.erase(_colPair);
          break;
        case RelativeMotion::Unconstrained:
          ++_colPair;
          break;
        default:
          hppDout(warning, "RelativeMotionType not understood");
          ++_colPair;
          break;
        }
      }
      bodyPairCollisionPool_.clear();
    }

    void ContinuousValidation::init (ContinuousValidationWkPtr_t weak)
    {
      weak_ = weak;
      initializer_->initContinuousValidation(weak_);
    }

    void ContinuousValidation::changeInitializer (continuousValidation::InitializerPtr_t initializer)
    {
      initializer_ = initializer;
      initializer_->initContinuousValidation(weak_);
      initializer_->reset();
      initializer_->initialize();
    }

    ContinuousValidation::~ContinuousValidation()
    {
    }

    ContinuousValidation::ContinuousValidation(const DevicePtr_t &robot, const value_type &tolerance):
      robot_(robot), tolerance_(tolerance), bodyPairCollisions_(),
      weak_()
    {
      initializer_ = continuousValidation::Initializer::create();
      if (tolerance < 0) {
        throw std::runtime_error ("tolerance should be non-negative.");
      }
    }
  } // namespace core
} // namespace hpp
<commit_msg>Reverse harmful change in ContinuousValidation<commit_after>//
// Copyright (c) 2014, 2015, 2016, 2017, 2018 CNRS
// Authors: Florent Lamiraux, Joseph Mirabel, Diane Bury
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core 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 Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#include <hpp/core/continuous-validation.hh>

#include <limits>
#include <pinocchio/multibody/geometry.hpp>
#include <hpp/util/debug.hh>
#include <hpp/core/collision-path-validation-report.hh>
#include <hpp/core/straight-path.hh>
#include <hpp/core/path-vector.hh>
#include <hpp/core/continuous-validation/initializer.hh>
#include <hpp/core/continuous-validation/solid-solid-collision.hh>

#include <iterator>
namespace hpp {
  namespace core {
    using continuousValidation::BodyPairCollisions_t;
    using continuousValidation::SolidSolidCollision;

    /// Validate interval centered on a path parameter
    /// \param bodyPairCollisions a reference to the pair with smallest interval.
    /// \param config Configuration at abscissa tmin on the path.
    /// \param t parameter value in the path interval of definition
    /// \retval interval interval validated for all validation elements
    /// \retval report reason why the interval is not valid,
    /// \return true if the configuration is collision free for this parameter
    ///         value, false otherwise.
    bool ContinuousValidation::validateConfiguration(BodyPairCollisions_t& bodyPairCollisions,
        const Configuration_t &config, const value_type &t,
        interval_t &interval, PathValidationReportPtr_t &report)
    {
      interval.first = -std::numeric_limits <value_type>::infinity ();
      interval.second = std::numeric_limits <value_type>::infinity ();
      hpp::pinocchio::DeviceSync robot (robot_);
      robot.currentConfiguration (config);
      robot.computeForwardKinematics();
      robot.updateGeometryPlacements();
      BodyPairCollisions_t::iterator smallestInterval = bodyPairCollisions.begin();
      if (!validateIntervals<BodyPairCollisions_t, CollisionValidationReportPtr_t>
            (bodyPairCollisions, t, interval, report,
             smallestInterval, robot.d()))
        return false;
      // Put the smallest interval first so that, at next iteration,
      // collision pairs with large interval are not computed.
      if (bodyPairCollisions.size() > 1 && smallestInterval != bodyPairCollisions.begin())
        std::iter_swap (bodyPairCollisions.begin(), smallestInterval);
      return true;
    }

    bool ContinuousValidation::validate(const PathPtr_t &path, bool reverse, PathPtr_t &validPart,
                                              PathValidationReportPtr_t &report)
    {
      if (PathVectorPtr_t pv = HPP_DYNAMIC_PTR_CAST(PathVector, path))
      {
        PathVectorPtr_t validPathVector = PathVector::create(path->outputSize(), path->outputDerivativeSize());
        validPart = validPathVector;
        PathPtr_t localValidPart;
        if (reverse)
        {
          value_type param = path->length();
          std::deque<PathPtr_t> paths;
          for (std::size_t i = pv->numberPaths() + 1; i != 0; --i)
          {
            PathPtr_t localPath(pv->pathAtRank(i - 1));
            if (validate(localPath, reverse, localValidPart, report))
            {
              paths.push_front(localPath->copy());
              param -= localPath->length();
            }
            else
            {
              report->parameter += param - localPath->length();
              paths.push_front(localValidPart->copy());
              for (std::deque<PathPtr_t>::const_iterator it = paths.begin();
                  it != paths.end(); ++it)
              {
                validPathVector->appendPath(*it);
              }
              return false;
            }
          }
          return true;
        }
        else
        {
          value_type param = 0;
          for (std::size_t i = 0; i < pv->numberPaths(); ++i)
          {
            PathPtr_t localPath(pv->pathAtRank(i));
            if (validate(localPath, reverse, localValidPart, report))
            {
              validPathVector->appendPath(localPath->copy());
              param += localPath->length();
            }
            else
            {
              report->parameter += param;
              validPathVector->appendPath(localValidPart->copy());
              return false;
            }
          }
          return true;
        }
      }
      BodyPairCollisions_t* bpc;
      if (!bodyPairCollisionPool_.available()) {
        // Add an element
        bpc = new BodyPairCollisions_t(bodyPairCollisions_.size());
        for (std::size_t i = 0; i < bpc->size(); ++i)
          (*bpc)[i] = bodyPairCollisions_[i]->copy();
        bodyPairCollisionPool_.push_back (bpc);
      }
      bpc = bodyPairCollisionPool_.acquire();
      bool ret = validateStraightPath(*bpc, path, reverse, validPart, report);
      bodyPairCollisionPool_.release (bpc);
      return ret;
    }

    void ContinuousValidation::addObstacle(const CollisionObjectConstPtr_t &object)
    {
      for (size_type idx = 0; idx < robot_->nbJoints(); ++idx) {
        JointPtr_t joint = robot_->jointAt (idx);
      BodyPtr_t body = joint->linkedBody ();
        if (body)
        {
          ConstObjectStdVector_t objects;
          objects.push_back(object);
          bodyPairCollisions_.push_back(SolidSolidCollision::create (joint, objects, tolerance_));
          bodyPairCollisionPool_.clear();
        }
      }
    }

    void ContinuousValidation::setPath(BodyPairCollisions_t& bodyPairCollisions,
        const PathPtr_t &path, bool reverse)
    {
      for (BodyPairCollisions_t::iterator itPair = bodyPairCollisions.begin ();
      itPair != bodyPairCollisions.end (); ++itPair) {
        (*itPair)->path (path, reverse);
      }
    }

    void ContinuousValidation::removeObstacleFromJoint(const JointPtr_t &joint, const CollisionObjectConstPtr_t &obstacle)
    {
      assert (joint);
      bool removed = false;
      for (BodyPairCollisions_t::iterator itPair = bodyPairCollisions_.begin();
          itPair != bodyPairCollisions_.end(); ++itPair)
      {
        // If jointA == joint and jointB is the root joint.
        if ((*itPair)->indexJointA() == (size_type)joint->index()
            && (*itPair)->indexJointB() == 0)
        {
          if ((*itPair)->removeObjectTo_b(obstacle))
          {
            removed = true;
            if ((*itPair)->pairs().empty())
            {
              bodyPairCollisions_.erase(itPair);
              bodyPairCollisionPool_.clear();
            }
          }
        }
      }
      if (!removed)
      {
        std::ostringstream oss;
        oss << "ContinuousValidation::removeObstacleFromJoint: obstacle \""
            << obstacle->name() << "\" is not registered as obstacle for joint \"" << joint->name()
            << "\".";
        throw std::runtime_error(oss.str());
      }
    }

    void ContinuousValidation::filterCollisionPairs(const RelativeMotion::matrix_type &relMotion)
    {
      // Loop over collision pairs and remove disabled ones.
      size_type ia, ib;
      for (BodyPairCollisions_t::iterator _colPair = bodyPairCollisions_.begin();
          _colPair != bodyPairCollisions_.end();)
      {
        ia = (*_colPair)->indexJointA ();
        ib = (*_colPair)->indexJointB ();
        if (ia < 0 || ib < 0) {
          ++_colPair;
          continue;
        }
        switch (relMotion(ia, ib))
        {
        case RelativeMotion::Parameterized:
          hppDout(info, "Parameterized collision pairs treated as Constrained");
        case RelativeMotion::Constrained:
          hppDout(info, "Disabling collision pair " << **_colPair);
          disabledBodyPairCollisions_.push_back(*_colPair);
          _colPair = bodyPairCollisions_.erase(_colPair);
          break;
        case RelativeMotion::Unconstrained:
          ++_colPair;
          break;
        default:
          hppDout(warning, "RelativeMotionType not understood");
          ++_colPair;
          break;
        }
      }
      bodyPairCollisionPool_.clear();
    }

    void ContinuousValidation::init (ContinuousValidationWkPtr_t weak)
    {
      weak_ = weak;
      initializer_->initContinuousValidation(weak_);
    }

    void ContinuousValidation::changeInitializer (continuousValidation::InitializerPtr_t initializer)
    {
      initializer_ = initializer;
      initializer_->initContinuousValidation(weak_);
      initializer_->reset();
      initializer_->initialize();
    }

    ContinuousValidation::~ContinuousValidation()
    {
    }

    ContinuousValidation::ContinuousValidation(const DevicePtr_t &robot, const value_type &tolerance):
      robot_(robot), tolerance_(tolerance), bodyPairCollisions_(),
      weak_()
    {
      initializer_ = continuousValidation::Initializer::create();
      if (tolerance < 0) {
        throw std::runtime_error ("tolerance should be non-negative.");
      }
    }
  } // namespace core
} // namespace hpp
<|endoftext|>


<commit_before>/// \file dtscfix.cpp
/// Contains the code that will attempt to merge 2 files into a single DTSC file.

#include <string>
#include <vector>
#include <mist/config.h>
#include <mist/dtsc.h>

namespace Converters {
  int DTSCMerge(int argc, char ** argv){
    Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
    conf.addOption("output", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"Filename of the output file.\"}"));
    conf.addOption("input", JSON::fromString("{\"arg_num\":2, \"arg\":\"string\", \"help\":\"Filename of the first input file.\"}"));
    conf.addOption("[additional_inputs ...]", JSON::fromString("{\"arg_num\":3, \"arg\":\"string\", \"help\":\"Filenames of any number of aditional inputs.\"}"));
    conf.parseArgs(argc, argv);

    DTSC::File outFile("/dev/null",true);
    JSON::Value meta;
    std::map<std::string,std::map<int, int> > trackMapping;
    int nextTrackID = 1;

    bool fullSort = true;
    std::map<std::string, DTSC::File> inFiles;
    std::string tmpFileName;
    for (int i = 2; i < argc; i++){
      tmpFileName = argv[i];
      if (tmpFileName == std::string(argv[1])){
        fullSort = false;
      }else{
        inFiles.insert(std::pair<std::string, DTSC::File>(tmpFileName, DTSC::File(tmpFileName)));
      }
    }
    if (fullSort){
      outFile = DTSC::File(argv[1], true);
    }else{
      outFile = DTSC::File(argv[1]);
      meta = outFile.getMeta();
    }
    JSON::Value newMeta = meta;

    for (std::map<std::string,DTSC::File>::iterator it = inFiles.begin(); it != inFiles.end(); it++){
      JSON::Value tmpMeta = it->second.getMeta();
      //for (JSON::ObjIter oIt =
    }

    return 0;
  }
}

int main(int argc, char ** argv){
  return Converters::DTSCMerge(argc, argv);
}
<commit_msg>Finished DTSCMerge, initial version.<commit_after>/// \file dtscmerge.cpp
/// Contains the code that will attempt to merge multiple files into a single DTSC file.

#include <string>
#include <vector>
#include <mist/config.h>
#include <mist/dtsc.h>

namespace Converters {
  int getNextFree( std::map<std::string,std::map<int,int> > mapping ){
    int result = 1;
    std::map<std::string,std::map<int,int> >::iterator mapIt;
    std::map<int,int>::iterator subIt;
    if (mapping.size()){
      for (mapIt = mapping.begin(); mapIt != mapping.end(); mapIt++){
        if (mapIt->second.size()){
          for (subIt = mapIt->second.begin(); subIt != mapIt->second.end(); subIt++){
            if (subIt->second >= result){
              result = subIt->second + 1;
            }
          }
        }
      }
    }
    return result;
  }

  struct keyframeInfo{
    std::string fileName;
    int trackID;
    int keyTime;
    int keyBPos;
    int keyNum;
    int keyLen;
    int endBPos;
  };//keyframeInfo struct

  int DTSCMerge(int argc, char ** argv){
    Util::Config conf = Util::Config(argv[0], PACKAGE_VERSION);
    conf.addOption("output", JSON::fromString("{\"arg_num\":1, \"arg\":\"string\", \"help\":\"Filename of the output file.\"}"));
    conf.addOption("input", JSON::fromString("{\"arg_num\":2, \"arg\":\"string\", \"help\":\"Filename of the first input file.\"}"));
    conf.addOption("[additional_inputs ...]", JSON::fromString("{\"arg_num\":3, \"default\":\"\", \"arg\":\"string\", \"help\":\"Filenames of any number of aditional inputs.\"}"));
    conf.parseArgs(argc, argv);

    DTSC::File outFile;
    JSON::Value meta;
    JSON::Value newMeta;
    std::map<std::string,std::map<int, int> > trackMapping;

    bool fullSort = true;
    std::map<std::string, DTSC::File> inFiles;
    std::string outFileName = argv[1];
    std::string tmpFileName;
    for (int i = 2; i < argc; i++){
      tmpFileName = argv[i];
      if (tmpFileName == outFileName){
        fullSort = false;
      }else{
        inFiles.insert(std::pair<std::string,DTSC::File>(tmpFileName,DTSC::File(tmpFileName)));
      }
    }

    if (fullSort){
      outFile = DTSC::File(outFileName, true);
    }else{
      outFile = DTSC::File(outFileName);
      meta = outFile.getMeta();
      newMeta = meta;
      if (meta.isMember("tracks") && meta["tracks"].size() > 0){
        for (JSON::ObjIter trackIt = meta["tracks"].ObjBegin(); trackIt != meta["tracks"].ObjEnd(); trackIt++){
          trackMapping[argv[1]].insert(std::pair<int,int>(trackIt->second["trackid"].asInt(),getNextFree(trackMapping)));
          newMeta["tracks"][trackIt->first]["trackid"] = trackMapping[argv[1]][trackIt->second["trackid"].asInt()];
        }
      }
    }

    std::multimap<int,keyframeInfo> allSorted;

    for (std::map<std::string,DTSC::File>::iterator it = inFiles.begin(); it != inFiles.end(); it++){
      JSON::Value tmpMeta = it->second.getMeta();
      if (tmpMeta.isMember("tracks") && tmpMeta["tracks"].size() > 0){
        for (JSON::ObjIter trackIt = tmpMeta["tracks"].ObjBegin(); trackIt != tmpMeta["tracks"].ObjEnd(); trackIt++){
          long long int oldID = trackIt->second["trackid"].asInt();
          long long int mappedID = getNextFree(trackMapping);
          trackMapping[it->first].insert(std::pair<int,int>(oldID,mappedID));
          trackIt->second["trackid"] = mappedID;
          for (int i = 0; i < trackIt->second["keytime"].size(); i++){
            ///\todo Update to new struct.
            keyframeInfo tmpInfo;
            tmpInfo.fileName = it->first;
            tmpInfo.trackID = oldID;
            tmpInfo.keyTime = trackIt->second["keytime"][i].asInt();
            tmpInfo.keyBPos = trackIt->second["keybpos"][i].asInt();
            tmpInfo.keyNum = trackIt->second["keynum"][i].asInt();
            tmpInfo.keyLen = trackIt->second["keylen"][i].asInt();
            if ( i < trackIt->second["keytime"].size() - 1 ){
              tmpInfo.endBPos = trackIt->second["keybpos"][i + 1].asInt();
            }else{
              tmpInfo.endBPos = it->second.getBytePosEOF();
            }
            allSorted.insert(std::pair<int,keyframeInfo>(trackIt->second["keytime"][i].asInt(),tmpInfo));
          }
          trackIt->second.removeMember("keytime");
          trackIt->second.removeMember("keybpos");
          trackIt->second.removeMember("keynum");
          trackIt->second.removeMember("keylen");
          trackIt->second.removeMember("frags");
          newMeta["tracks"][JSON::Value(mappedID).asString()] = trackIt->second;
        }
      }
    }

    if (fullSort){
      meta.null();
      meta["moreheader"] = 0ll;
      std::string tmpWrite = meta.toPacked();
      outFile.writeHeader(tmpWrite,true);
    }

    for (std::multimap<int,keyframeInfo>::iterator sortIt = allSorted.begin(); sortIt != allSorted.end(); sortIt++){
      inFiles[sortIt->second.fileName].seek_bpos(sortIt->second.keyBPos);
      while (inFiles[sortIt->second.fileName].getBytePos() < sortIt->second.endBPos){
        JSON::Value translate = inFiles[sortIt->second.fileName].getJSON();
        if (translate["trackid"].asInt() == sortIt->second.trackID){
          translate["trackid"] = trackMapping[sortIt->second.fileName][translate["trackid"].asInt()];
          outFile.writePacket(translate);
        }
        inFiles[sortIt->second.fileName].seekNext();
      }
    }

    fprintf(stderr, "%s\n", newMeta.toPrettyString().c_str());
    fprintf(stderr, "Oldheader (%d):\n%s\n", meta.toPacked().size(), meta.toPrettyString().c_str());
    std::string writeMeta = newMeta.toPacked();
    meta["moreheader"] = outFile.addHeader(writeMeta);
    fprintf(stderr, "Newheader (%d):\n%s\n", meta.toPacked().size(), meta.toPrettyString().c_str());
    writeMeta = meta.toPacked();
    outFile.writeHeader(writeMeta);

    return 0;
  }
}

int main(int argc, char ** argv){
  return Converters::DTSCMerge(argc, argv);
}
<|endoftext|>


<commit_before>#include "I2C.h"
#include <mutex>

// The pigpiod_if header file doesn't protect itself when included from
// C++, so force it to be treated as 'C' here.
extern "C" {
#include "pigpiod_if.h"
}

#include <iostream>
#include <sstream>
#include "string.h"

#define SDA_PIN 5
#define SDL_PIN 6

namespace PiWars
{

std::once_flag initPIGPIODFlag;

I2C::I2C(uint8_t i2cAddress) : _i2cAddress(i2cAddress) {
  // We need to initialise pigpiod once, regardless of how many
  // i2c connections we establish
  std::call_once(initPIGPIODFlag, initPIGPIOD);
}

I2C::~I2C() {
}

bool I2C::exists() {
  return writeByte(0x00);
}

void I2C::initPIGPIOD() {
  if(0 != pigpio_start(NULL, NULL)) {
    std::cerr << "Failed to connect to pigpiod, is it running?" << std::endl;
    exit(-1);
  }

  // Create a 'bit bang' variant
  if(0 != bb_i2c_open(SDA_PIN, SDL_PIN, 100000)) {
    std::cerr << "Failed to open bit bang port" << std::endl;
    exit(-1);
  }

  // We want to stop the pigpio connection when the program exits
  std::atexit(finalizePIGPIOD);
}

void I2C::finalizePIGPIOD() {
std::cerr << "Finalize PIGPIOS" << std::endl;

  bb_i2c_close(SDA_PIN);
  pigpio_stop();
}

I2CInternal::I2CInternal(uint8_t i2cAddress) : I2C(i2cAddress), _i2cHandle(-1) {
  // Establish a handle to talk to the i2c device
  _i2cHandle = i2c_open(1, address(), 0);
}

I2CInternal::~I2CInternal() {
  i2c_close(_i2cHandle);
}

bool I2CInternal::writeBytes(const char *bytes, size_t length) {
  bool result = true;

  if(i2c_write_device(_i2cHandle, (char *)bytes, length) < 0 ) {
    std::cerr << "Failed to send message!" << std::endl;
    result = false;
  }

  return result;
}

size_t I2CInternal::readBytes(char *buffer, size_t length) {
  int read;

  read = i2c_read_device(_i2cHandle, buffer, length);

  // Did we fail?
  if(read < 0) {
    // Set to 0 for now
    read = 0;
  }

  return read;
}

bool I2CInternal::writeByte(const uint8_t byte) {
  if(i2c_write_byte(_i2cHandle, byte) >= 0) {
    return true;
  }

  return false;
}

bool I2CInternal::readByte(uint8_t &byte) {
  int read;

  read = i2c_read_byte(_i2cHandle);
  if(read >= 0) {
    byte = (uint8_t)read;
    return true;
  }

  return false;
}

I2CExternal::I2CExternal(uint8_t i2cAddress) : I2C(i2cAddress) {
}

I2CExternal::~I2CExternal() {
}

bool I2CExternal::writeByte(const uint8_t byte) {
  bool success = false;
  char command[] = { 0x04, address(), 0x02, 0x07, 0x01, byte, 0x03, 0x00};

  if(0 == bb_i2c_zip(SDA_PIN, command, sizeof(command), NULL, 0)) {
    success = true;
  }

  return success;
}

bool I2CExternal::readByte(uint8_t &byte) {
  bool read = false;

  // Set Address, address, Start, Read, 1 byte, Stop, End
  char command[] = { 0x04, address(), 0x02, 0x06, 0x01, 0x03, 0x00};

  if(1 == bb_i2c_zip(SDA_PIN, command, sizeof(command), (char *)&byte, 1)) {
    read = true;
  }

  return read;
}

bool I2CExternal::writeBytes(const char *bytes, size_t length) {
  bool result = true;

/*  if(i2c_write_device(_i2cHandle, (char *)bytes, length) < 0 ) {
    std::cerr << "Failed to send message!" << std::endl;
    result = false;
  }
  */
  return result;
}

size_t I2CExternal::readBytes(char *buffer, size_t length) {
  int read;

  //read = i2c_read_device(_i2cHandle, buffer, length);

  // Did we fail?
  if(read < 0) {
    // Set to 0 for now
    read = 0;
  }

  return read;
}

}

<commit_msg>Implemented the 'readBytes' and 'writeBytes' for the external I2C<commit_after>#include "I2C.h"
#include <mutex>

// The pigpiod_if header file doesn't protect itself when included from
// C++, so force it to be treated as 'C' here.
extern "C" {
#include "pigpiod_if.h"
}

#include <iostream>
#include <sstream>
#include "string.h"

#define SDA_PIN 5
#define SDL_PIN 6

namespace PiWars
{

std::once_flag initPIGPIODFlag;

I2C::I2C(uint8_t i2cAddress) : _i2cAddress(i2cAddress) {
  // We need to initialise pigpiod once, regardless of how many
  // i2c connections we establish
  std::call_once(initPIGPIODFlag, initPIGPIOD);
}

I2C::~I2C() {
}

bool I2C::exists() {
  return writeByte(0x00);
}

void I2C::initPIGPIOD() {
  if(0 != pigpio_start(NULL, NULL)) {
    std::cerr << "Failed to connect to pigpiod, is it running?" << std::endl;
    exit(-1);
  }

  // Create a 'bit bang' variant
  if(0 != bb_i2c_open(SDA_PIN, SDL_PIN, 100000)) {
    std::cerr << "Failed to open bit bang port" << std::endl;
    exit(-1);
  }

  // We want to stop the pigpio connection when the program exits
  std::atexit(finalizePIGPIOD);
}

void I2C::finalizePIGPIOD() {
std::cerr << "Finalize PIGPIOS" << std::endl;

  bb_i2c_close(SDA_PIN);
  pigpio_stop();
}

I2CInternal::I2CInternal(uint8_t i2cAddress) : I2C(i2cAddress), _i2cHandle(-1) {
  // Establish a handle to talk to the i2c device
  _i2cHandle = i2c_open(1, address(), 0);
}

I2CInternal::~I2CInternal() {
  i2c_close(_i2cHandle);
}

bool I2CInternal::writeBytes(const char *bytes, size_t length) {
  bool result = true;

  if(i2c_write_device(_i2cHandle, (char *)bytes, length) < 0 ) {
    std::cerr << "Failed to send message!" << std::endl;
    result = false;
  }

  return result;
}

size_t I2CInternal::readBytes(char *buffer, size_t length) {
  int read;

  read = i2c_read_device(_i2cHandle, buffer, length);

  // Did we fail?
  if(read < 0) {
    // Set to 0 for now
    read = 0;
  }

  return read;
}

bool I2CInternal::writeByte(const uint8_t byte) {
  if(i2c_write_byte(_i2cHandle, byte) >= 0) {
    return true;
  }

  return false;
}

bool I2CInternal::readByte(uint8_t &byte) {
  int read;

  read = i2c_read_byte(_i2cHandle);
  if(read >= 0) {
    byte = (uint8_t)read;
    return true;
  }

  return false;
}

I2CExternal::I2CExternal(uint8_t i2cAddress) : I2C(i2cAddress) {
}

I2CExternal::~I2CExternal() {
}

bool I2CExternal::writeByte(const uint8_t byte) {
  bool success = false;
  char command[] = { 0x04, address(), 0x02, 0x07, 0x01, byte, 0x03, 0x00};

  if(0 == bb_i2c_zip(SDA_PIN, command, sizeof(command), NULL, 0)) {
    success = true;
  }

  return success;
}

bool I2CExternal::readByte(uint8_t &byte) {
  bool read = false;

  // Set Address, address, Start, Read, 1 byte, Stop, End
  char command[] = { 0x04, address(), 0x02, 0x06, 0x01, 0x03, 0x00};

  if(1 == bb_i2c_zip(SDA_PIN, command, sizeof(command), (char *)&byte, 1)) {
    read = true;
  }

  return read;
}

bool I2CExternal::writeBytes(const char *bytes, size_t length) {
  bool success = false;
  char command[64];
  int commandLength = 0;

  // Is the length too long?
  if(length > 32) {
    return false;
  }

  command[commandLength++] = 0x04; // Set address
  command[commandLength++] = address();
  command[commandLength++] = 0x02; // Start
  command[commandLength++] = 0x07; // Write
  command[commandLength++] = length; // umber of bytes

  // Copy the bytes to send
  memcpy(&command[commandLength], bytes,length);
  commandLength += length;

  command[commandLength++] = 0x03; // Stop
  command[commandLength++] = 0x00; // End

  if(0 == bb_i2c_zip(SDA_PIN, command, commandLength, NULL, 0)) {
    success = true;
  }

  return success;
}

size_t I2CExternal::readBytes(char *buffer, size_t length) {
  // Set Address, address, Start, Read, lengt, Stop, End
  char command[] = { 0x04, address(), 0x02, 0x06, (char)length, 0x03, 0x00};
  size_t read = 0;

  if(length > 0xFF) {
    return false;
  }

  if(length == bb_i2c_zip(SDA_PIN, command, sizeof(command), buffer, length)) {
    read = length;
  }

  return read;
}

}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012-2020 Daniele Bartolini and individual contributors.
 * License: https://github.com/dbartolini/crown/blob/master/LICENSE
 */

#include "core/error/error.inl"
#include "core/math/quaternion.inl"
#include "core/types.h"

namespace crown
{
/// Returns the rotation portion of the matrix @a m as a Quaternion.
Quaternion quaternion(const Matrix3x3& m)
{
	const f32 ww = m.x.x + m.y.y + m.z.z;
	const f32 xx = m.x.x - m.y.y - m.z.z;
	const f32 yy = m.y.y - m.x.x - m.z.z;
	const f32 zz = m.z.z - m.x.x - m.y.y;
	f32 max = ww;
	u32 index = 0;

	if (xx > max)
	{
		max = xx;
		index = 1;
	}

	if (yy > max)
	{
		max = yy;
		index = 2;
	}

	if (zz > max)
	{
		max = zz;
		index = 3;
	}

	const f32 biggest = fsqrt(max + 1.0f) * 0.5f;
	const f32 mult = 0.25f / biggest;

	Quaternion tmp;
	switch (index)
	{
	case 0:
		tmp.w = biggest;
		tmp.x = (m.y.z - m.z.y) * mult;
		tmp.y = (m.z.x - m.x.z) * mult;
		tmp.z = (m.x.y - m.y.x) * mult;
		break;

	case 1:
		tmp.x = biggest;
		tmp.w = (m.y.z - m.z.y) * mult;
		tmp.y = (m.x.y + m.y.x) * mult;
		tmp.z = (m.z.x + m.x.z) * mult;
		break;

	case 2:
		tmp.y = biggest;
		tmp.w = (m.z.x - m.x.z) * mult;
		tmp.x = (m.x.y + m.y.x) * mult;
		tmp.z = (m.y.z + m.z.y) * mult;
		break;

	case 3:
		tmp.z = biggest;
		tmp.w = (m.x.y - m.y.x) * mult;
		tmp.x = (m.z.x + m.x.z) * mult;
		tmp.y = (m.y.z + m.z.y) * mult;
		break;

	default:
		CE_FATAL("Fatal");
		break;
	}
	return tmp;
}

} // namespace crown
<commit_msg>core: cleanup<commit_after>/*
 * Copyright (c) 2012-2020 Daniele Bartolini and individual contributors.
 * License: https://github.com/dbartolini/crown/blob/master/LICENSE
 */

#include "core/error/error.inl"
#include "core/math/quaternion.inl"
#include "core/types.h"

namespace crown
{
/// Returns the rotation portion of the matrix @a m as a Quaternion.
Quaternion quaternion(const Matrix3x3& m)
{
	// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
	const f32 tr = m.x.x + m.y.y + m.z.z;

	Quaternion tmp;
	if (tr > 0.0f)
	{
		const f32 sq = fsqrt(1.0f + tr) * 0.5f;
		const f32 inv = 0.25f / sq;
		tmp.w = sq;
		tmp.x = (m.y.z - m.z.y) * inv;
		tmp.y = (m.z.x - m.x.z) * inv;
		tmp.z = (m.x.y - m.y.x) * inv;
	}
	else if ((m.x.x > m.y.y) && (m.x.x > m.z.z))
	{
		const f32 sq = fsqrt(1.0f + m.x.x - m.y.y - m.z.z) * 0.5f;
		const f32 inv = 0.25f / sq;
		tmp.x = sq;
		tmp.w = (m.y.z - m.z.y) * inv;
		tmp.y = (m.x.y + m.y.x) * inv;
		tmp.z = (m.z.x + m.x.z) * inv;
	}
	else if (m.y.y > m.z.z)
	{
		const f32 sq = fsqrt(1.0f + m.y.y - m.x.x - m.z.z) * 0.5f;
		const f32 inv = 0.25f / sq;
		tmp.y = sq;
		tmp.w = (m.z.x - m.x.z) * inv;
		tmp.x = (m.x.y + m.y.x) * inv;
		tmp.z = (m.y.z + m.z.y) * inv;
	}
	else
	{
		const f32 sq = fsqrt(1.0f + m.z.z - m.x.x - m.y.y) * 0.5f;
		const f32 inv = 0.25f / sq;
		tmp.z = sq;
		tmp.w = (m.x.y - m.y.x) * inv;
		tmp.x = (m.z.x + m.x.z) * inv;
		tmp.y = (m.y.z + m.z.y) * inv;
	}
	return tmp;
}

} // namespace crown
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2012-2016 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwo/core/util/logcentral.h>
#include <inviwo/core/util/stacktrace.h>
#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/processors/processor.h>
#include <inviwo/core/network/processornetwork.h>

namespace inviwo {

void Logger::logProcessor(Processor* processor, LogLevel level, LogAudience audience,
                          std::string msg, const char* file, const char* function, int line) {
    log("Processor " + processor->getIdentifier(), level, audience, file, function, line, msg);
}

void Logger::logNetwork(LogLevel level, LogAudience audience, std::string msg, const char* file,
                        const char* function, int line) {
    log("ProcessorNetwork", level, audience, file, function, line, msg);
}

ConsoleLogger::ConsoleLogger() : Logger() {}
ConsoleLogger::~ConsoleLogger() {}

void ConsoleLogger::log(std::string logSource, LogLevel logLevel, LogAudience audience,
                        const char* fileName, const char* functionName, int lineNumber,
                        std::string logMsg) {
    IVW_UNUSED_PARAM(fileName);
    IVW_UNUSED_PARAM(logLevel);
    IVW_UNUSED_PARAM(functionName);
    IVW_UNUSED_PARAM(lineNumber);
    if (logLevel == LogLevel::Error) {
        std::cerr << "(" << logSource << ") " << logMsg << std::endl;
    } else {
        std::cout << "(" << logSource << ") " << logMsg << std::endl;
    }
}

FileLogger::FileLogger(std::string logPath) : Logger() {
    if (filesystem::getFileExtension(logPath) != "") {
        fileStream_ = new std::ofstream(logPath.c_str());
    } else {
        fileStream_ = new std::ofstream(logPath.append("/inviwo-log.html").c_str());
    }

    (*fileStream_) << "" << std::endl;

    (*fileStream_) << "
Inviwo (V " << IVW_VERSION << ") Log File
"
                   << std::endl;
}

FileLogger::~FileLogger() {
    fileStream_->close();
    delete fileStream_;
}

void FileLogger::log(std::string logSource, LogLevel logLevel, LogAudience audience,
                     const char* fileName, const char* functionName, int lineNumber,
                     std::string logMsg) {
    IVW_UNUSED_PARAM(fileName);
    IVW_UNUSED_PARAM(logLevel);
    IVW_UNUSED_PARAM(functionName);
    IVW_UNUSED_PARAM(lineNumber);

    switch (logLevel) {
        case LogLevel::Info:
            (*fileStream_) << "
Info: ";
            break;

        case LogLevel::Warn:
            (*fileStream_) << "
Warn: ";
            break;

        case LogLevel::Error:
            (*fileStream_) << "
Error: ";
            break;
    }

    logMsg = htmlEncode(logMsg);

    replaceInString(logMsg, " ", " ");
    replaceInString(logMsg, "\n", "
");
    replaceInString(logMsg, "\t", "    ");

    (*fileStream_) << "(" << logSource << ":" << lineNumber << ") " << logMsg;
    (*fileStream_) << "
" << std::endl;
}

LogCentral::LogCentral() :
    logLevel_(LogLevel::Info),
    logStacktrace_(false) {}

LogCentral::~LogCentral() {
    for (auto& logger : loggers_) delete logger;
}

void LogCentral::registerLogger(Logger* logger) { loggers_.push_back(logger); }

void LogCentral::unregisterLogger(Logger* logger) {
    auto it = std::find(loggers_.begin(), loggers_.end(), logger);
    if (it != loggers_.end()) {
        delete logger;
        loggers_.erase(it);
    }
}

void LogCentral::log(std::string source, LogLevel level, LogAudience audience, const char* file,
                     const char* function, int line, std::string msg) {
    if (logStacktrace_ && level == LogLevel::Error && audience == LogAudience::Developer) {
        std::stringstream ss;
        ss << msg;

        std::vector<std::string> stacktrace = getStackTrace();
        // start at i == 3 to remove log and getStacktrace from stackgrace
        for (size_t i = 3; i < stacktrace.size(); ++i) {
            ss << std::endl << stacktrace[i];
        }
        // append an extra line break to easier seperate several stacktraces in a row
        ss << std::endl;

        msg = ss.str();
    }

    if (level >= logLevel_) {
        for (const auto& logger : loggers_) {
            logger->log(source, level, audience, file, function, line, msg);
        }
    }
}

void LogCentral::logProcessor(Processor* processor, LogLevel level, LogAudience audience,
                              std::string msg, const char* file, const char* function, int line) {
    if (level >= logLevel_) {
        for (const auto& logger : loggers_) {
            logger->logProcessor(processor, level, audience, msg, file, function, line);
        }
    }
}

void LogCentral::logNetwork(LogLevel level, LogAudience audience, std::string msg, const char* file,
                            const char* function, int line) {
    if (level >= logLevel_) {
        for (const auto& logger : loggers_) {
            logger->logNetwork(level, audience, msg, file, function, line);
        }
    }
}

void LogCentral::setLogStacktrace(const bool& logStacktrace) { logStacktrace_ = logStacktrace; }

bool LogCentral::getLogStacktrace() const { return logStacktrace_; }

void util::log(ExceptionContext context, std::string message, LogLevel level,
               LogAudience audience) {
    LogCentral::getPtr()->log(context.getCaller(), level, audience, context.getFile().c_str(),
                              context.getFunction().c_str(), context.getLine(), message);
}

}  // namespace<commit_msg>Core: Added date and time to filelogger<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2012-2016 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include <inviwo/core/util/logcentral.h>
#include <inviwo/core/util/stacktrace.h>
#include <inviwo/core/util/filesystem.h>
#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/processors/processor.h>
#include <inviwo/core/network/processornetwork.h>

namespace inviwo {

void Logger::logProcessor(Processor* processor, LogLevel level, LogAudience audience,
                          std::string msg, const char* file, const char* function, int line) {
    log("Processor " + processor->getIdentifier(), level, audience, file, function, line, msg);
}

void Logger::logNetwork(LogLevel level, LogAudience audience, std::string msg, const char* file,
                        const char* function, int line) {
    log("ProcessorNetwork", level, audience, file, function, line, msg);
}

ConsoleLogger::ConsoleLogger() : Logger() {}
ConsoleLogger::~ConsoleLogger() {}

void ConsoleLogger::log(std::string logSource, LogLevel logLevel, LogAudience audience,
                        const char* fileName, const char* functionName, int lineNumber,
                        std::string logMsg) {
    IVW_UNUSED_PARAM(fileName);
    IVW_UNUSED_PARAM(logLevel);
    IVW_UNUSED_PARAM(functionName);
    IVW_UNUSED_PARAM(lineNumber);
    if (logLevel == LogLevel::Error) {
        std::cerr << "(" << logSource << ") " << logMsg << std::endl;
    } else {
        std::cout << "(" << logSource << ") " << logMsg << std::endl;
    }
}

FileLogger::FileLogger(std::string logPath) : Logger() {
    if (filesystem::getFileExtension(logPath) != "") {
        fileStream_ = new std::ofstream(logPath.c_str());
    } else {
        fileStream_ = new std::ofstream(logPath.append("/inviwo-log.html").c_str());
    }

    (*fileStream_) << "" << std::endl;

    (*fileStream_) << "
Inviwo (V " << IVW_VERSION << ") Log File
"
        << std::endl;

    auto t = std::time(nullptr);
    auto tm = *std::localtime(&t);
    (*fileStream_) << "
Created at: " << std::put_time(&tm, "%Y-%m-%d %H:%M:%S") << "
" << std::endl;
}

FileLogger::~FileLogger() {
    fileStream_->close();
    delete fileStream_;
}

void FileLogger::log(std::string logSource, LogLevel logLevel, LogAudience audience,
                     const char* fileName, const char* functionName, int lineNumber,
                     std::string logMsg) {
    IVW_UNUSED_PARAM(fileName);
    IVW_UNUSED_PARAM(logLevel);
    IVW_UNUSED_PARAM(functionName);
    IVW_UNUSED_PARAM(lineNumber);

    switch (logLevel) {
        case LogLevel::Info:
            (*fileStream_) << "
Info: ";
            break;

        case LogLevel::Warn:
            (*fileStream_) << "
Warn: ";
            break;

        case LogLevel::Error:
            (*fileStream_) << "
Error: ";
            break;
    }

    logMsg = htmlEncode(logMsg);

    replaceInString(logMsg, " ", " ");
    replaceInString(logMsg, "\n", "
");
    replaceInString(logMsg, "\t", "    ");

    (*fileStream_) << "(" << logSource << ":" << lineNumber << ") " << logMsg;
    (*fileStream_) << "
" << std::endl;
}

LogCentral::LogCentral() :
    logLevel_(LogLevel::Info),
    logStacktrace_(false) {}

LogCentral::~LogCentral() {
    for (auto& logger : loggers_) delete logger;
}

void LogCentral::registerLogger(Logger* logger) { loggers_.push_back(logger); }

void LogCentral::unregisterLogger(Logger* logger) {
    auto it = std::find(loggers_.begin(), loggers_.end(), logger);
    if (it != loggers_.end()) {
        delete logger;
        loggers_.erase(it);
    }
}

void LogCentral::log(std::string source, LogLevel level, LogAudience audience, const char* file,
                     const char* function, int line, std::string msg) {
    if (logStacktrace_ && level == LogLevel::Error && audience == LogAudience::Developer) {
        std::stringstream ss;
        ss << msg;

        std::vector<std::string> stacktrace = getStackTrace();
        // start at i == 3 to remove log and getStacktrace from stackgrace
        for (size_t i = 3; i < stacktrace.size(); ++i) {
            ss << std::endl << stacktrace[i];
        }
        // append an extra line break to easier seperate several stacktraces in a row
        ss << std::endl;

        msg = ss.str();
    }

    if (level >= logLevel_) {
        for (const auto& logger : loggers_) {
            logger->log(source, level, audience, file, function, line, msg);
        }
    }
}

void LogCentral::logProcessor(Processor* processor, LogLevel level, LogAudience audience,
                              std::string msg, const char* file, const char* function, int line) {
    if (level >= logLevel_) {
        for (const auto& logger : loggers_) {
            logger->logProcessor(processor, level, audience, msg, file, function, line);
        }
    }
}

void LogCentral::logNetwork(LogLevel level, LogAudience audience, std::string msg, const char* file,
                            const char* function, int line) {
    if (level >= logLevel_) {
        for (const auto& logger : loggers_) {
            logger->logNetwork(level, audience, msg, file, function, line);
        }
    }
}

void LogCentral::setLogStacktrace(const bool& logStacktrace) { logStacktrace_ = logStacktrace; }

bool LogCentral::getLogStacktrace() const { return logStacktrace_; }

void util::log(ExceptionContext context, std::string message, LogLevel level,
               LogAudience audience) {
    LogCentral::getPtr()->log(context.getCaller(), level, audience, context.getFile().c_str(),
                              context.getFunction().c_str(), context.getLine(), message);
}

}  // namespace<|endoftext|>


<commit_before>#include <set>
#include <functional>

#include "trace.h"
#include "tpafile.h"
#include "utils.h"

bool read_field(pal::string_t line, int& offset, pal::string_t& value_recv)
{
    // The first character should be a '"'
    if (line[offset] != '"')
    {
        trace::error(_X("error reading TPA file"));
        return false;
    }
    offset++;

    // Set up destination buffer (it can't be bigger than the original line)
    pal::char_t buf[PATH_MAX];
    auto buf_offset = 0;

    // Iterate through characters in the string
    for (; offset < line.length(); offset++)
    {
        // Is this a '\'?
        if (line[offset] == '\\')
        {
            // Skip this character and read the next character into the buffer
            offset++;
            buf[buf_offset] = line[offset];
        }
        // Is this a '"'?
        else if (line[offset] == '\"')
        {
            // Done! Advance to the pointer after the input
            offset++;
            break;
        }
        else
        {
            // Take the character
            buf[buf_offset] = line[offset];
        }
        buf_offset++;
    }
    buf[buf_offset] = '\0';
    value_recv.assign(buf);

    // Consume the ',' if we have one
    if (line[offset] == ',')
    {
        offset++;
    }
    return true;
}

bool tpafile::load(pal::string_t path)
{
    // Check if the file exists, if not, there is nothing to add
    if (!pal::file_exists(path))
    {
        return true;
    }

    // Open the file
    pal::ifstream_t file(path);
    if (!file.good())
    {
        // Failed to open the file!
        return false;
    }

    // Read lines from the file
    while (true)
    {
        std::string line;
        std::getline(file, line);
        auto line_palstr = pal::to_palstring(line);
        if (file.eof())
        {
            break;
        }

        auto offset = 0;

        tpaentry_t entry;

        // Read fields
        if (!(read_field(line_palstr, offset, entry.library_type))) return false;
        if (!(read_field(line_palstr, offset, entry.library_name))) return false;
        if (!(read_field(line_palstr, offset, entry.library_version))) return false;
        if (!(read_field(line_palstr, offset, entry.library_hash))) return false;
        if (!(read_field(line_palstr, offset, entry.asset_type))) return false;
        if (!(read_field(line_palstr, offset, entry.asset_name))) return false;
        if (!(read_field(line_palstr, offset, entry.relative_path))) return false;

        m_entries.push_back(entry);
    }

    return true;
}

void tpafile::add_from_local_dir(const pal::string_t& dir)
{
    trace::verbose(_X("adding files from %s to TPA"), dir.c_str());
    const pal::char_t * const tpa_extensions[] = {
        _X(".ni.dll"),      // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir
        _X(".dll"),
        _X(".ni.exe"),
        _X(".exe"),
    };

    std::set<pal::string_t> added_assemblies;

    // Get directory entries
    auto files = pal::readdir(dir);
    for (auto ext : tpa_extensions)
    {
        auto len = pal::strlen(ext);
        for (auto file : files)
        {
            // Can't be a match if it's the same length as the extension :)
            if (file.length() > len)
            {
                // Extract the same amount of text from the end of file name
                auto file_ext = file.substr(file.length() - len, len);

                // Check if this file name matches
                if (pal::strcasecmp(ext, file_ext.c_str()) == 0)
                {
                    // Get the assembly name by stripping the extension
                    // and add it to the set so we can de-dupe
                    auto asm_name = file.substr(0, file.length() - len);

                    // TODO(anurse): Also check if already in TPA file
                    if (added_assemblies.find(asm_name) == added_assemblies.end())
                    {
                        added_assemblies.insert(asm_name);

                        tpaentry_t entry;
                        entry.asset_type = pal::string_t(_X("runtime"));
                        entry.library_name = pal::string_t(asm_name);
                        entry.library_version = pal::string_t(_X(""));

                        pal::string_t relpath(dir);
                        relpath.push_back(DIR_SEPARATOR);
                        relpath.append(file);
                        entry.relative_path = relpath;
                        entry.asset_name = asm_name;

                        trace::verbose(_X("adding %s to TPA list from %s"), asm_name.c_str(), relpath.c_str());
                        m_entries.push_back(entry);
                    }
                }
            }
        }
    }
}

void tpafile::write_tpa_list(pal::string_t& output)
{
    std::set<pal::string_t> items;
    for (auto entry : m_entries)
    {
        if (pal::strcmp(entry.asset_type.c_str(), _X("runtime")) == 0 && items.find(entry.asset_name) == items.end())
        {
            // Resolve the full path
            for (auto search_path : m_package_search_paths)
            {
                pal::string_t candidate;
                candidate.reserve(search_path.length() +
                    entry.library_name.length() +
                    entry.library_version.length() +
                    entry.relative_path.length() + 3);
                candidate.append(search_path);

                append_path(candidate, entry.library_name.c_str());
                append_path(candidate, entry.library_version.c_str());
                append_path(candidate, entry.relative_path.c_str());
                if (pal::file_exists(candidate))
                {
                    trace::verbose(_X("adding tpa entry: %s"), candidate.c_str());

                    output.append(candidate);
                    output.push_back(PATH_SEPARATOR);
                    items.insert(entry.asset_name);
                    break;
                }
            }
        }
    }
}

void tpafile::write_native_paths(pal::string_t& output)
{
    std::set<pal::string_t> items;
    for (auto search_path : m_native_search_paths)
    {
        if (items.find(search_path) == items.end())
        {
            trace::verbose(_X("adding native search path: %s"), search_path.c_str());
            output.append(search_path);
            output.push_back(PATH_SEPARATOR);
            items.insert(search_path);
        }
    }

    for (auto entry : m_entries)
    {
        auto dir = entry.relative_path.substr(0, entry.relative_path.find_last_of(DIR_SEPARATOR));
        if (pal::strcmp(entry.asset_type.c_str(), _X("native")) == 0 && items.find(dir) == items.end())
        {
            // Resolve the full path
            for (auto search_path : m_package_search_paths)
            {
                pal::string_t candidate;
                candidate.reserve(search_path.length() +
                    entry.library_name.length() +
                    entry.library_version.length() +
                    dir.length() + 3);
                candidate.append(search_path);

                append_path(candidate, entry.library_name.c_str());
                append_path(candidate, entry.library_version.c_str());
                append_path(candidate, entry.relative_path.c_str());

                if (pal::file_exists(candidate))
                {
                    trace::verbose(_X("adding native search path: %s"), candidate.c_str());
                    output.append(candidate);
                    output.push_back(PATH_SEPARATOR);
                    items.insert(dir);
                    break;
                }
            }
        }
    }
}

void tpafile::add_package_dir(pal::string_t dir)
{
    m_package_search_paths.push_back(dir);
}

void tpafile::add_native_search_path(pal::string_t dir)
{
    m_native_search_paths.push_back(dir);
}
<commit_msg>Fixed bug resolving native search paths<commit_after>#include <set>
#include <functional>

#include "trace.h"
#include "tpafile.h"
#include "utils.h"

bool read_field(pal::string_t line, int& offset, pal::string_t& value_recv)
{
    // The first character should be a '"'
    if (line[offset] != '"')
    {
        trace::error(_X("error reading TPA file"));
        return false;
    }
    offset++;

    // Set up destination buffer (it can't be bigger than the original line)
    pal::char_t buf[PATH_MAX];
    auto buf_offset = 0;

    // Iterate through characters in the string
    for (; offset < line.length(); offset++)
    {
        // Is this a '\'?
        if (line[offset] == '\\')
        {
            // Skip this character and read the next character into the buffer
            offset++;
            buf[buf_offset] = line[offset];
        }
        // Is this a '"'?
        else if (line[offset] == '\"')
        {
            // Done! Advance to the pointer after the input
            offset++;
            break;
        }
        else
        {
            // Take the character
            buf[buf_offset] = line[offset];
        }
        buf_offset++;
    }
    buf[buf_offset] = '\0';
    value_recv.assign(buf);

    // Consume the ',' if we have one
    if (line[offset] == ',')
    {
        offset++;
    }
    return true;
}

bool tpafile::load(pal::string_t path)
{
    // Check if the file exists, if not, there is nothing to add
    if (!pal::file_exists(path))
    {
        return true;
    }

    // Open the file
    pal::ifstream_t file(path);
    if (!file.good())
    {
        // Failed to open the file!
        return false;
    }

    // Read lines from the file
    while (true)
    {
        std::string line;
        std::getline(file, line);
        auto line_palstr = pal::to_palstring(line);
        if (file.eof())
        {
            break;
        }

        auto offset = 0;

        tpaentry_t entry;

        // Read fields
        if (!(read_field(line_palstr, offset, entry.library_type))) return false;
        if (!(read_field(line_palstr, offset, entry.library_name))) return false;
        if (!(read_field(line_palstr, offset, entry.library_version))) return false;
        if (!(read_field(line_palstr, offset, entry.library_hash))) return false;
        if (!(read_field(line_palstr, offset, entry.asset_type))) return false;
        if (!(read_field(line_palstr, offset, entry.asset_name))) return false;
        if (!(read_field(line_palstr, offset, entry.relative_path))) return false;

        m_entries.push_back(entry);
    }

    return true;
}

void tpafile::add_from_local_dir(const pal::string_t& dir)
{
    trace::verbose(_X("adding files from %s to TPA"), dir.c_str());
    const pal::char_t * const tpa_extensions[] = {
        _X(".ni.dll"),      // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir
        _X(".dll"),
        _X(".ni.exe"),
        _X(".exe"),
    };

    std::set<pal::string_t> added_assemblies;

    // Get directory entries
    auto files = pal::readdir(dir);
    for (auto ext : tpa_extensions)
    {
        auto len = pal::strlen(ext);
        for (auto file : files)
        {
            // Can't be a match if it's the same length as the extension :)
            if (file.length() > len)
            {
                // Extract the same amount of text from the end of file name
                auto file_ext = file.substr(file.length() - len, len);

                // Check if this file name matches
                if (pal::strcasecmp(ext, file_ext.c_str()) == 0)
                {
                    // Get the assembly name by stripping the extension
                    // and add it to the set so we can de-dupe
                    auto asm_name = file.substr(0, file.length() - len);

                    // TODO(anurse): Also check if already in TPA file
                    if (added_assemblies.find(asm_name) == added_assemblies.end())
                    {
                        added_assemblies.insert(asm_name);

                        tpaentry_t entry;
                        entry.asset_type = pal::string_t(_X("runtime"));
                        entry.library_name = pal::string_t(asm_name);
                        entry.library_version = pal::string_t(_X(""));

                        pal::string_t relpath(dir);
                        relpath.push_back(DIR_SEPARATOR);
                        relpath.append(file);
                        entry.relative_path = relpath;
                        entry.asset_name = asm_name;

                        trace::verbose(_X("adding %s to TPA list from %s"), asm_name.c_str(), relpath.c_str());
                        m_entries.push_back(entry);
                    }
                }
            }
        }
    }
}

void tpafile::write_tpa_list(pal::string_t& output)
{
    std::set<pal::string_t> items;
    for (auto entry : m_entries)
    {
        if (pal::strcmp(entry.asset_type.c_str(), _X("runtime")) == 0 && items.find(entry.asset_name) == items.end())
        {
            // Resolve the full path
            for (auto search_path : m_package_search_paths)
            {
                pal::string_t candidate;
                candidate.reserve(search_path.length() +
                    entry.library_name.length() +
                    entry.library_version.length() +
                    entry.relative_path.length() + 3);
                candidate.append(search_path);

                append_path(candidate, entry.library_name.c_str());
                append_path(candidate, entry.library_version.c_str());
                append_path(candidate, entry.relative_path.c_str());
                if (pal::file_exists(candidate))
                {
                    trace::verbose(_X("adding tpa entry: %s"), candidate.c_str());

                    output.append(candidate);
                    output.push_back(PATH_SEPARATOR);
                    items.insert(entry.asset_name);
                    break;
                }
            }
        }
    }
}

void tpafile::write_native_paths(pal::string_t& output)
{
    std::set<pal::string_t> items;
    for (auto search_path : m_native_search_paths)
    {
        if (items.find(search_path) == items.end())
        {
            trace::verbose(_X("adding native search path: %s"), search_path.c_str());
            output.append(search_path);
            output.push_back(PATH_SEPARATOR);
            items.insert(search_path);
        }
    }

    for (auto entry : m_entries)
    {
        auto dir = entry.relative_path.substr(0, entry.relative_path.find_last_of(DIR_SEPARATOR));
        if (pal::strcmp(entry.asset_type.c_str(), _X("native")) == 0 && items.find(dir) == items.end())
        {
            // Resolve the full path
            for (auto search_path : m_package_search_paths)
            {
                pal::string_t candidate;
                candidate.reserve(search_path.length() +
                    entry.library_name.length() +
                    entry.library_version.length() +
                    dir.length() + 3);
                candidate.append(search_path);

                append_path(candidate, entry.library_name.c_str());
                append_path(candidate, entry.library_version.c_str());
                append_path(candidate, get_directory(entry.relative_path).c_str());

                if (pal::file_exists(candidate))
                {
                    trace::verbose(_X("adding native search path: %s"), candidate.c_str());
                    output.append(candidate);
                    output.push_back(PATH_SEPARATOR);
                    items.insert(dir);
                    break;
                }
            }
        }
    }
}

void tpafile::add_package_dir(pal::string_t dir)
{
    m_package_search_paths.push_back(dir);
}

void tpafile::add_native_search_path(pal::string_t dir)
{
    m_native_search_paths.push_back(dir);
}
<|endoftext|>