<commit_before>/*
 * This file is part of QZeitgeist.
 *
 * Copyright (C) 2013 David Rosca <nowrep@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
extern "C" {
#include <zeitgeist.h>
}

#include "timerange.h"
#include "timerange_p.h"
#include <limits>
#include <QDateTime>

namespace QZeitgeist
{

TimeRangePrivate::TimeRangePrivate(qint64 start_, qint64 end_)
    : start(start_)
    , end(end_)
{
}

TimeRangePrivate::TimeRangePrivate(const TimeRangePrivate &other)
    : start(other.start)
    , end(other.end)
{
}

bool TimeRangePrivate::compare(const TimeRangePrivate &other) const
{
    return start == other.start && end == other.end;
}

::ZeitgeistTimeRange *timeRangeToNative(const TimeRange &other)
{
    return zeitgeist_time_range_new(other.start(), other.end());
}

// class TimeRange
TimeRange::TimeRange(qint64 start, qint64 end)
    : d(new TimeRangePrivate(start, end))
{
}

TimeRange::TimeRange(const TimeRange &other)
    : d(new TimeRangePrivate(*other.d))
{
}

TimeRange::~TimeRange()
{
}

TimeRange &TimeRange::operator=(const TimeRange &other)
{
    if (this != &other) {
        d->start = other.d->start;
        d->end = other.d->end;
    }

    return *this;
}

bool TimeRange::operator==(const TimeRange &other) const
{
    return d->compare(*other.d);
}

bool TimeRange::isValid() const
{
    return d->start > -1 && d->end > -1 && d->start <= d->end;
}

qint64 TimeRange::start() const
{
    return d->start;
}

qint64 TimeRange::end() const
{
    return d->end;
}

TimeRange TimeRange::intersect(const TimeRange &timeRange) const
{
    ::ZeitgeistTimeRange *thisTr = timeRangeToNative(*this);
    ::ZeitgeistTimeRange *otherTr = timeRangeToNative(timeRange);
    ::ZeitgeistTimeRange *resultTr = zeitgeist_time_range_intersect(thisTr, otherTr);

    if (!resultTr) {
        g_object_unref(thisTr);
        g_object_unref(otherTr);

        return TimeRange(-1, -1);
    }

    TimeRange result(zeitgeist_time_range_get_start(resultTr),
                     zeitgeist_time_range_get_end(resultTr));

    g_object_unref(thisTr);
    g_object_unref(otherTr);
    g_object_unref(resultTr);

    return result;
}

// static
TimeRange TimeRange::timeRangeAnytime()
{
    return TimeRange(0, std::numeric_limits<qint64>::max());
}

// static
TimeRange TimeRange::timeRangeToNow()
{
    return TimeRange(0, QDateTime::currentDateTime().toMSecsSinceEpoch());
}

// static
TimeRange TimeRange::timeRangeFromNow()
{
    return TimeRange(QDateTime::currentDateTime().toMSecsSinceEpoch(), 0);
}

}; // namespace QZeitgeist

<commit_msg>Fixed TimeRange::timeRangeFromNow.<commit_after>/*
 * This file is part of QZeitgeist.
 *
 * Copyright (C) 2013 David Rosca <nowrep@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
extern "C" {
#include <zeitgeist.h>
}

#include "timerange.h"
#include "timerange_p.h"
#include <limits>
#include <QDateTime>

namespace QZeitgeist
{

TimeRangePrivate::TimeRangePrivate(qint64 start_, qint64 end_)
    : start(start_)
    , end(end_)
{
}

TimeRangePrivate::TimeRangePrivate(const TimeRangePrivate &other)
    : start(other.start)
    , end(other.end)
{
}

bool TimeRangePrivate::compare(const TimeRangePrivate &other) const
{
    return start == other.start && end == other.end;
}

::ZeitgeistTimeRange *timeRangeToNative(const TimeRange &other)
{
    return zeitgeist_time_range_new(other.start(), other.end());
}

// class TimeRange
TimeRange::TimeRange(qint64 start, qint64 end)
    : d(new TimeRangePrivate(start, end))
{
}

TimeRange::TimeRange(const TimeRange &other)
    : d(new TimeRangePrivate(*other.d))
{
}

TimeRange::~TimeRange()
{
}

TimeRange &TimeRange::operator=(const TimeRange &other)
{
    if (this != &other) {
        d->start = other.d->start;
        d->end = other.d->end;
    }

    return *this;
}

bool TimeRange::operator==(const TimeRange &other) const
{
    return d->compare(*other.d);
}

bool TimeRange::isValid() const
{
    return d->start > -1 && d->end > -1 && d->start <= d->end;
}

qint64 TimeRange::start() const
{
    return d->start;
}

qint64 TimeRange::end() const
{
    return d->end;
}

TimeRange TimeRange::intersect(const TimeRange &timeRange) const
{
    ::ZeitgeistTimeRange *thisTr = timeRangeToNative(*this);
    ::ZeitgeistTimeRange *otherTr = timeRangeToNative(timeRange);
    ::ZeitgeistTimeRange *resultTr = zeitgeist_time_range_intersect(thisTr, otherTr);

    if (!resultTr) {
        g_object_unref(thisTr);
        g_object_unref(otherTr);

        return TimeRange(-1, -1);
    }

    TimeRange result(zeitgeist_time_range_get_start(resultTr),
                     zeitgeist_time_range_get_end(resultTr));

    g_object_unref(thisTr);
    g_object_unref(otherTr);
    g_object_unref(resultTr);

    return result;
}

// static
TimeRange TimeRange::timeRangeAnytime()
{
    return TimeRange(0, std::numeric_limits<qint64>::max());
}

// static
TimeRange TimeRange::timeRangeToNow()
{
    return TimeRange(0, QDateTime::currentDateTime().toMSecsSinceEpoch());
}

// static
TimeRange TimeRange::timeRangeFromNow()
{
    return TimeRange(QDateTime::currentDateTime().toMSecsSinceEpoch(),
                     std::numeric_limits<qint64>::max());
}

}; // namespace QZeitgeist

<|endoftext|>


<commit_before>#ifndef LIFOCache_HPP
#define LIFOCache_HPP

#include <string.h>
#include <iostream>
#include <cassert>
#include <stdlib.h>
#include <memory>

using namespace std;

#ifndef bool
#define bool int
#endif
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

/**
 * Threadsafe LIFO single-producer/single-consumer cache that returns most recently posted value.
 */
template <class T> class LIFOCache {
  private: volatile long readCount;
  private: volatile long writeCount;
  private: T emptyValue;
  private: T values[2];

  public: LIFOCache() {
    this->readCount = 0;
    this->writeCount = 0;
  }

  public: ~LIFOCache() { }

  public: T& get() {
    int valueIndex = writeCount - readCount;
    if (valueIndex > 0) {
      values[0] = values[valueIndex];
      for (int i = 1; i <= valueIndex; i++) {
	values[i] = emptyValue;
      }
    }
    readCount = writeCount;
    return values[0];
  }

  public: void post(T value) {
    int valueIndex = writeCount - readCount + 1;
    if (valueIndex >= 2) {
      throw "LIFOCache overflow";
    }
    values[valueIndex] = value;
    writeCount++;
  }

  public: bool isFresh() { return writeCount && writeCount != readCount; }
};

template <class T> class SmartPointer {
  public: class ReferencedPointer {
    private: int references;
    private: T* ptr;

    public: inline ReferencedPointer() {
      ptr = NULL;
      references = 0;
    }

    public: inline ReferencedPointer(T* ptr) {
      references = 1;
      this->ptr = ptr;
    }

    public: inline void decref() {
      references--;
      if (references < 0) {
	throw "ReferencedPointer extra dereference";
      }
      if (ptr && references == 0) {
	cout << "ReferencedPointer() free " << (long) ptr << endl;
	* (char *) ptr = 0; // mark as deleted
	free(ptr);
      }
    }

    public: inline void incref() { references++; }
    public: inline T* get() { return ptr; }
    public: inline int getReferences() const { return references; }
  };

  private: ReferencedPointer *pPointer;
  private: inline void decref() { if (pPointer) { pPointer->decref(); } }
  private: inline void incref() { if (pPointer) { pPointer->incref(); } }

  public: inline SmartPointer(T* ptr) {
    cout << "SmartPointer(" << (long) ptr << ")" << endl;
    this->pPointer = new ReferencedPointer(ptr);
  }

  public: inline SmartPointer() {
    cout << "SmartPointer(NULL)" << endl;
    this->pPointer = NULL;
  }

  public: inline SmartPointer(const SmartPointer &that) {
    this->pPointer = that.pPointer;
    this->incref();
  }

  public: inline ~SmartPointer() { decref(); }

  public: inline SmartPointer& operator=( SmartPointer that ) {
    decref();
    this->pPointer = that.pPointer;
    incref();
    return *this;
  }

  public: inline int getReferences() { return pPointer ? pPointer->getReferences() : 0; }
  public: inline T& operator*() { throw "SmartPointer not implemented (1)"; }
  public: inline const T& operator*() const { throw "SmartPointer not implemented (2)"; }
  public: inline T* operator->() { return pPointer ? pPointer->get() : NULL; }
  public: inline const T* operator->() const { return pPointer ? pPointer->get() : NULL; }
  public: inline operator T*() const { return pPointer ? pPointer->get() : NULL; }
};

#endif
<commit_msg>multi-thread get<commit_after>#ifndef LIFOCache_HPP
#define LIFOCache_HPP

#include <string.h>
#include <iostream>
#include <cassert>
#include <stdlib.h>
#include <memory>
#include <sched.h>

using namespace std;

#ifndef bool
#define bool int
#endif
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

/**
 * Threadsafe LIFO single-producer/multi-consumer cache that returns most recently posted value.
 */
template <class T> class LIFOCache {
  private: volatile long readCount;
  private: volatile long writeCount;
  private: T emptyValue;
  private: T values[2];
  private: volatile int nReaders;

  public: LIFOCache() {
    this->readCount = 0;
    this->writeCount = 0;
    this->nReaders = 0;
  }

  public: ~LIFOCache() { }

  public: T& get() {
    int valueIndex = writeCount - readCount;
    if (valueIndex > 0) {
      ///////////// CRITICAL SECTION BEGIN ///////////////
      while (++nReaders != 1) {				//
        --nReaders;					//
	sched_yield();					//
      }							//
      values[0] = values[valueIndex];			//
      for (int i = 1; i <= valueIndex; i++) {		//
	values[i] = emptyValue;				//
      }							//
      nReaders--; 					//
      ///////////// CRITICAL SECTION END /////////////////
    }
    readCount = writeCount;
    return values[0];
  }

  public: void post(T value) {
    int valueIndex = writeCount - readCount + 1;
    if (valueIndex >= 2) {
      throw "LIFOCache overflow";
    }
    values[valueIndex] = value;
    writeCount++;
  }

  public: bool isFresh() { return writeCount && writeCount != readCount; }
};

template <class T> class SmartPointer {
  public: class ReferencedPointer {
    private: int references;
    private: T* ptr;

    public: inline ReferencedPointer() {
      ptr = NULL;
      references = 0;
    }

    public: inline ReferencedPointer(T* ptr) {
      references = 1;
      this->ptr = ptr;
    }

    public: inline void decref() {
      references--;
      if (references < 0) {
	throw "ReferencedPointer extra dereference";
      }
      if (ptr && references == 0) {
	cout << "ReferencedPointer() free " << (long) ptr << endl;
	* (char *) ptr = 0; // mark as deleted
	free(ptr);
      }
    }

    public: inline void incref() { references++; }
    public: inline T* get() { return ptr; }
    public: inline int getReferences() const { return references; }
  };

  private: ReferencedPointer *pPointer;
  private: inline void decref() { if (pPointer) { pPointer->decref(); } }
  private: inline void incref() { if (pPointer) { pPointer->incref(); } }

  public: inline SmartPointer(T* ptr) {
    cout << "SmartPointer(" << (long) ptr << ")" << endl;
    this->pPointer = new ReferencedPointer(ptr);
  }

  public: inline SmartPointer() {
    cout << "SmartPointer(NULL)" << endl;
    this->pPointer = NULL;
  }

  public: inline SmartPointer(const SmartPointer &that) {
    this->pPointer = that.pPointer;
    this->incref();
  }

  public: inline ~SmartPointer() { decref(); }

  public: inline SmartPointer& operator=( SmartPointer that ) {
    decref();
    this->pPointer = that.pPointer;
    incref();
    return *this;
  }

  public: inline int getReferences() { return pPointer ? pPointer->getReferences() : 0; }
  public: inline T& operator*() { throw "SmartPointer not implemented (1)"; }
  public: inline const T& operator*() const { throw "SmartPointer not implemented (2)"; }
  public: inline T* operator->() { return pPointer ? pPointer->get() : NULL; }
  public: inline const T* operator->() const { return pPointer ? pPointer->get() : NULL; }
  public: inline operator T*() const { return pPointer ? pPointer->get() : NULL; }
};

#endif
<|endoftext|>


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

void eteditor::setetype(etype* e) {
  entitytype=e;
}

void eteditor::setfont(font* fontset) {
  f=fontset;
}

void eteditor::setrenderer(SDL_Renderer* renderer) {
  r=renderer;
}

void eteditor::mouse() {
  if (*mB&1) {
    if (entitytype!=NULL) {
      temppoint.x=*mX;
      temppoint.y=*mY;
      temprect.x=w-256;
      temprect.y=offY+20;
      temprect.w=85;
      temprect.h=20;
      if (SDL_PointInRect(&temppoint,&temprect)) {
        select=true;
        selectedevent=0x00000000;
      }
      if (select) {
        temprect.w=(w-512)/5;
        temprect.h=20;
        temprect.y=offY+20;
        for (int i=0; i<5; i++) {
          temprect.x=offX+(((w-512)*i)/5);
          if (SDL_PointInRect(&temppoint,&temprect)) {
            switch (i) {
              case 0: selectedevent=0x00000000; break;
              case 1: selectedevent=0x01000000; break;
              case 2: selectedevent=0x02000000; break;
              case 3: selectedevent=0x03000000; break;
              case 4: selectedevent=0x0f000000; break;
            }
          }
        }
        temprect.y=offY+40;
        for (int i=0; i<5; i++) {
          temprect.x=offX+(((w-512)*i)/5);
          if (SDL_PointInRect(&temppoint,&temprect)) {
            switch (i) {
              case 0: selectedevent=0x10000000; break;
              case 1: selectedevent=0x20000000; break;
              case 2: selectedevent=0x70000000; break;
              case 3: selectedevent=0x7e000000; break;
              case 4: selectedevent=0x7f000000; break;
            }
          }
        }
      }
    }
  }
}

void eteditor::draw() {
  f->drawf(256,256,{255,255,255,255},0,0,"%d",(entitytype==NULL));
  if (entitytype!=NULL) {
    f->draw(w-128, offY+2, color[0], 1, 0, false, "Events");
    SDL_RenderDrawLine(r, w, offY+20, w-256, offY+20);
    SDL_RenderDrawLine(r, w, offY+40, w-256, offY+40);
    SDL_RenderDrawLine(r, w-256, offY, w-256, h);

    SDL_RenderDrawLine(r, w-85, offY+20, w-85, offY+40);
    SDL_RenderDrawLine(r, w-171, offY+20, w-171, offY+40);

    f->draw(w-214, offY+22, color[0], 1, 0, 0, "Add");
    f->draw(w-128, offY+22, color[0], 1, 0, 0, "Change");
    f->draw(w-43, offY+22, color[0], 1, 0, 0, "Remove");

    if (select) {
      eventselector();
    } else {
      codeeditor();
    }
  }
}

void eteditor::eventselector() {
  // header
  f->draw(w/2,offY,color[0],1,0,0,"Select Event");
  SDL_RenderDrawLine(r, offX, offY+20, w-256, offY+20);
  // event type buttons
  f->draw(offX+(int)(((float)w-512)*0.1),offY+20,color[((selectedevent>>24)==0x00)],1,0,0,"Entity");
  f->draw(offX+(int)(((float)w-512)*0.3),offY+20,color[((selectedevent>>24)==0x01)],1,0,0,"Frame");
  f->draw(offX+(int)(((float)w-512)*0.5),offY+20,color[((selectedevent>>24)==0x02)],1,0,0,"Collision");
  f->draw(offX+(int)(((float)w-512)*0.7),offY+20,color[((selectedevent>>24)==0x03)],1,0,0,"Timer");
  f->draw(offX+(int)(((float)w-512)*0.9),offY+20,color[((selectedevent>>24)==0x0f)],1,0,0,"Render");
  f->draw(offX+(int)(((float)w-512)*0.1),offY+40,color[((selectedevent>>28)==0x1)],1,0,0,"Input");
  f->draw(offX+(int)(((float)w-512)*0.3),offY+40,color[((selectedevent>>24)==0x20)],1,0,0,"Scene");
  f->draw(offX+(int)(((float)w-512)*0.5),offY+40,color[((selectedevent>>24)==0x70)],1,0,0,"Game");
  f->draw(offX+(int)(((float)w-512)*0.7),offY+40,color[((selectedevent>>24)==0x7e)],1,0,0,"Error");
  f->draw(offX+(int)(((float)w-512)*0.9),offY+40,color[((selectedevent>>24)==0x7f)],1,0,0,"User");
  SDL_RenderDrawLine(r, offX, offY+60, w-256, offY+60);
  // event-type-respective UI
  switch (selectedevent>>24) {
    case 0:
      f->draw(w/2,offY+100,color[(selectedevent&0xf)==1],1,1,0,"Pre-Creation");
      f->draw(w/2,offY+160,color[(selectedevent&0xf)==2],1,1,0,"Creation");
      f->draw(w/2,offY+220,color[(selectedevent&0xf)==3],1,1,0,"Destruction");
      f->draw(w/2,offY+280,color[(selectedevent&0xf)==4],1,1,0,"Post-Destruction");
      break;
    case 1:
      f->draw(w/2,offY+100,color[(selectedevent&0xf)==1],1,1,0,"Pre-Frame");
      f->draw(w/2,offY+160,color[(selectedevent&0xf)==2],1,1,0,"Frame");
      f->draw(w/2,offY+220,color[(selectedevent&0xf)==3],1,1,0,"Post-Frame");
      break;
    case 2:
      SDL_RenderDrawLine(r, offX, offY+80, w-256, offY+80);
      f->draw(offX+(int)(((float)w-512)*1/6),offY+60,color[((selectedevent>>20)<0x02e)],1,0,0,"-> Entity Type");
      f->draw(offX+(int)(((float)w-512)*3/6),offY+60,color[((selectedevent>>20)==0x02e)],1,0,0,"-> Entity Group");
      f->draw(offX+(int)(((float)w-512)*5/6),offY+60,color[((selectedevent>>20)==0x02f)],1,0,0,"-> Other");
      break;
    case 3:
      SDL_RenderDrawLine(r, offX, offY+80, w-256, offY+80);
      f->draw(offX+(int)(((float)w-512)*1/4),offY+60,color[((selectedevent>>20)<0x038)],1,0,0,"Entity");
      f->draw(offX+(int)(((float)w-512)*3/4),offY+60,color[((selectedevent>>20)>0x037)],1,0,0,"Global");
      break;
    case 0x0f:
      f->draw(w/2,offY+100,color[(selectedevent&0xf)==1],1,1,0,"Pre-Clear");
      f->draw(w/2,offY+160,color[(selectedevent&0xf)==2],1,1,0,"Pre-Render");
      f->draw(w/2,offY+220,color[(selectedevent&0xf)==3],1,1,0,"Render");
      f->draw(w/2,offY+280,color[(selectedevent&0xf)==4],1,1,0,"Post-Render");
      f->draw(w/2,offY+340,color[(selectedevent&0xf)==4],1,1,0,"Overlay");
      f->draw(w/2,offY+400,color[(selectedevent&0xf)==4],1,1,0,"Post-Present");
      break;
    case 0x20:
      f->draw(w/2,offY+100,color[(selectedevent&0xf)==1],1,1,0,"Load");
      f->draw(w/2,offY+160,color[(selectedevent&0xf)==2],1,1,0,"Finish");
      break;
    case 0x70:
      f->draw(w/2,offY+100,color[(selectedevent&0xf)==1],1,1,0,"Start");
      f->draw(w/2,offY+160,color[(selectedevent&0xf)==2],1,1,0,"Exit");
      f->draw(w/2,offY+220,color[(selectedevent&0xf)==3],1,1,0,"Restart");
      f->draw(w/2,offY+280,color[(selectedevent&0xf)==4],1,1,0,"Close Button");
      break;
    case 0x7e:
      SDL_RenderDrawLine(r, offX, offY+80, w-256, offY+80);
      f->draw(offX+(int)(((float)w-512)*1/8),offY+60,color[((selectedevent>>20)<0x02e)],1,0,0,"Any Terminate");
      f->draw(offX+(int)(((float)w-512)*3/8),offY+60,color[((selectedevent>>20)==0x02e)],1,0,0,"Any Crash");
      f->draw(offX+(int)(((float)w-512)*5/8),offY+60,color[((selectedevent>>20)==0x02f)],1,0,0,"Any Signal");
      f->draw(offX+(int)(((float)w-512)*7/8),offY+60,color[((selectedevent>>20)==0x02f)],1,0,0,"Specific Signal");
      break;
  }
  // event ID
  SDL_RenderDrawLine(r, offX, h-20, w-256, h-20);
  f->drawf(offX+8,h-20,color[0],0,0,"Event ID: 0x%.8x",selectedevent);
  // done/cancel buttons
  SDL_RenderDrawLine(r,w-256-128,h-20,w-256-128,h);
  SDL_RenderDrawLine(r,w-256-64,h-20,w-256-64,h);
  f->draw(w-256-96,h-20,color[0],1,0,0,"Done");
  f->draw(w-256-32,h-20,color[0],1,0,0,"Cancel");

}

void eteditor::codeeditor() {
  f->draw(offX,offY,color[0],1,0,0,"Code Editor");
}

void eteditor::setcolor(int colindex, SDL_Color colcol) {
  color[colindex]=colcol;
}

void eteditor::setmouse(int* x, int* y, unsigned int* b, unsigned int* bold) {
  mX=x; mY=y; mB=b; mBold=bold;
}

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

void eteditor::setetype(etype* e) {
  entitytype=e;
}

void eteditor::setfont(font* fontset) {
  f=fontset;
}

void eteditor::setrenderer(SDL_Renderer* renderer) {
  r=renderer;
}

void eteditor::mouse() {
  if (*mB&1) {
    if (entitytype!=NULL) {
      temppoint.x=*mX;
      temppoint.y=*mY;
      temprect.x=w-256;
      temprect.y=offY+20;
      temprect.w=85;
      temprect.h=20;
      if (SDL_PointInRect(&temppoint,&temprect)) {
        select=true;
        selectedevent=0x00000000;
      }
      if (select) {
        temprect.w=(w-512)/5;
        temprect.h=20;
        temprect.y=offY+20;
        for (int i=0; i<5; i++) {
          temprect.x=offX+(((w-512)*i)/5);
          if (SDL_PointInRect(&temppoint,&temprect)) {
            switch (i) {
              case 0: selectedevent=0x00000000; break;
              case 1: selectedevent=0x01000000; break;
              case 2: selectedevent=0x02000000; break;
              case 3: selectedevent=0x03000000; break;
              case 4: selectedevent=0x0f000000; break;
            }
          }
        }
        temprect.y=offY+40;
        for (int i=0; i<5; i++) {
          temprect.x=offX+(((w-512)*i)/5);
          if (SDL_PointInRect(&temppoint,&temprect)) {
            switch (i) {
              case 0: selectedevent=0x10000000; break;
              case 1: selectedevent=0x20000000; break;
              case 2: selectedevent=0x70000000; break;
              case 3: selectedevent=0x7e000000; break;
              case 4: selectedevent=0x7f000000; break;
            }
          }
        }
      }
    }
  }
}

void eteditor::draw() {
  f->drawf(256,256,{255,255,255,255},0,0,"%d",(entitytype==NULL));
  if (entitytype!=NULL) {
    f->draw(w-128, offY+2, color[0], 1, 0, false, "Events");
    SDL_RenderDrawLine(r, w, offY+20, w-256, offY+20);
    SDL_RenderDrawLine(r, w, offY+40, w-256, offY+40);
    SDL_RenderDrawLine(r, w-256, offY, w-256, h);

    SDL_RenderDrawLine(r, w-85, offY+20, w-85, offY+40);
    SDL_RenderDrawLine(r, w-171, offY+20, w-171, offY+40);

    f->draw(w-214, offY+22, color[0], 1, 0, 0, "Add");
    f->draw(w-128, offY+22, color[0], 1, 0, 0, "Change");
    f->draw(w-43, offY+22, color[0], 1, 0, 0, "Remove");

    if (select) {
      eventselector();
    } else {
      codeeditor();
    }
  }
}

void eteditor::eventselector() {
  // header
  f->draw(w/2,offY,color[0],1,0,0,"Select Event");
  SDL_RenderDrawLine(r, offX, offY+20, w-256, offY+20);
  // event type buttons
  f->draw(offX+(int)(((float)w-512)*0.1),offY+20,color[((selectedevent>>24)==0x00)],1,0,0,"Entity");
  f->draw(offX+(int)(((float)w-512)*0.3),offY+20,color[((selectedevent>>24)==0x01)],1,0,0,"Frame");
  f->draw(offX+(int)(((float)w-512)*0.5),offY+20,color[((selectedevent>>24)==0x02)],1,0,0,"Collision");
  f->draw(offX+(int)(((float)w-512)*0.7),offY+20,color[((selectedevent>>24)==0x03)],1,0,0,"Timer");
  f->draw(offX+(int)(((float)w-512)*0.9),offY+20,color[((selectedevent>>24)==0x0f)],1,0,0,"Render");
  f->draw(offX+(int)(((float)w-512)*0.1),offY+40,color[((selectedevent>>28)==0x1)],1,0,0,"Input");
  f->draw(offX+(int)(((float)w-512)*0.3),offY+40,color[((selectedevent>>24)==0x20)],1,0,0,"Scene");
  f->draw(offX+(int)(((float)w-512)*0.5),offY+40,color[((selectedevent>>24)==0x70)],1,0,0,"Game");
  f->draw(offX+(int)(((float)w-512)*0.7),offY+40,color[((selectedevent>>24)==0x7e)],1,0,0,"Error");
  f->draw(offX+(int)(((float)w-512)*0.9),offY+40,color[((selectedevent>>24)==0x7f)],1,0,0,"User");
  SDL_RenderDrawLine(r, offX, offY+60, w-256, offY+60);
  // event-type-respective UI
  if ((selectedevent>>28)==0x1) {
    SDL_RenderDrawLine(r, offX, offY+80, w-256, offY+80);
    f->draw(offX+(int)(((float)w-512)*1/10),offY+60,color[((selectedevent>>24)==0x10)],1,0,0,"Keyboard");
    f->draw(offX+(int)(((float)w-512)*3/10),offY+60,color[((selectedevent>>24)==0x11)],1,0,0,"Mouse");
    f->draw(offX+(int)(((float)w-512)*5/10),offY+60,color[((selectedevent>>24)==0x12)],1,0,0,"Joystick");
    f->draw(offX+(int)(((float)w-512)*7/10),offY+60,color[((selectedevent>>24)==0x13)],1,0,0,"Touch");
    f->draw(offX+(int)(((float)w-512)*9/10),offY+60,color[((selectedevent>>24)==0x1f)],1,0,0,"Other");
  } else {
    switch (selectedevent>>24) {
      case 0:
        f->draw(w/2,offY+100,color[(selectedevent&0xf)==1],1,1,0,"Pre-Creation");
        f->draw(w/2,offY+160,color[(selectedevent&0xf)==2],1,1,0,"Creation");
        f->draw(w/2,offY+220,color[(selectedevent&0xf)==3],1,1,0,"Destruction");
        f->draw(w/2,offY+280,color[(selectedevent&0xf)==4],1,1,0,"Post-Destruction");
        break;
      case 1:
        f->draw(w/2,offY+100,color[(selectedevent&0xf)==1],1,1,0,"Pre-Frame");
        f->draw(w/2,offY+160,color[(selectedevent&0xf)==2],1,1,0,"Frame");
        f->draw(w/2,offY+220,color[(selectedevent&0xf)==3],1,1,0,"Post-Frame");
        break;
      case 2:
        SDL_RenderDrawLine(r, offX, offY+80, w-256, offY+80);
        f->draw(offX+(int)(((float)w-512)*1/6),offY+60,color[((selectedevent>>20)<0x02e)],1,0,0,"-> Entity Type");
        f->draw(offX+(int)(((float)w-512)*3/6),offY+60,color[((selectedevent>>20)==0x02e)],1,0,0,"-> Entity Group");
        f->draw(offX+(int)(((float)w-512)*5/6),offY+60,color[((selectedevent>>20)==0x02f)],1,0,0,"-> Other");
        break;
      case 3:
        SDL_RenderDrawLine(r, offX, offY+80, w-256, offY+80);
        f->draw(offX+(int)(((float)w-512)*1/4),offY+60,color[((selectedevent>>20)<0x038)],1,0,0,"Entity");
        f->draw(offX+(int)(((float)w-512)*3/4),offY+60,color[((selectedevent>>20)>0x037)],1,0,0,"Global");
        break;
      case 0x0f:
        f->draw(w/2,offY+100,color[(selectedevent&0xf)==1],1,1,0,"Pre-Clear");
        f->draw(w/2,offY+160,color[(selectedevent&0xf)==2],1,1,0,"Pre-Render");
        f->draw(w/2,offY+220,color[(selectedevent&0xf)==3],1,1,0,"Render");
        f->draw(w/2,offY+280,color[(selectedevent&0xf)==4],1,1,0,"Post-Render");
        f->draw(w/2,offY+340,color[(selectedevent&0xf)==4],1,1,0,"Overlay");
        f->draw(w/2,offY+400,color[(selectedevent&0xf)==4],1,1,0,"Post-Present");
        break;
      case 0x20:
        f->draw(w/2,offY+100,color[(selectedevent&0xf)==1],1,1,0,"Load");
        f->draw(w/2,offY+160,color[(selectedevent&0xf)==2],1,1,0,"Finish");
        break;
      case 0x70:
        f->draw(w/2,offY+100,color[(selectedevent&0xf)==1],1,1,0,"Start");
        f->draw(w/2,offY+160,color[(selectedevent&0xf)==2],1,1,0,"Exit");
        f->draw(w/2,offY+220,color[(selectedevent&0xf)==3],1,1,0,"Restart");
        f->draw(w/2,offY+280,color[(selectedevent&0xf)==4],1,1,0,"Close Button");
        break;
      case 0x7e:
        SDL_RenderDrawLine(r, offX, offY+80, w-256, offY+80);
        f->draw(offX+(int)(((float)w-512)*1/8),offY+60,color[((selectedevent>>20)<0x02e)],1,0,0,"Any Terminate");
        f->draw(offX+(int)(((float)w-512)*3/8),offY+60,color[((selectedevent>>20)==0x02e)],1,0,0,"Any Crash");
        f->draw(offX+(int)(((float)w-512)*5/8),offY+60,color[((selectedevent>>20)==0x02f)],1,0,0,"Any Signal");
        f->draw(offX+(int)(((float)w-512)*7/8),offY+60,color[((selectedevent>>20)==0x02f)],1,0,0,"Specific Signal");
        break;
    }
  }
  // event ID
  SDL_RenderDrawLine(r, offX, h-20, w-256, h-20);
  f->drawf(offX+8,h-20,color[0],0,0,"Event ID: 0x%.8x",selectedevent);
  // done/cancel buttons
  SDL_RenderDrawLine(r,w-256-128,h-20,w-256-128,h);
  SDL_RenderDrawLine(r,w-256-64,h-20,w-256-64,h);
  f->draw(w-256-96,h-20,color[0],1,0,0,"Done");
  f->draw(w-256-32,h-20,color[0],1,0,0,"Cancel");

}

void eteditor::codeeditor() {
  f->draw(offX,offY,color[0],1,0,0,"Code Editor");
}

void eteditor::setcolor(int colindex, SDL_Color colcol) {
  color[colindex]=colcol;
}

void eteditor::setmouse(int* x, int* y, unsigned int* b, unsigned int* bold) {
  mX=x; mY=y; mB=b; mBold=bold;
}

eteditor::eteditor() {
  entitytype=NULL;
  select=false;
}<|endoftext|>


<commit_before>#include "stdafx.h"
#include "Option.h"
#include "Util.h"
#include "MotifTester.h"

using namespace std;

Option::Option()
	:desc("Options", getScreenSize().first)
{
	// define
	using boost::program_options::value;
	desc.add_options()
		("help", "Print help messages")
		("nMotif", value<int>(&nMotif)->default_value(-1), "[integer] # of motif to load"
			"non-positive means load all)")
		("nGraph", value<int>(&nGraph)->default_value(-1), "[integer] # of graph to load"
			"non-positive means load all)")
		("nSkipMotif",value<int>(&nSkipMotif)->default_value(0),"[integer] skip the first k valid motifs.")
		("nSkipGraph", value<int>(&nSkipGraph)->default_value(0), "[integer] skip the first k valid graph.")
		("motifPath", value<string>(&motifPath), "the folder for motifs (input)")
		("motifPattern", value<string>(&motifPattern)->default_value(string("res-.*\\.txt")),
			"the file name pattern for the motif files, in ECMAScript regular expressions syntax. "
			"USE \"\" to contain the regular expression for special characters of the shell, like *")
		("graphPath", value<string>(&graphPath), "the folder for graph data (input)")
		("graphTypePos", value<vector<int>>(&graphTypePos)->multitoken(), "the type(s) of positive graph")
		("graphTypeNeg", value<vector<int>>(&graphTypeNeg)->multitoken()->default_value(vector<int>(1, 0), "0"),
			"the type(s) of negative graphs")
		//("thrsldMotifSub", value<double>(&thrsldMotifSub)->default_value(0.4, "0.4"),
		//	"the portion threshold for regarding a motif as existence on a subject")
		(MotifTester::name.c_str(), value<vector<string>>(&motifTestMethod)->multitoken(), MotifTester::usage.c_str())
		("logFile", value<string>(&logFile), "the file for detailed motif checking log (output)")
		("outputFile", value<string>(&outputFile), "the file for outputting the result (output)")
		;
}

boost::program_options::options_description & Option::getDesc()
{
	return desc;
}

bool Option::parseInput(int argc, char* argv[]) {
	//parse
	bool flag_help = false;
	boost::program_options::variables_map var_map;
	try {
		boost::program_options::store(
			boost::program_options::parse_command_line(argc, argv, desc), var_map);
		boost::program_options::notify(var_map);

		if(var_map.count("help")) {
			flag_help = true;
		}
	} catch(std::exception& excep) {
		cerr << "error: " << excep.what() << "\n";
		flag_help = true;
	} catch(...) {
		cerr << "Exception of unknown type!\n";
		flag_help = true;
	}

	while(!flag_help) { // technique for condition checking
		sortUpPath(motifPath);
		sortUpPath(graphPath);
		mergeGraphType();
		break;
	}

	if(true == flag_help) {
		cerr << desc << endl;
		return false;
	}
	return true;
}

std::string& Option::sortUpPath(std::string & path)
{
	if(!path.empty() && path.back() != '/')
		path.push_back('/');
	return path;
}

void Option::mergeGraphType()
{
	graphTypes.clear();
	graphTypes.reserve(graphTypePos.size() + graphTypeNeg.size());
	graphTypes = graphTypePos;
	for(auto& v : graphTypeNeg)
		graphTypes.push_back(v);
	sort(graphTypes.begin(), graphTypes.end());
}

<commit_msg>add input checking<commit_after>#include "stdafx.h"
#include "Option.h"
#include "Util.h"
#include "MotifTester.h"

using namespace std;

Option::Option()
	:desc("Options", getScreenSize().first)
{
	// define
	using boost::program_options::value;
	desc.add_options()
		("help", "Print help messages")
		("nMotif", value<int>(&nMotif)->default_value(-1), "[integer] # of motif to load"
			"non-positive means load all)")
		("nGraph", value<int>(&nGraph)->default_value(-1), "[integer] # of graph to load"
			"non-positive means load all)")
		("nSkipMotif",value<int>(&nSkipMotif)->default_value(0),"[integer] skip the first k valid motifs.")
		("nSkipGraph", value<int>(&nSkipGraph)->default_value(0), "[integer] skip the first k valid graph.")
		("motifPath", value<string>(&motifPath), "the folder for motifs (input)")
		("motifPattern", value<string>(&motifPattern)->default_value(string("res-.*\\.txt")),
			"the file name pattern for the motif files, in ECMAScript regular expressions syntax. "
			"USE \"\" to contain the regular expression for special characters of the shell, like *")
		("graphPath", value<string>(&graphPath), "the folder for graph data (input)")
		("graphTypePos", value<vector<int>>(&graphTypePos)->multitoken(), "the type(s) of positive graph")
		("graphTypeNeg", value<vector<int>>(&graphTypeNeg)->multitoken()->default_value(vector<int>(1, 0), "0"),
			"the type(s) of negative graphs")
		//("thrsldMotifSub", value<double>(&thrsldMotifSub)->default_value(0.4, "0.4"),
		//	"the portion threshold for regarding a motif as existence on a subject")
		(MotifTester::name.c_str(), value<vector<string>>(&motifTestMethod)->multitoken(), MotifTester::usage.c_str())
		("logFile", value<string>(&logFile), "the file for detailed motif checking log (output)")
		("outputFile", value<string>(&outputFile), "the file for outputting the result (output)")
		;
}

boost::program_options::options_description & Option::getDesc()
{
	return desc;
}

bool Option::parseInput(int argc, char* argv[]) {
	//parse
	bool flag_help = false;
	boost::program_options::variables_map var_map;
	try {
		boost::program_options::store(
			boost::program_options::parse_command_line(argc, argv, desc), var_map);
		boost::program_options::notify(var_map);

		if(var_map.count("help")) {
			flag_help = true;
		}
	} catch(std::exception& excep) {
		cerr << "error: " << excep.what() << "\n";
		flag_help = true;
	} catch(...) {
		cerr << "Exception of unknown type!\n";
		flag_help = true;
	}

	while(!flag_help) { // technique for condition checking
		if(motifPath.empty()) {
			cerr << "motif path is not given" << endl;
			flag_help = true;
			break;
		}
		if(graphPath.empty()) {
			cerr << "graph path is not given" << endl;
			flag_help = true;
			break;
		}
		if(motifPattern.empty()) {
			cerr << "motif file name pattern is not given" << endl;
			flag_help = true;
			break;
		}
		if(graphTypePos.empty()) {
			cerr << "positive graph type list is not given" << endl;
			flag_help = true;
			break;
		}
		if(graphTypeNeg.empty()) {
			cerr << "negative graph type list is not given" << endl;
			flag_help = true;
			break;
		}
		sortUpPath(motifPath);
		sortUpPath(graphPath);
		mergeGraphType();
		break;
	}

	if(true == flag_help) {
		cerr << desc << endl;
		return false;
	}
	return true;
}

std::string& Option::sortUpPath(std::string & path)
{
	if(!path.empty() && path.back() != '/')
		path.push_back('/');
	return path;
}

void Option::mergeGraphType()
{
	graphTypes.clear();
	graphTypes.reserve(graphTypePos.size() + graphTypeNeg.size());
	graphTypes = graphTypePos;
	for(auto& v : graphTypeNeg)
		graphTypes.push_back(v);
	sort(graphTypes.begin(), graphTypes.end());
}

<|endoftext|>


<commit_before>#include <boost/tokenizer.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <sys/wait.h>
#include <sys/types.h>
#include <vector>
#include <pwd.h>
#include <iostream>

using namespace std;
using namespace boost;

class Shell {
    private:
        string command;
        bool exit_override;
        //Step 1: Ask for command
        //Step 2: Parse command
        //Step 3: Execute command
        //Step 4: Account for connectors
    public:
        Shell() {exit_override = false;};
        ~Shell() {};
        void run()
        {
            char* name;
            char hostname[1024];
            gethostname(hostname, 1024);
            struct passwd* pass;
            pass = getpwuid(getuid());
            name = pass->pw_name;
            exit_override = false;
            while(command != "exit" || !exit_override)
            {

                if(exit_override)
                {
                    return;
                }
                else
                {
               	    cout << name << "@" << hostname << "$ ";
                    getline(cin, command);
                    if(command == "exit") //If the command is just exit
                    {
                        return;
                    }
                    else if(command != "") //If we entered an actual command
                    {
			int result = parse(command);
		        if(result == 2)
                        {
                            exit_override = true;
			    exit(0);
                        }
			else if(result == 1)
			{
			    cout << "Error: Command Invalid." << endl;
			}
                    }
                }
            }
        }
        int parse(string cmdLine)
        {
            vector <string> v;
            //Defines a tokenizer type that seperates cmdLine by spaces
            typedef tokenizer<char_separator<char> > tokenizer;
            char_separator<char> sep(" ");
            tokenizer tok(cmdLine, sep);

            //Checks each token and puts it in a vector.
            for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
            {
                    v.push_back(*it);
            }
	        //Takes each tokenized phrase and anaylzes it for different cases.
            v = analyze_split(v);

            //Quick check if the first command is exit.
	        if (v.at(0) == "exit")
	        {
		        return 2;
	        }

	        //Organize the vector by precedence.
	        vector<vector <string> > commands = organize_commands(v);

	        //Create a new vector to store and run commands.
	        //Also create a last_output variable, telling us whether or not the
	        //last output of a command was true or false.
            vector<string> command_to_execute;
	        int last_output = 2; //0 - false 1 - true

            for (unsigned i = 0; i < commands.size(); ++i)
            {

                for (unsigned j = 0; j < commands.at(i).size(); ++j)
                {
                    //std::cout << commands.at(i).at(j) << std::endl; Use to output commands
                    //If comment is seen, we don't push it to our command.
                    //Instead, we execute it and jump out of the loop.
                    if(commands.at(i).at(j).at(0) == '#')
                    {
                        execute(command_to_execute);
                        return 4; //Error code for command
                    }
                    //If a connector is detected.
                    else if (commands.at(i).at(j) == "||" || commands.at(i).at(j) == "&&" || commands.at(i).at(j) == ";")
                    {
                        //Case 0: The connector is either the only element in the vector OR the first element
                        //Also does quick checks for && in case the past commands failed already
                        //Check if the command failed last time and the connector is an "and" symbol
    		            if (last_output == 0 && commands.at(i).at(j) == "&&")
    		            {
    			            return 1;
    		            }
    		            //Checks if the last command succeeded, the input is &&, and that it is either the only command OR the first element
    		            //in another command.
    		            else if (last_output == 1 && commands.at(i).at(0) == "&&")
    		            {
    		                last_output = last_output;
    		            }
    		            //Checks if the last command failed and that the connector is an "or" symbol
    		            else if (last_output == 0 && commands.at(i).at(j) == "||")
    		            {
    		                ++i;
    		            }
    		            //Checks if the last command succeeded, the input is ||, and that it is either the only command OR the first element
    		            //in another command.
    		            else if(last_output == 1 && commands.at(i).at(0) == "||")
    		            {
    		                return 5; //We know that if it is either of those cases, then we don't do anything else to the rest of the input.
    		            }
    		            else
    		            {
    		                //CASE 1: There are inputs BEFORE the connector.
    		                //Execute the command. Store its result in a boolean.
                            bool cmd_output = execute(command_to_execute);
    		                last_output = cmd_output;
                            command_to_execute.clear(); //Clear the vector to add in new commands.
                            //Check whether or not to add in new commands depending on the connector.
                            bool cnt_output = connector(cmd_output, commands.at(i).at(j));

                            if (cnt_output == false)
                            {
    			                if (cmd_output == 1) //If the first command failed and we have an || connector after
    			                {
    			                    break; //Just return since nothing else is supposed to happen for that command.
    			                }
                                if (cmd_output == 0) //If the first command failed and we have an && connector after
    			                {
    			                    return 1; //Return code for failure
    			                }
                            }
    		            }
                    }
                    //CASE 2: The command has no connectors AND/OR this is the last element of the command
                    else if (j == (unsigned)commands.at(i).size() - 1)
                    {
                        if (commands.at(i).at(j) == "exit")
                        {
                            return 2;
                        }
                        command_to_execute.push_back(commands.at(i).at(j));
                        bool temp = execute(command_to_execute);
                        command_to_execute.clear();
                        if (temp == false)
                        {
                            return 1; //Return code for error
                        }
                    }
                    //CASE 3: An piece of a command that is not a connector is pushed in.
                    else
                    {
                        command_to_execute.push_back(commands.at(i).at(j));
                    }
                   // cout << v.at(i) << endl;
                }
            }
            return 0; //Return code for command sucessfully parsed

        }

        //Accounts for connectors mixed with other text
        vector<string> analyze_split(vector<string>& v)
        {
            vector<string> commands;
            //Look at each string in the vector.

            for(unsigned i = 0; i < v.size(); ++i)
            {
                string temp;
                //Look at each letter of each string for connectors.
                for(unsigned j = 0; j < v.at(i).size(); ++j)
                {
                    //Tests whether or not we found a connector.
		            if(v.at(i).at(j) == '|' && j + 1 != v.at(i).size())
		            {
                        if(v.at(i).at(j + 1) == '|')
                        {
                           if(temp != "")
                            {
                                commands.push_back(temp);
                            }

                            temp = "||";
                            commands.push_back(temp);
                            temp = "";
                            ++j;
                        }
		            }
		            else if(v.at(i).at(j) == '&' && j + 1 != v.at(i).size())
		            {
		                if( v.at(i).at(j + 1) == '&')
                            {
                                if(temp != "")
                                {
                                commands.push_back(temp);
                                }

                                temp = "&&";
                                commands.push_back(temp);
                                temp = "";
                                ++j;
			                }
                    }
                    else if(v.at(i).at(j) == ';')
                    {
                        if(temp != "")
                        {
                            commands.push_back(temp);
                        }

                        temp = ";";
                        commands.push_back(temp);
                        temp = "";
                    }
                    else if(v.at(i).at(j) == '#')
                    {
                        if(temp != "")
                        {
                            commands.push_back(temp);
                        }

                        temp = "#";
                        commands.push_back(temp);
                        temp = "";
                    }
                    else if(v.at(i).at(j) == '(')
                    {
                        if(temp != "")
                        {
                            commands.push_back(temp);
                        }

                        temp = "(";
                        commands.push_back(temp);
                        temp = "";
                    }
                    else if(v.at(i).at(j) == ')')
                    {
                        if(temp != "")
                        {
                            commands.push_back(temp);
                        }

                        temp = ")";
                        commands.push_back(temp);
                        temp = "";
                    }
                    else
                    {
                        temp = temp + v.at(i).at(j);
                    }
                }
                if(temp != "")
                {
                    commands.push_back(temp);
                }

            }
            //Push the string in case there are no connectors.
            //commands.push_back(temp);
            //Input should now be organized correctly by parts.

           //Test to see if commands are actually parsed correctly.
	    /*for (unsigned i = 0; i < commands.size(); i++)
	    {
		    cout << commands.at(i) << endl;
	    }*/
            return commands;
        }
        //TO DO: Check for erroneous paratheses. *****************************************************
        vector<vector<string> >organize_commands(vector<string> whole_command)
        {
            //Vector to be returned
            vector<vector<string> > commands;
            //Vector of a single command that is constantly pushed into the vector above.
            vector<string> command;
            bool para_open = false; //Checks if the parathese is open or not.

            for(unsigned i = 0; i < whole_command.size(); ++i)
            {
                if(whole_command.at(i) == "(")
                {
                    //We now know that there is an open paratheses.
                    para_open = true;
                    //Push the current command onto the vector.
                    if(!command.empty())
                    {
                        commands.push_back(command);
                        command.clear();
                    }

                }
                else if(para_open == true)
                {
                    //There is a closed paratheses which will close the inner command.
                    if(whole_command.at(i) == ")")
                    {
                        //We know that this is a closed set of paratheses, so we push that command on there.
                        para_open = false;
                        commands.push_back(command);
                        command.clear();
                    }
                    else
                    {
                        //In this case we just add the piece of the command onto the vector before we close it.
                        command.push_back(whole_command.at(i));
                    }
                }
                else
                {   //Just add the piece of the command onto the vector.
                    command.push_back(whole_command.at(i));
                }
            }
            //If no paratheses were left in the vector we simply check of any commands were put into the vector
            //And push that in as well.
            if(!command.empty())
            {
                commands.push_back(command);
            }

            //Test to see if the commands are actually organized correctly.
            /*for (unsigned i = 0; i < commands.size(); ++i)
	        {
	            for(unsigned j = 0; j < commands.at(i).size(); j++)
	            {
	                std::cout << commands.at(i).at(j) << std::endl;
	            }
	            std::cout << "COMMAND" << std::endl;
	        }*/

            return commands;
        }

        //Executes the command.
        bool execute(vector<string>cmd)
        {
                //Accounts for case if a comment is inputted.
                if (cmd.size() == 0)
                {
                    return false;
                }
                else if (cmd.at(0) == "exit" && cmd.size() == 1)
                {
                    cout << "Exit statement hit." << endl;
                    return false;
                }
                else
                {
		    char **temp = new char*[cmd.size() + 1];
               // char* temp[cmd.size()+ 1];
                //Sets the command in a c-string form.
                for(unsigned i = 0; i < cmd.size(); ++i)
                {
                    temp[i] = (char*)cmd.at(i).c_str();
                }
                //We push a null character at the end of the array to let execvp
                //know where to end with the command.
                temp[cmd.size()] = NULL;

                pid_t pid = fork();
                if (pid == 0)
                {
                    //If the command does not work
                    if(execvp(temp[0], temp) == -1)
                    {
                        perror("exec");
                        return false;
                    }
                }
                if (pid > 0)
                {
                    if (wait(0) == -1)
                    {
                        perror("wait");
                    }
                }
                return true;
                }
        }
	//Connector Logic is put here.
	//Made to decide whether or not to execute the next command
	//in sequence given the connector.
        bool connector(bool cmdExecuted, string connector)
        {
            if(connector == "||")
            {
                if(cmdExecuted == false)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else if(connector == "&&")
            {
                if(cmdExecuted == true)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else if(connector == "#")
            {
                return false;
            }
            //Semicolon will always execute next command
            else
            {
                return true;
            }
        }
};<commit_msg>Fixed shell bugs<commit_after>#include <boost/tokenizer.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <sys/wait.h>
#include <sys/types.h>
#include <vector>
#include <pwd.h>
#include <iostream>

using namespace std;
using namespace boost;

class Shell {
    private:
        string command;
        bool exit_override;
        //Step 1: Ask for command
        //Step 2: Parse command
        //Step 3: Execute command
        //Step 4: Account for connectors
    public:
        Shell() {exit_override = false;};
        ~Shell() {};
        void run()
        {
            char* name;
            char hostname[1024];
            gethostname(hostname, 1024);
            struct passwd* pass;
            pass = getpwuid(getuid());
            name = pass->pw_name;
            exit_override = false;
            while(command != "exit" || !exit_override)
            {

                if(exit_override)
                {
                    return;
                }
                else
                {
               	    cout << name << "@" << hostname << "$ ";
                    getline(cin, command);
                    if(command == "exit") //If the command is just exit
                    {
                        return;
                    }
                    else if(command != "") //If we entered an actual command
                    {
			int result = parse(command);
		        if(result == 2)
                        {
                            exit_override = true;
			    exit(0);
                        }
			else if(result == 1)
			{
			    cout << "Error: Command Invalid." << endl;
			}
                    }
                }
            }
        }
        int parse(string cmdLine)
        {
            vector <string> v;
            //Defines a tokenizer type that seperates cmdLine by spaces
            typedef tokenizer<char_separator<char> > tokenizer;
            char_separator<char> sep(" ");
            tokenizer tok(cmdLine, sep);

            //Checks each token and puts it in a vector.
            for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it)
            {
                    v.push_back(*it);
            }
	        //Takes each tokenized phrase and anaylzes it for different cases.
            v = analyze_split(v);

            //Quick check if the first command is exit.
	        if (v.at(0) == "exit")
	        {
		        return 2;
	        }

	        //Organize the vector by precedence.
	        vector<vector <string> > commands = organize_commands(v);

	        //Create a new vector to store and run commands.
	        //Also create a last_output variable, telling us whether or not the
	        //last output of a command was true or false.
            vector<string> command_to_execute;
	        int last_output = 2; //0 - false 1 - true
	        int cnt_output = 2;

            for (unsigned i = 0; i < commands.size(); ++i)
            {

                for (unsigned j = 0; j < commands.at(i).size(); ++j)
                {
                    //std::cout << commands.at(i).at(j) << std::endl; Use to output commands
                    //If comment is seen, we don't push it to our command.
                    //Instead, we execute it and jump out of the loop.
                    if(commands.at(i).at(j).at(0) == '#')
                    {
                        execute(command_to_execute);
                        return 4; //Error code for command
                    }
                    //If a connector is detected.
                    else if (commands.at(i).at(j) == "||" || commands.at(i).at(j) == "&&" || commands.at(i).at(j) == ";")
                    {
                        //std::cout << commands.at(i).at(j) << std::endl;
                        //std::cout << last_output << " " << cnt_output << std::endl;

                        //Case 0: The connector is either the only element in the vector OR the first element
                        //Also does quick checks for && in case the past commands failed already
                        //Check if the command failed last time and the connector is an "and" symbol
    		            if (last_output == 0 && commands.at(i).at(j) == "&&")
    		            {
    			            return 1;
    		            }
    		            //Checks if the last command succeeded, the input is &&, and that it is either the only command OR the first element
    		            //in another command.
    		            else if (last_output == 1 && commands.at(i).at(0) == "&&" && j == 0)
    		            {
    		                cnt_output = 1; //We want to simulate that && connector goes true, so we make out cnt_output to 1 to indicate that
    		                                // we can go on with the next command.
    		            }
    		            //Checks for past || operators. If the command before || runs true, everything afterward should
                        //not run at all.
                        else if(last_output == 1 && cnt_output == 0)
                        {
                            break;
                        }
    		            //Checks if the last command failed, the input is ||, and that it is either the only command OR the first element
    		            //in another command.
    		            else if (last_output == 0 && commands.at(i).at(0) == "||")
    		            {
    		                last_output = 2;
    		            }
    		            //Checks if the last command failed and that the connector is an "or" symbol
    		            else if (last_output == 0 && commands.at(i).at(j) == "||")
    		            {
    		                ++i;
    		            }
    		            //Checks if the last command succeeded, the input is ||, and that it is either the only command OR the first element
    		            //in another command.
    		            else if(last_output == 1 && commands.at(i).at(0) == "||")
    		            {
    		                cnt_output = 0;
    		                break; //We know that if it is either of those cases, then we don't do anything else to the rest of the input.
    		            }
    		            else
    		            {
    		                //CASE 1: There are inputs BEFORE the connector.
    		                //Execute the command. Store its result in a boolean.
                            bool cmd_output = execute(command_to_execute);
    		                last_output = cmd_output;
                            command_to_execute.clear(); //Clear the vector to add in new commands.
                            //Check whether or not to add in new commands depending on the connector.
                            cnt_output = connector(cmd_output, commands.at(i).at(j));

                            if (cnt_output == 0)
                            {
    			                if (cmd_output == 1) //If the first command failed and we have an || connector after
    			                {
    			                    break; //Just return since nothing else is supposed to happen for that command.
    			                }
                                if (cmd_output == 0) //If the first command failed and we have an && connector after
    			                {
    			                    break; //Break because we're done with this command.
    			                }
                            }
    		            }
                    }
                    //CASE 2: The command has no connectors AND/OR this is the last element of the command
                    else if (j == (unsigned)commands.at(i).size() - 1)
                    {
                        //Checks for past || operators. If the command before || runs true, everything afterward should
                        //not run at all.
                        if(last_output == 1 && cnt_output == 0)
                        {
                            break;
                        }
                        else if (commands.at(i).at(j) == "exit")
                        {
                            return 2;
                        }
                        //Push the last command onto the vector
                        command_to_execute.push_back(commands.at(i).at(j));
                        bool cmd_output = execute(command_to_execute);
                        last_output = cmd_output; //Check to see if the command failed.
                        command_to_execute.clear();
                        if (cmd_output == false)
                        {
                            break; //Return code for error
                        }
                    }
                    //CASE 3: An piece of a command that is not a connector is pushed in.
                    else
                    {
                        if(last_output == 1 && cnt_output == 0)
                        {
                            break;
                        }
                        else
                        {
                            command_to_execute.push_back(commands.at(i).at(j));
                        }
                    }
                   // cout << v.at(i) << endl;
                }
            }
            return 0; //Return code for command sucessfully parsed

        }

        //Accounts for connectors mixed with other text
        vector<string> analyze_split(vector<string>& v)
        {
            vector<string> commands;
            //Look at each string in the vector.

            for(unsigned i = 0; i < v.size(); ++i)
            {
                string temp;
                //Look at each letter of each string for connectors.
                for(unsigned j = 0; j < v.at(i).size(); ++j)
                {
                    //Tests whether or not we found a connector.
		            if(v.at(i).at(j) == '|' && j + 1 != v.at(i).size())
		            {
                        if(v.at(i).at(j + 1) == '|')
                        {
                           if(temp != "")
                            {
                                commands.push_back(temp);
                            }

                            temp = "||";
                            commands.push_back(temp);
                            temp = "";
                            ++j;
                        }
		            }
		            else if(v.at(i).at(j) == '&' && j + 1 != v.at(i).size())
		            {
		                if( v.at(i).at(j + 1) == '&')
                            {
                                if(temp != "")
                                {
                                commands.push_back(temp);
                                }

                                temp = "&&";
                                commands.push_back(temp);
                                temp = "";
                                ++j;
			                }
                    }
                    else if(v.at(i).at(j) == ';')
                    {
                        if(temp != "")
                        {
                            commands.push_back(temp);
                        }

                        temp = ";";
                        commands.push_back(temp);
                        temp = "";
                    }
                    else if(v.at(i).at(j) == '#')
                    {
                        if(temp != "")
                        {
                            commands.push_back(temp);
                        }

                        temp = "#";
                        commands.push_back(temp);
                        temp = "";
                    }
                    else if(v.at(i).at(j) == '(')
                    {
                        if(temp != "")
                        {
                            commands.push_back(temp);
                        }

                        temp = "(";
                        commands.push_back(temp);
                        temp = "";
                    }
                    else if(v.at(i).at(j) == ')')
                    {
                        if(temp != "")
                        {
                            commands.push_back(temp);
                        }

                        temp = ")";
                        commands.push_back(temp);
                        temp = "";
                    }
                    else
                    {
                        temp = temp + v.at(i).at(j);
                    }
                }
                if(temp != "")
                {
                    commands.push_back(temp);
                }

            }
            //Push the string in case there are no connectors.
            //commands.push_back(temp);
            //Input should now be organized correctly by parts.

           //Test to see if commands are actually parsed correctly.
	    /*for (unsigned i = 0; i < commands.size(); i++)
	    {
		    cout << commands.at(i) << endl;
	    }*/
            return commands;
        }
        //TO DO: Check for erroneous paratheses. *****************************************************
        vector<vector<string> >organize_commands(vector<string> whole_command)
        {
            //Vector to be returned
            vector<vector<string> > commands;
            //Vector of a single command that is constantly pushed into the vector above.
            vector<string> command;
            bool para_open = false; //Checks if the parathese is open or not.
            int para_loc = 0;

            for(unsigned i = 0; i < whole_command.size(); ++i)
            {
                if(whole_command.at(i) == "(")
                {
                    //We now know that there is an open paratheses.
                    para_open = true;
                    //Push the current command onto the vector.
                    if(!command.empty())
                    {
                        commands.push_back(command);
                        command.clear();
                    }
                    //Then, push the paratheses on the vector.
                    command.push_back(whole_command.at(i));
                    para_loc = command.size() - 1; //Store the location of the open paratheses.

                }
                else if(para_open == true)
                {
                    //There is a closed paratheses which will close the inner command.
                    if(whole_command.at(i) == ")")
                    {
                        //We know that this is a closed set of paratheses, so we push that command on there.
                        //Afterwards we removed the opening paratheses since we know that is this is a closed
                        //command.
                        para_open = false;
                        command.erase(command.begin() + para_loc);
                        commands.push_back(command);
                        command.clear();
                    }
                    else
                    {
                        //In this case we just add the piece of the command onto the vector before we close it.
                        command.push_back(whole_command.at(i));
                    }
                }
                else
                {   //Just add the piece of the command onto the vector.
                    command.push_back(whole_command.at(i));
                }
            }
            //If no paratheses were left in the vector we simply check of any commands were put into the vector
            //And push that in as well.
            if(!command.empty())
            {
                commands.push_back(command);
            }

            //Test to see if the commands are actually organized correctly.
            /*for (unsigned i = 0; i < commands.size(); ++i)
	        {
	            for(unsigned j = 0; j < commands.at(i).size(); j++)
	            {
	                std::cout << commands.at(i).at(j) << std::endl;
	            }
	            std::cout << "COMMAND" << std::endl;
	        }*/

            return commands;
        }

        //Executes the command.
        bool execute(vector<string>cmd)
        {
                //Accounts for case if a comment is inputted.
                if (cmd.size() == 0)
                {
                    return false;
                }
                else if (cmd.at(0) == "exit" && cmd.size() == 1)
                {
                    return false;
                }
                else
                {
		        char **temp = new char*[cmd.size() + 1];
                //Sets the command in a c-string form.
                for(unsigned i = 0; i < cmd.size(); ++i)
                {
                    temp[i] = (char*)cmd.at(i).c_str();
                }
                //We push a null character at the end of the array to let execvp
                //know where to end with the command.
                temp[cmd.size()] = NULL;

                pid_t pid = fork();
                if (pid == 0)
                {
                    //If the command does not work
                    if(execvp(temp[0], temp) == -1)
                    {
                        perror("exec");
                        return false;
                    }
                }
                if (pid > 0)
                {
                    if (wait(0) == -1)
                    {
                        perror("wait");
                    }
                }
                return true;
                }
        }
	//Connector Logic is put here.
	//Made to decide whether or not to execute the next command
	//in sequence given the connector.
        bool connector(bool cmdExecuted, string connector)
        {
            if(connector == "||")
            {
                if(cmdExecuted == false)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else if(connector == "&&")
            {
                if(cmdExecuted == true)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else if(connector == "#")
            {
                return false;
            }
            //Semicolon will always execute next command
            else
            {
                return true;
            }
        }
};<|endoftext|>


<commit_before>#include "iotsaRequest.h"
#include <base64.h>
#ifdef ESP32
#include <HTTPClient.h>
#else
#include <ESP8266HTTPClient.h>
#endif

#ifdef ESP32
#define SSL_INFO_NAME "rootCA"
#else
#define SSL_INFO_NAME "fingerprint"
#endif

bool IotsaRequest::configLoad(IotsaConfigFileLoad& cf, String& f_name) {
    cf.get(f_name + ".url", url, "");
    cf.get(f_name + "." + SSL_INFO_NAME, sslInfo, "");
    cf.get(f_name + "credentials", credentials, "");
    cf.get(f_name + "token", token, "");
    return url != "";
}

void IotsaRequest::configSave(IotsaConfigFileSave& cf, String& f_name) {
    cf.put(f_name + ".url", url);
    cf.put(f_name + "." + SSL_INFO_NAME, sslInfo);
    cf.put(f_name + ".credentials", credentials);
    cf.put(f_name + ".token", token);
}

#ifdef IOTSA_WITH_WEB
void IotsaRequest::formHandler(String& message) {
  message += "Activation URL: <input name='url'>
\n";
#ifdef ESP32
  message += "Root CA cert (https only): <input name='rootCA'>
\n";
#else
  message += "Fingerprint (https only): <input name='fingerprint'>
\n";
#endif

  message += "Bearer token (optional): <input name='token'>
\n";
  message += "Credentials (optional, user:pass): <input name='credentials'>
\n";
}

void IotsaRequest::formHandler(String& message, String& text, String& f_name) {
  message += "Activation URL: <input name='" + f_name +  ".url' value='";
  message += url;
  message += "'>
\n";
#ifdef ESP32
  message += "Root CA cert (https only): <input name='" + f_name + ".rootCA' value='";
  message += sslInfo;
#else
  message += "Fingerprint (https only): <input name='" + f_name +  ".fingerprint' value='";
  message += sslInfo;
#endif
  message += "'>
\n";

  message += "Bearer token (optional): <input name='" + f_name + ".token' value='";
  message += token;
  message += "'>
\n";

  message += "Credentials (optional, user:pass): <input name='" + f_name + ".credentials' value='";
  message += credentials;
  message += "'>
\n";
}

void IotsaRequest::formHandlerTH(String& message) {
  message += "URL	" SSL_INFO_NAME "	credentials	token	";
}

void IotsaRequest::formHandlerTD(String& message) {
  message += "";
  message += url;
  message += "	";
  message += sslInfo;
  message += "	";
  message += credentials;
  message += "	";
  message += token;
  message += "	";
}

bool IotsaRequest::formArgHandler(IotsaWebServer *server, String name) {
  bool any = false;
  String wtdName = name + "url";
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), url);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(url);
    any = true;
  }
  wtdName = name + SSL_INFO_NAME;
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), sslInfo);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(sslInfo);
    any = true;
  }
  wtdName = name + "credentials";
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), credentials);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(credentials);
    any = true;
    }
  wtdName = name + "token";
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), token);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(token);
    any = true;
  }
  return any;
}
#endif // IOTSA_WITH_WEB

bool IotsaRequest::send(const char *query) {
  bool rv = true;
  HTTPClient http;
  WiFiClient client;
#ifdef ESP32
  WiFiClientSecure secureClient;
#else
  BearSSL::WiFiClientSecure *secureClientPtr = NULL;
#endif
  String _url = url;
  if (query != NULL && *query != '\0') {
    _url = _url + "?" + query;
  }
  if (_url.startsWith("https:")) {
#ifdef ESP32
    secureClient.setCACert(sslInfo.c_str());
    rv = http.begin(secureClient, _url);
#else
    secureClientPtr = new BearSSL::WiFiClientSecure();
    secureClientPtr->setFingerprint(sslInfo.c_str());

    rv = http.begin(*secureClientPtr, _url);
#endif
  } else {
    rv = http.begin(client, _url);
  }
  if (!rv) {
#ifndef ESP32
    if (secureClientPtr) delete secureClientPtr;
#endif
    return false;
  }
  if (token != "") {
    http.addHeader("Authorization", "Bearer " + token);
  }

  if (credentials != "") {
  	String cred64 = base64::encode(credentials);
    http.addHeader("Authorization", "Basic " + cred64);
  }
  int code = http.GET();
  if (code >= 200 && code <= 299) {
    IFDEBUG IotsaSerial.print(code);
    IFDEBUG IotsaSerial.print(" OK GET ");
    IFDEBUG IotsaSerial.println(_url);
  } else {
    IFDEBUG IotsaSerial.print(code);
    IFDEBUG IotsaSerial.print(" FAIL GET ");
    IFDEBUG IotsaSerial.print(_url);
    if (sslInfo != "") {
#ifdef ESP32
      IFDEBUG IotsaSerial.print(", RootCA ");
#else
      IFDEBUG IotsaSerial.print(", fingerprint ");
#endif
      IFDEBUG IotsaSerial.println(sslInfo);
    }
    rv = false;
  }
  http.end();
#ifndef ESP32
  if (secureClientPtr) delete secureClientPtr;
#endif
  return rv;
}

#ifdef IOTSA_WITH_API
void IotsaRequest::getHandler(JsonObject& reply) {
  reply["url"] = url;
  reply[SSL_INFO_NAME] = sslInfo;
  reply["hasCredentials"] = credentials != "";
  reply["hasToken"] = token != "";
}

bool IotsaRequest::putHandler(const JsonVariant& request) {
  if (!request.is<JsonObject>()) return false;
  bool any = false;
  const JsonObject& reqObj = request.as<JsonObject>();
  if (reqObj.containsKey("url")) {
    any = true;
    url = reqObj["url"].as<String>();
  }
  if (reqObj.containsKey(SSL_INFO_NAME)) {
    any = true;
    sslInfo = reqObj[SSL_INFO_NAME].as<String>();
  }
  if (reqObj.containsKey("credentials")) {
    any = true;
    credentials = reqObj["credentials"].as<String>();
  }
  if (reqObj.containsKey("token")) {
    any = true;
    token = reqObj["token"].as<String>();
  }
  return any;
}
#endif // IOTSA_WITH_API<commit_msg>Bug fixes to iotsaRequest<commit_after>#include "iotsaRequest.h"
#include <base64.h>
#ifdef ESP32
#include <HTTPClient.h>
#else
#include <ESP8266HTTPClient.h>
#endif

#ifdef ESP32
#define SSL_INFO_NAME "rootCA"
#else
#define SSL_INFO_NAME "fingerprint"
#endif

bool IotsaRequest::configLoad(IotsaConfigFileLoad& cf, String& f_name) {
    cf.get(f_name + ".url", url, "");
    cf.get(f_name + "." + SSL_INFO_NAME, sslInfo, "");
    cf.get(f_name + ".credentials", credentials, "");
    cf.get(f_name + ".token", token, "");
    return url != "";
}

void IotsaRequest::configSave(IotsaConfigFileSave& cf, String& f_name) {
    cf.put(f_name + ".url", url);
    cf.put(f_name + "." + SSL_INFO_NAME, sslInfo);
    cf.put(f_name + ".credentials", credentials);
    cf.put(f_name + ".token", token);
}

#ifdef IOTSA_WITH_WEB
void IotsaRequest::formHandler(String& message) {
  message += "Activation URL: <input name='url'>
\n";
#ifdef ESP32
  message += "Root CA cert (https only): <input name='rootCA'>
\n";
#else
  message += "Fingerprint (https only): <input name='fingerprint'>
\n";
#endif

  message += "Bearer token (optional): <input name='token'>
\n";
  message += "Credentials (optional, user:pass): <input name='credentials'>
\n";
}

void IotsaRequest::formHandler(String& message, String& text, String& f_name) {
  message += "Activation URL: <input name='" + f_name +  ".url' value='";
  message += url;
  message += "'>
\n";
#ifdef ESP32
  message += "Root CA cert (https only): <input name='" + f_name + ".rootCA' value='";
  message += sslInfo;
#else
  message += "Fingerprint (https only): <input name='" + f_name +  ".fingerprint' value='";
  message += sslInfo;
#endif
  message += "'>
\n";

  message += "Bearer token (optional): <input name='" + f_name + ".token' value='";
  message += token;
  message += "'>
\n";

  message += "Credentials (optional, user:pass): <input name='" + f_name + ".credentials' value='";
  message += credentials;
  message += "'>
\n";
}

void IotsaRequest::formHandlerTH(String& message) {
  message += "URL	" SSL_INFO_NAME "	credentials	token	";
}

void IotsaRequest::formHandlerTD(String& message) {
  message += "";
  message += url;
  message += "	";
  message += sslInfo;
  message += "	";
  message += credentials;
  message += "	";
  message += token;
  message += "	";
}

bool IotsaRequest::formArgHandler(IotsaWebServer *server, String name) {
  bool any = false;
  String wtdName = name + "url";
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), url);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(url);
    any = true;
  }
  wtdName = name + SSL_INFO_NAME;
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), sslInfo);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(sslInfo);
    any = true;
  }
  wtdName = name + "credentials";
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), credentials);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(credentials);
    any = true;
    }
  wtdName = name + "token";
  if (server->hasArg(wtdName)) {
    IotsaMod::percentDecode(server->arg(wtdName), token);
    IFDEBUG IotsaSerial.print(wtdName);
    IFDEBUG IotsaSerial.print("=");
    IFDEBUG IotsaSerial.println(token);
    any = true;
  }
  return any;
}
#endif // IOTSA_WITH_WEB

bool IotsaRequest::send(const char *query) {
  bool rv = true;
  HTTPClient http;
  WiFiClient client;
#ifdef ESP32
  WiFiClientSecure secureClient;
#else
  BearSSL::WiFiClientSecure *secureClientPtr = NULL;
#endif
  String _url = url;
  if (query != NULL && *query != '\0') {
    if (_url.indexOf('?') > 0) {
      _url = _url + "&" + query;
    } else {
      _url = _url + "?" + query;
    }
  }
  if (_url.startsWith("https:")) {
#ifdef ESP32
    secureClient.setCACert(sslInfo.c_str());
    rv = http.begin(secureClient, _url);
#else
    secureClientPtr = new BearSSL::WiFiClientSecure();
    secureClientPtr->setFingerprint(sslInfo.c_str());

    rv = http.begin(*secureClientPtr, _url);
#endif
  } else {
    rv = http.begin(client, _url);
  }
  if (!rv) {
#ifndef ESP32
    if (secureClientPtr) delete secureClientPtr;
#endif
    return false;
  }
  if (token != "") {
    http.addHeader("Authorization", "Bearer " + token);
  }

  if (credentials != "") {
  	String cred64 = base64::encode(credentials);
    http.addHeader("Authorization", "Basic " + cred64);
  }
  int code = http.GET();
  if (code >= 200 && code <= 299) {
    IFDEBUG IotsaSerial.print(code);
    IFDEBUG IotsaSerial.print(" OK GET ");
    IFDEBUG IotsaSerial.println(_url);
  } else {
    IFDEBUG IotsaSerial.print(code);
    IFDEBUG IotsaSerial.print(" FAIL GET ");
    IFDEBUG IotsaSerial.print(_url);
    if (sslInfo != "") {
#ifdef ESP32
      IFDEBUG IotsaSerial.print(", RootCA ");
#else
      IFDEBUG IotsaSerial.print(", fingerprint ");
#endif
      IFDEBUG IotsaSerial.println(sslInfo);
    }
    rv = false;
  }
  http.end();
#ifndef ESP32
  if (secureClientPtr) delete secureClientPtr;
#endif
  return rv;
}

#ifdef IOTSA_WITH_API
void IotsaRequest::getHandler(JsonObject& reply) {
  reply["url"] = url;
  reply[SSL_INFO_NAME] = sslInfo;
  reply["hasCredentials"] = credentials != "";
  reply["hasToken"] = token != "";
}

bool IotsaRequest::putHandler(const JsonVariant& request) {
  if (!request.is<JsonObject>()) return false;
  bool any = false;
  const JsonObject& reqObj = request.as<JsonObject>();
  if (reqObj.containsKey("url")) {
    any = true;
    url = reqObj["url"].as<String>();
  }
  if (reqObj.containsKey(SSL_INFO_NAME)) {
    any = true;
    sslInfo = reqObj[SSL_INFO_NAME].as<String>();
  }
  if (reqObj.containsKey("credentials")) {
    any = true;
    credentials = reqObj["credentials"].as<String>();
  }
  if (reqObj.containsKey("token")) {
    any = true;
    token = reqObj["token"].as<String>();
  }
  return any;
}
#endif // IOTSA_WITH_API<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007-2009 Digital Bazaar, Inc. All rights reserved.
 */
#include "monarch/mail/MailTemplateParser.h"

#include "monarch/data/TemplateInputStream.h"
#include "monarch/rt/Exception.h"

using namespace std;
using namespace monarch::data;
using namespace monarch::io;
using namespace monarch::mail;
using namespace monarch::rt;

MailTemplateParser::MailTemplateParser()
{
}

MailTemplateParser::~MailTemplateParser()
{
}

/**
 * Parses a single line from the template and adds its contents to the
 * passed Mail either as a header or as a line of the message body.
 * Template variables are replaced according to the passed "vars"
 * DynamicObject and the headers flag is cleared once a blank line
 * has been parsed.
 *
 * @param mail the Mail to populate.
 * @param vars the key-value variables in the template.
 * @param line the line to parse.
 * @param headers the flag to clear once the headers have been parsed.
 * @param bodyEncoded the flag to set if the body should be transfer-encoded.
 *
 * @return true if successful, false if an exception occurred.
 */
static bool parseLine(
   Mail* mail, const char* line, bool& headers, bool& bodyEncoded)
{
   bool rval = true;

   if(headers)
   {
      if(strlen(line) == 0)
      {
         // empty line means last header found
         headers = false;
      }
      else
      {
         // get the header name
         const char* header = strstr(line, ": ");

         // ensure there is a header name and that no white-space occurs in it
         if(header == NULL || (int)strcspn(line, " \t") < (header - line))
         {
            ExceptionRef e = new Exception(
               "Parse error while parsing mail template. Mail header "
               "is malformed or non-existant.",
               "monarch.mail.InvalidHeader");
            Exception::set(e);
            rval = false;
         }
         else
         {
            // see if the header is the subject header
            if(strncasecmp(line, "subject", 7) == 0)
            {
               // subject line found
               mail->setSubject(header + 2);
            }
            else
            {
               // set the header
               char hdr[header - line + 1];
               strncpy(hdr, line, header - line);
               hdr[header - line] = 0;
               mail->setHeader(hdr, header + 2);

               if(!bodyEncoded)
               {
                  bodyEncoded = mail->shouldTransferEncodeBody();
               }
            }
         }
      }
   }
   else
   {
      // append the line to the mail's body
      mail->appendBodyLine(line);
   }

   return rval;
}

bool MailTemplateParser::parse(
   Mail* mail, DynamicObject& vars, bool strict, InputStream* is)
{
   bool rval = true;

   // FIXME: This code can be refactored to do less "cornercase" handling
   // regarding body encoding

   // clear mail
   mail->clear();

   // add template input stream to passed input stream
   TemplateInputStream tis(vars, strict, is, false);

   // SMTP RFC requires lines be no longer than 998 bytes (+2 for CRLF = 1000)
   // so read in a maximum of 1000 bytes at a time
   bool bodyEncoded = mail->shouldTransferEncodeBody();
   string body;
   bool headers = true;
   char b[1001];
   int numBytes;
   int length = 0;
   char* start = 0;
   char* end = 0;
   bool cr = false;

   // read as much as 1000 bytes at a time, then check the read buffer
   while(rval && (numBytes = tis.read(b + length, 1000 - length)) > 0)
   {
      // increment length (number of valid bytes in 'b')
      length += numBytes;

      // ensure line is null-terminated
      b[length] = 0;
      start = b;

      // if using body encoded and headers are finished, append to body string
      if(bodyEncoded && !headers)
      {
         body.append(b);
         length = 0;
      }
      // parse line normally
      else
      {
         // parse lines according to line breaks
         while(rval && (end = strpbrk(start, "\r\n")) != NULL)
         {
            // take note of CR, then insert null-terminator
            cr = (end[0] == '\r');
            end[0] = 0;

            // parse line
            rval = parseLine(mail, start, headers, bodyEncoded);

            // decrement length and increment start skipping LF as appropriate
            // Note: 'b' always ends in 0, so end[1] must always be a valid byte
            // or the null-terminator of b
            int skip = (cr && end[1] == '\n' ? 2 : 1);
            length -= (end - start) + skip;
            start = end + skip;

            if(!headers && bodyEncoded)
            {
               // append rest of data in buffer to body and break
               body.append(start);
               start = b;
               length = 0;
               break;
            }
         }

         if(end == NULL && length > 998)
         {
            // invalid line detected
            numBytes = -1;
            ExceptionRef e = new Exception(
               "Message line too long. SMTP requires that lines be no longer "
               "than 1000 bytes, including the terminating CRLF.",
               "monarch.mail.LineTooLong");
            Exception::set(e);
            rval = false;
         }
         else if(start > b)
         {
            // shift buffer contents as necessary
            memmove(b, start, length + 1);
         }
      }
   }

   if(numBytes < 0)
   {
      rval = false;
   }
   else if(length > 0)
   {
      // if using body encoded and headers are finished, append to body string
      if(bodyEncoded && !headers)
      {
         body.append(b);
      }
      // parse last line normally
      else
      {
         rval = parseLine(mail, b, headers, bodyEncoded);
      }
   }

   // if body is to be encoded, now set it in the mail
   if(bodyEncoded)
   {
      mail->setBody(body.c_str());
   }

   return rval;
}
<commit_msg>Turned on eol strip by default.<commit_after>/*
 * Copyright (c) 2007-2009 Digital Bazaar, Inc. All rights reserved.
 */
#include "monarch/mail/MailTemplateParser.h"

#include "monarch/data/TemplateInputStream.h"
#include "monarch/rt/Exception.h"

using namespace std;
using namespace monarch::data;
using namespace monarch::io;
using namespace monarch::mail;
using namespace monarch::rt;

MailTemplateParser::MailTemplateParser()
{
}

MailTemplateParser::~MailTemplateParser()
{
}

/**
 * Parses a single line from the template and adds its contents to the
 * passed Mail either as a header or as a line of the message body.
 * Template variables are replaced according to the passed "vars"
 * DynamicObject and the headers flag is cleared once a blank line
 * has been parsed.
 *
 * @param mail the Mail to populate.
 * @param vars the key-value variables in the template.
 * @param line the line to parse.
 * @param headers the flag to clear once the headers have been parsed.
 * @param bodyEncoded the flag to set if the body should be transfer-encoded.
 *
 * @return true if successful, false if an exception occurred.
 */
static bool parseLine(
   Mail* mail, const char* line, bool& headers, bool& bodyEncoded)
{
   bool rval = true;

   if(headers)
   {
      if(strlen(line) == 0)
      {
         // empty line means last header found
         headers = false;
      }
      else
      {
         // get the header name
         const char* header = strstr(line, ": ");

         // ensure there is a header name and that no white-space occurs in it
         if(header == NULL || (int)strcspn(line, " \t") < (header - line))
         {
            ExceptionRef e = new Exception(
               "Parse error while parsing mail template. Mail header "
               "is malformed or non-existant.",
               "monarch.mail.InvalidHeader");
            Exception::set(e);
            rval = false;
         }
         else
         {
            // see if the header is the subject header
            if(strncasecmp(line, "subject", 7) == 0)
            {
               // subject line found
               mail->setSubject(header + 2);
            }
            else
            {
               // set the header
               char hdr[header - line + 1];
               strncpy(hdr, line, header - line);
               hdr[header - line] = 0;
               mail->setHeader(hdr, header + 2);

               if(!bodyEncoded)
               {
                  bodyEncoded = mail->shouldTransferEncodeBody();
               }
            }
         }
      }
   }
   else
   {
      // append the line to the mail's body
      mail->appendBodyLine(line);
   }

   return rval;
}

bool MailTemplateParser::parse(
   Mail* mail, DynamicObject& vars, bool strict, InputStream* is)
{
   bool rval = true;

   // FIXME: This code can be refactored to do less "cornercase" handling
   // regarding body encoding

   // clear mail
   mail->clear();

   // add template input stream to passed input stream
   TemplateInputStream tis(vars, strict, is, false);
   tis.setStripStartingEol(true);

   // SMTP RFC requires lines be no longer than 998 bytes (+2 for CRLF = 1000)
   // so read in a maximum of 1000 bytes at a time
   bool bodyEncoded = mail->shouldTransferEncodeBody();
   string body;
   bool headers = true;
   char b[1001];
   int numBytes;
   int length = 0;
   char* start = 0;
   char* end = 0;
   bool cr = false;

   // read as much as 1000 bytes at a time, then check the read buffer
   while(rval && (numBytes = tis.read(b + length, 1000 - length)) > 0)
   {
      // increment length (number of valid bytes in 'b')
      length += numBytes;

      // ensure line is null-terminated
      b[length] = 0;
      start = b;

      // if using body encoded and headers are finished, append to body string
      if(bodyEncoded && !headers)
      {
         body.append(b);
         length = 0;
      }
      // parse line normally
      else
      {
         // parse lines according to line breaks
         while(rval && (end = strpbrk(start, "\r\n")) != NULL)
         {
            // take note of CR, then insert null-terminator
            cr = (end[0] == '\r');
            end[0] = 0;

            // parse line
            rval = parseLine(mail, start, headers, bodyEncoded);

            // decrement length and increment start skipping LF as appropriate
            // Note: 'b' always ends in 0, so end[1] must always be a valid byte
            // or the null-terminator of b
            int skip = (cr && end[1] == '\n' ? 2 : 1);
            length -= (end - start) + skip;
            start = end + skip;

            if(!headers && bodyEncoded)
            {
               // append rest of data in buffer to body and break
               body.append(start);
               start = b;
               length = 0;
               break;
            }
         }

         if(end == NULL && length > 998)
         {
            // invalid line detected
            numBytes = -1;
            ExceptionRef e = new Exception(
               "Message line too long. SMTP requires that lines be no longer "
               "than 1000 bytes, including the terminating CRLF.",
               "monarch.mail.LineTooLong");
            Exception::set(e);
            rval = false;
         }
         else if(start > b)
         {
            // shift buffer contents as necessary
            memmove(b, start, length + 1);
         }
      }
   }

   if(numBytes < 0)
   {
      rval = false;
   }
   else if(length > 0)
   {
      // if using body encoded and headers are finished, append to body string
      if(bodyEncoded && !headers)
      {
         body.append(b);
      }
      // parse last line normally
      else
      {
         rval = parseLine(mail, b, headers, bodyEncoded);
      }
   }

   // if body is to be encoded, now set it in the mail
   if(bodyEncoded)
   {
      mail->setBody(body.c_str());
   }

   return rval;
}
<|endoftext|>


<commit_before><commit_msg>removed energy normalization<commit_after><|endoftext|>