<commit_before>#include "types.h"
#include "amd64.h"
#include "mmu.h"
#include "cpu.hh"
#include "kernel.hh"
#include "bits.hh"
#include "spinlock.h"
#include "kalloc.h"
#include "queue.h"
#include "condvar.h"
#include "proc.hh"
#include "vm.hh"
#include "gc.hh"
#include "crange.hh"
#include "cpputil.hh"

enum { vm_debug = 0 };

/*
 * vmnode
 */

vmnode::vmnode(u64 npg, vmntype ntype)
  : npages(npg), ref(0), type(ntype), ip(0), offset(0), sz(0)
{
  if (npg > NELEM(page))
    panic("vmnode too big\n");
  memset(page, 0, sizeof(page));
  if (type == EAGER)
    assert(allocpg() == 0);
}

vmnode::~vmnode()
{
  for(u64 i = 0; i < npages; i++) {
    if (page[i]) {
      kfree(page[i]);
      page[i] = 0;
    }
  }
  if (ip) {
    iput(ip);
    ip = 0;
  }
}

void
vmnode::decref()
{
  if(--ref == 0)
    delete this;
}

int
vmnode::allocpg()
{
  for(u64 i = 0; i < npages; i++) {
    if((page[i] = kalloc()) == 0)
      return -1;
    memset((char *) page[i], 0, PGSIZE);
  }
  return 0;
}

vmnode *
vmnode::copy()
{
  vmnode *c = new vmnode(npages, type);
  if(c != 0) {
    c->type = type;
    if (type == ONDEMAND) {
      c->ip = idup(ip);
      c->offset = offset;
      c->sz = c->sz;
    }
    if (page[0]) {   // If the first page is present, all of them are present
      if (c->allocpg() < 0) {
	cprintf("vmn_copy: out of memory\n");
	delete c;
	return 0;
      }
      for(u64 i = 0; i < npages; i++) {
	memmove(c->page[i], page[i], PGSIZE);
      }
    }
  }
  return c;
}

int
vmnode::demand_load()
{
  for (u64 i = 0; i < sz; i += PGSIZE) {
    char *p = page[i / PGSIZE];
    s64 n;
    if (sz - i < PGSIZE)
      n = sz - i;
    else
      n = PGSIZE;
    if (readi(ip, p, offset+i, n) != n)
      return -1;
  }
  return 0;
}

int
vmnode::load(inode *iparg, u64 offarg, u64 szarg)
{
  ip = iparg;
  offset = offarg;
  sz = szarg;

  if (type == ONDEMAND)
    return 0;
  return demand_load();
}

/*
 * vma
 */

vma::vma(vmap *vmap, uptr start, uptr end, enum vmatype vtype, vmnode *vmn)
  : range(&vmap->cr, start, end-start),
    vma_start(start), vma_end(end), va_type(vtype), n(vmn)
{
  if (n)
    n->ref++;
}

vma::~vma()
{
  if (n)
    n->decref();
}

/*
 * vmap
 */

vmap::vmap()
  : cr(10), pml4(setupkvm()), kshared((char*) ksalloc(slab_kshared))
{
  ref = 1;
  alloc = 0;

  if (pml4 == 0) {
    cprintf("vmap_alloc: setupkvm out of memory\n");
    goto err;
  }

  if (kshared == NULL) {
    cprintf("vmap::vmap: kshared out of memory\n");
    goto err;
  }

  if (setupkshared(pml4, kshared)) {
    cprintf("vmap::vmap: setupkshared out of memory\n");
    goto err;
  }

  return;

 err:
  if (kshared)
    ksfree(slab_kshared, kshared);
  if (pml4)
    freevm(pml4);
}

vmap::~vmap()
{
  if (kshared)
    ksfree(slab_kshared, kshared);
  if (pml4)
    freevm(pml4);
  alloc = 0;
}

void
vmap::decref()
{
  if (--ref == 0)
    delete this;
}

bool
vmap::replace_vma(vma *a, vma *b)
{
  auto span = cr.search_lock(a->vma_start, a->vma_end - a->vma_start);
  if (a->deleted())
    return false;
  for (auto e: span)
    assert(a == e);
  span.replace(b);
  return true;
}

vmap*
vmap::copy(int share)
{
  vmap *nm = new vmap();
  if(nm == 0)
    return 0;

  for (range *r: cr) {
    vma *e = (vma *) r;

    struct vma *ne;
    if (share) {
      ne = new vma(nm, e->vma_start, e->vma_end, COW, e->n);

      // if the original vma wasn't COW, replace it with a COW vma
      if (e->va_type != COW) {
        vma *repl = new vma(this, e->vma_start, e->vma_end, COW, e->n);
        replace_vma(e, repl);
        updatepages(pml4, e->vma_start, e->vma_end, [](atomic<pme_t>* p) {
            for (;;) {
              pme_t v = p->load();
              if (v & PTE_LOCK)
                continue;
              if (!(v & PTE_P) || !(v & PTE_U) || !(v & PTE_W) ||
                  cmpxch(p, v, PTE_ADDR(v) | PTE_P | PTE_U | PTE_COW))
                break;
            }
          });
      }
    } else {
      ne = new vma(nm, e->vma_start, e->vma_end, PRIVATE, e->n->copy());
    }

    if (ne == 0)
      goto err;

    if (ne->n == 0) {
      delete ne;
      goto err;
    }

    auto span = nm->cr.search_lock(ne->vma_start, ne->vma_end - ne->vma_start);
    for (auto x __attribute__((unused)): span)
      assert(0);  /* span must be empty */
    span.replace(ne);
  }

  if (share) {
    // XXX should really be tlbflush(), but callers hold some locks..
    lcr3(rcr3());  // Reload hardware page table
  }

  return nm;

 err:
  delete nm;
  return 0;
}

// Does any vma overlap start..start+len?
// If yes, return the vma pointer.
// If no, return 0.
// This code can't handle regions at the very end
// of the address space, e.g. 0xffffffff..0x0
// We key vma's by their end address.
vma *
vmap::lookup(uptr start, uptr len)
{
  if (start + len < start)
    panic("vmap::lookup bad len");

  range *r = cr.search(start, len);
  if (r != 0) {
    vma *e = (vma *) r;
    if (e->vma_end <= e->vma_start)
      panic("malformed va");
    if (e->vma_start < start+len && e->vma_end > start)
      return e;
  }

  return 0;
}

int
vmap::insert(vmnode *n, uptr vma_start)
{
  vma *e;

  {
    // new scope to release the search lock before tlbflush
    u64 len = n->npages * PGSIZE;
    auto span = cr.search_lock(vma_start, len);
    for (auto r: span) {
      vma *rvma = (vma*) r;
      cprintf("vmap::insert: overlap with 0x%lx--0x%lx\n", rvma->vma_start, rvma->vma_end);
      return -1;
    }

    // XXX handle overlaps

    e = new vma(this, vma_start, vma_start+len, PRIVATE, n);
    if (e == 0) {
      cprintf("vmap::insert: out of vmas\n");
      return -1;
    }

    span.replace(e);
  }

  updatepages(pml4, e->vma_start, e->vma_end, [](atomic<pme_t> *p) {
      for (;;) {
        pme_t v = p->load();
        if (v & PTE_LOCK)
          continue;
        if (cmpxch(p, v, (pme_t) 0))
          break;
      }
    });
  tlbflush();
  return 0;
}

int
vmap::remove(uptr vma_start, uptr len)
{
  {
    // new scope to release the search lock before tlbflush
    uptr vma_end = vma_start + len;

    auto span = cr.search_lock(vma_start, len);
    for (auto r: span) {
      vma *rvma = (vma*) r;
      if (rvma->vma_start < vma_start || rvma->vma_end > vma_end) {
        cprintf("vmap::remove: partial unmap not supported\n");
        return -1;
      }
    }

    // XXX handle partial unmap

    span.replace(0);
  }

  updatepages(pml4, vma_start, vma_start + len, [](atomic<pme_t> *p) {
      for (;;) {
        pme_t v = p->load();
        if (v & PTE_LOCK)
          continue;
        if (cmpxch(p, v, (pme_t) 0))
          break;
      }
    });
  tlbflush();
  return 0;
}

/*
 * pagefault handling code on vmap
 */

int
vmap::pagefault_wcow(vma *m)
{
  // Always make a copy of n, even if this process has the only ref,
  // because other processes may change ref count while this process
  // is handling wcow.
  struct vmnode *nodecopy = m->n->copy();
  if (nodecopy == 0) {
    cprintf("pagefault_wcow: out of mem\n");
    return -1;
  }

  vma *repl = new vma(this, m->vma_start, m->vma_end, PRIVATE, nodecopy);

  replace_vma(m, repl);
  updatepages(pml4, m->vma_start, m->vma_end, [](atomic<pme_t> *p) {
      for (;;) {
        pme_t v = p->load();
        if (v & PTE_LOCK)
          continue;
        if (cmpxch(p, v, (pme_t) 0))
          break;
      }
    });

  return 0;
}

int
vmap::pagefault(uptr va, u32 err)
{
  atomic<pme_t> *pte = walkpgdir(pml4, va, 1);

 retry:
  pme_t ptev = pte->load();

  // optimize checks of args to syscals
  if ((ptev & (PTE_P|PTE_U|PTE_W)) == (PTE_P|PTE_U|PTE_W)) {
    // XXX using pagefault() as a security check in syscalls is prone to races
    return 0;
  }

  if (ptev & PTE_LOCK) {
    // locked, might as well wait for the other pagefaulting core..
    goto retry;
  }

  scoped_gc_epoch gc;
  vma *m = lookup(va, 1);
  if (m == 0)
    return -1;

  u64 npg = (PGROUNDDOWN(va) - m->vma_start) / PGSIZE;
  if (vm_debug)
    cprintf("pagefault: err 0x%x va 0x%lx type %d ref %lu pid %d\n",
            err, va, m->va_type, m->n->ref.load(), myproc()->pid);

  if (m->n && m->n->type == ONDEMAND && m->n->page[npg] == 0) {
    if (m->n->allocpg() < 0)
      panic("pagefault: couldn't allocate pages");
    if (m->n->demand_load() < 0)
      panic("pagefault: couldn't load");
  }

  if (m->va_type == COW && (err & FEC_WR)) {
    if (pagefault_wcow(m) < 0)
      return -1;

    tlbflush();
    goto retry;
  }

  if (!cmpxch(pte, ptev, ptev | PTE_LOCK))
    goto retry;

  if (m->deleted()) {
    *pte = ptev;
    goto retry;
  }

  if (m->va_type == COW) {
    *pte = v2p(m->n->page[npg]) | PTE_P | PTE_U | PTE_COW;
  } else {
    assert(m->n->ref == 1);
    *pte = v2p(m->n->page[npg]) | PTE_P | PTE_U | PTE_W;
  }

  return 1;
}

int
pagefault(struct vmap *vmap, uptr va, u32 err)
{
  return vmap->pagefault(va, err);
}

// Copy len bytes from p to user address va in vmap.
// Most useful when vmap is not the current page table.
int
vmap::copyout(uptr va, void *p, u64 len)
{
  char *buf = (char*)p;
  while(len > 0){
    uptr va0 = (uptr)PGROUNDDOWN(va);
    scoped_gc_epoch gc;
    vma *vma = lookup(va, 1);
    if(vma == 0)
      return -1;

    uptr pn = (va0 - vma->vma_start) / PGSIZE;
    char *p0 = vma->n->page[pn];
    if(p0 == 0)
      panic("copyout: missing page");
    uptr n = PGSIZE - (va - va0);
    if(n > len)
      n = len;
    memmove(p0 + (va - va0), buf, n);
    len -= n;
    buf += n;
    va = va0 + PGSIZE;
  }
  return 0;
}
<commit_msg>no vmap lock means we can do a proper tlbflush()<commit_after>#include "types.h"
#include "amd64.h"
#include "mmu.h"
#include "cpu.hh"
#include "kernel.hh"
#include "bits.hh"
#include "spinlock.h"
#include "kalloc.h"
#include "queue.h"
#include "condvar.h"
#include "proc.hh"
#include "vm.hh"
#include "gc.hh"
#include "crange.hh"
#include "cpputil.hh"

enum { vm_debug = 0 };

/*
 * vmnode
 */

vmnode::vmnode(u64 npg, vmntype ntype)
  : npages(npg), ref(0), type(ntype), ip(0), offset(0), sz(0)
{
  if (npg > NELEM(page))
    panic("vmnode too big\n");
  memset(page, 0, sizeof(page));
  if (type == EAGER)
    assert(allocpg() == 0);
}

vmnode::~vmnode()
{
  for(u64 i = 0; i < npages; i++) {
    if (page[i]) {
      kfree(page[i]);
      page[i] = 0;
    }
  }
  if (ip) {
    iput(ip);
    ip = 0;
  }
}

void
vmnode::decref()
{
  if(--ref == 0)
    delete this;
}

int
vmnode::allocpg()
{
  for(u64 i = 0; i < npages; i++) {
    if((page[i] = kalloc()) == 0)
      return -1;
    memset((char *) page[i], 0, PGSIZE);
  }
  return 0;
}

vmnode *
vmnode::copy()
{
  vmnode *c = new vmnode(npages, type);
  if(c != 0) {
    c->type = type;
    if (type == ONDEMAND) {
      c->ip = idup(ip);
      c->offset = offset;
      c->sz = c->sz;
    }
    if (page[0]) {   // If the first page is present, all of them are present
      if (c->allocpg() < 0) {
	cprintf("vmn_copy: out of memory\n");
	delete c;
	return 0;
      }
      for(u64 i = 0; i < npages; i++) {
	memmove(c->page[i], page[i], PGSIZE);
      }
    }
  }
  return c;
}

int
vmnode::demand_load()
{
  for (u64 i = 0; i < sz; i += PGSIZE) {
    char *p = page[i / PGSIZE];
    s64 n;
    if (sz - i < PGSIZE)
      n = sz - i;
    else
      n = PGSIZE;
    if (readi(ip, p, offset+i, n) != n)
      return -1;
  }
  return 0;
}

int
vmnode::load(inode *iparg, u64 offarg, u64 szarg)
{
  ip = iparg;
  offset = offarg;
  sz = szarg;

  if (type == ONDEMAND)
    return 0;
  return demand_load();
}

/*
 * vma
 */

vma::vma(vmap *vmap, uptr start, uptr end, enum vmatype vtype, vmnode *vmn)
  : range(&vmap->cr, start, end-start),
    vma_start(start), vma_end(end), va_type(vtype), n(vmn)
{
  if (n)
    n->ref++;
}

vma::~vma()
{
  if (n)
    n->decref();
}

/*
 * vmap
 */

vmap::vmap()
  : cr(10), pml4(setupkvm()), kshared((char*) ksalloc(slab_kshared))
{
  ref = 1;
  alloc = 0;

  if (pml4 == 0) {
    cprintf("vmap_alloc: setupkvm out of memory\n");
    goto err;
  }

  if (kshared == NULL) {
    cprintf("vmap::vmap: kshared out of memory\n");
    goto err;
  }

  if (setupkshared(pml4, kshared)) {
    cprintf("vmap::vmap: setupkshared out of memory\n");
    goto err;
  }

  return;

 err:
  if (kshared)
    ksfree(slab_kshared, kshared);
  if (pml4)
    freevm(pml4);
}

vmap::~vmap()
{
  if (kshared)
    ksfree(slab_kshared, kshared);
  if (pml4)
    freevm(pml4);
  alloc = 0;
}

void
vmap::decref()
{
  if (--ref == 0)
    delete this;
}

bool
vmap::replace_vma(vma *a, vma *b)
{
  auto span = cr.search_lock(a->vma_start, a->vma_end - a->vma_start);
  if (a->deleted())
    return false;
  for (auto e: span)
    assert(a == e);
  span.replace(b);
  return true;
}

vmap*
vmap::copy(int share)
{
  vmap *nm = new vmap();
  if(nm == 0)
    return 0;

  for (range *r: cr) {
    vma *e = (vma *) r;

    struct vma *ne;
    if (share) {
      ne = new vma(nm, e->vma_start, e->vma_end, COW, e->n);

      // if the original vma wasn't COW, replace it with a COW vma
      if (e->va_type != COW) {
        vma *repl = new vma(this, e->vma_start, e->vma_end, COW, e->n);
        replace_vma(e, repl);
        updatepages(pml4, e->vma_start, e->vma_end, [](atomic<pme_t>* p) {
            for (;;) {
              pme_t v = p->load();
              if (v & PTE_LOCK)
                continue;
              if (!(v & PTE_P) || !(v & PTE_U) || !(v & PTE_W) ||
                  cmpxch(p, v, PTE_ADDR(v) | PTE_P | PTE_U | PTE_COW))
                break;
            }
          });
      }
    } else {
      ne = new vma(nm, e->vma_start, e->vma_end, PRIVATE, e->n->copy());
    }

    if (ne == 0)
      goto err;

    if (ne->n == 0) {
      delete ne;
      goto err;
    }

    auto span = nm->cr.search_lock(ne->vma_start, ne->vma_end - ne->vma_start);
    for (auto x __attribute__((unused)): span)
      assert(0);  /* span must be empty */
    span.replace(ne);
  }

  if (share)
    tlbflush();  // Reload hardware page table

  return nm;

 err:
  delete nm;
  return 0;
}

// Does any vma overlap start..start+len?
// If yes, return the vma pointer.
// If no, return 0.
// This code can't handle regions at the very end
// of the address space, e.g. 0xffffffff..0x0
// We key vma's by their end address.
vma *
vmap::lookup(uptr start, uptr len)
{
  if (start + len < start)
    panic("vmap::lookup bad len");

  range *r = cr.search(start, len);
  if (r != 0) {
    vma *e = (vma *) r;
    if (e->vma_end <= e->vma_start)
      panic("malformed va");
    if (e->vma_start < start+len && e->vma_end > start)
      return e;
  }

  return 0;
}

int
vmap::insert(vmnode *n, uptr vma_start)
{
  vma *e;

  {
    // new scope to release the search lock before tlbflush
    u64 len = n->npages * PGSIZE;
    auto span = cr.search_lock(vma_start, len);
    for (auto r: span) {
      vma *rvma = (vma*) r;
      cprintf("vmap::insert: overlap with 0x%lx--0x%lx\n", rvma->vma_start, rvma->vma_end);
      return -1;
    }

    // XXX handle overlaps

    e = new vma(this, vma_start, vma_start+len, PRIVATE, n);
    if (e == 0) {
      cprintf("vmap::insert: out of vmas\n");
      return -1;
    }

    span.replace(e);
  }

  updatepages(pml4, e->vma_start, e->vma_end, [](atomic<pme_t> *p) {
      for (;;) {
        pme_t v = p->load();
        if (v & PTE_LOCK)
          continue;
        if (cmpxch(p, v, (pme_t) 0))
          break;
      }
    });
  tlbflush();
  return 0;
}

int
vmap::remove(uptr vma_start, uptr len)
{
  {
    // new scope to release the search lock before tlbflush
    uptr vma_end = vma_start + len;

    auto span = cr.search_lock(vma_start, len);
    for (auto r: span) {
      vma *rvma = (vma*) r;
      if (rvma->vma_start < vma_start || rvma->vma_end > vma_end) {
        cprintf("vmap::remove: partial unmap not supported\n");
        return -1;
      }
    }

    // XXX handle partial unmap

    span.replace(0);
  }

  updatepages(pml4, vma_start, vma_start + len, [](atomic<pme_t> *p) {
      for (;;) {
        pme_t v = p->load();
        if (v & PTE_LOCK)
          continue;
        if (cmpxch(p, v, (pme_t) 0))
          break;
      }
    });
  tlbflush();
  return 0;
}

/*
 * pagefault handling code on vmap
 */

int
vmap::pagefault_wcow(vma *m)
{
  // Always make a copy of n, even if this process has the only ref,
  // because other processes may change ref count while this process
  // is handling wcow.
  struct vmnode *nodecopy = m->n->copy();
  if (nodecopy == 0) {
    cprintf("pagefault_wcow: out of mem\n");
    return -1;
  }

  vma *repl = new vma(this, m->vma_start, m->vma_end, PRIVATE, nodecopy);

  replace_vma(m, repl);
  updatepages(pml4, m->vma_start, m->vma_end, [](atomic<pme_t> *p) {
      for (;;) {
        pme_t v = p->load();
        if (v & PTE_LOCK)
          continue;
        if (cmpxch(p, v, (pme_t) 0))
          break;
      }
    });

  return 0;
}

int
vmap::pagefault(uptr va, u32 err)
{
  atomic<pme_t> *pte = walkpgdir(pml4, va, 1);

 retry:
  pme_t ptev = pte->load();

  // optimize checks of args to syscals
  if ((ptev & (PTE_P|PTE_U|PTE_W)) == (PTE_P|PTE_U|PTE_W)) {
    // XXX using pagefault() as a security check in syscalls is prone to races
    return 0;
  }

  if (ptev & PTE_LOCK) {
    // locked, might as well wait for the other pagefaulting core..
    goto retry;
  }

  scoped_gc_epoch gc;
  vma *m = lookup(va, 1);
  if (m == 0)
    return -1;

  u64 npg = (PGROUNDDOWN(va) - m->vma_start) / PGSIZE;
  if (vm_debug)
    cprintf("pagefault: err 0x%x va 0x%lx type %d ref %lu pid %d\n",
            err, va, m->va_type, m->n->ref.load(), myproc()->pid);

  if (m->n && m->n->type == ONDEMAND && m->n->page[npg] == 0) {
    if (m->n->allocpg() < 0)
      panic("pagefault: couldn't allocate pages");
    if (m->n->demand_load() < 0)
      panic("pagefault: couldn't load");
  }

  if (m->va_type == COW && (err & FEC_WR)) {
    if (pagefault_wcow(m) < 0)
      return -1;

    tlbflush();
    goto retry;
  }

  if (!cmpxch(pte, ptev, ptev | PTE_LOCK))
    goto retry;

  if (m->deleted()) {
    *pte = ptev;
    goto retry;
  }

  if (m->va_type == COW) {
    *pte = v2p(m->n->page[npg]) | PTE_P | PTE_U | PTE_COW;
  } else {
    assert(m->n->ref == 1);
    *pte = v2p(m->n->page[npg]) | PTE_P | PTE_U | PTE_W;
  }

  return 1;
}

int
pagefault(struct vmap *vmap, uptr va, u32 err)
{
  return vmap->pagefault(va, err);
}

// Copy len bytes from p to user address va in vmap.
// Most useful when vmap is not the current page table.
int
vmap::copyout(uptr va, void *p, u64 len)
{
  char *buf = (char*)p;
  while(len > 0){
    uptr va0 = (uptr)PGROUNDDOWN(va);
    scoped_gc_epoch gc;
    vma *vma = lookup(va, 1);
    if(vma == 0)
      return -1;

    uptr pn = (va0 - vma->vma_start) / PGSIZE;
    char *p0 = vma->n->page[pn];
    if(p0 == 0)
      panic("copyout: missing page");
    uptr n = PGSIZE - (va - va0);
    if(n > len)
      n = len;
    memmove(p0 + (va - va0), buf, n);
    len -= n;
    buf += n;
    va = va0 + PGSIZE;
  }
  return 0;
}
<|endoftext|>


<commit_before>#include <specs/util/argv_helper.h>
#include <specs/specs.h>

using namespace bandit::specs::util;
namespace bd = bandit::detail;

static void all_ok(const bd::options &opt) {
  AssertThat(opt.parsed_ok(), IsTrue());
  AssertThat(opt.has_further_arguments(), IsFalse());
  AssertThat(opt.has_unknown_options(), IsFalse());
}

go_bandit([](){

    describe("options:", [&](){

      it("parses the '--help' option", [&](){
        argv_helper argv({"--help"});

        bd::options opt(argv.argc(), argv.argv());

        AssertThat(opt.help(), IsTrue());
        all_ok(opt);
      });

      it("parses the '--version' option", [&](){
        argv_helper argv({"--version"});

        bd::options opt(argv.argc(), argv.argv());

        AssertThat(opt.version(), IsTrue());
        all_ok(opt);
      });

      it("parses the '--no-color' option", [&](){
        argv_helper argv({"--no-color"});

        bd::options opt(argv.argc(), argv.argv());

        AssertThat(opt.no_color(), IsTrue());
        all_ok(opt);
      });

      it("parses the '--formatter=vs' option", [&](){
        argv_helper argv({"--formatter=vs"});

        bd::options opt(argv.argc(), argv.argv());
        AssertThat(opt.formatter(), Equals(bd::options::formatters::FORMATTER_VS));
        all_ok(opt);
      });

      it("parses the '--formatter=default' option", [&](){
        argv_helper argv({"--formatter=default"});

        bd::options opt(argv.argc(), argv.argv());
        AssertThat(opt.formatter(), Equals(bd::options::formatters::FORMATTER_DEFAULT));
        all_ok(opt);
      });

      it("parses the '--skip=\"substring\"' option", [&](){
        argv_helper argv({"--skip=substring"});

        bd::options opt(argv.argc(), argv.argv());
        AssertThat(opt.skip(), Equals("substring"));
        all_ok(opt);
      });

      it("parses skip as empty string if not present", [&](){
        argv_helper argv({});

        bd::options opt(argv.argc(), argv.argv());
        AssertThat(opt.skip(), Equals(""));
        all_ok(opt);
      });

      it("parses the '--only=\"substring\"' option", [&](){
        argv_helper argv({"--only=substring"});

        bd::options opt(argv.argc(), argv.argv());
        AssertThat(opt.only(), Equals("substring"));
        all_ok(opt);
      });

      it("parses only as empty string if not present", [&](){
        argv_helper argv({});

        bd::options opt(argv.argc(), argv.argv());
        AssertThat(opt.only(), Equals(""));
        all_ok(opt);
      });

      it("parses the '--break-on-failure' option", [&](){
        argv_helper argv({"--break-on-failure"});

        bd::options opt(argv.argc(), argv.argv());

        AssertThat(opt.break_on_failure(), IsTrue());
        all_ok(opt);
      });

      it("parses the '--dry-run' option", [&](){
        argv_helper argv({"--dry-run"});

        bd::options opt(argv.argc(), argv.argv());

        AssertThat(opt.dry_run(), IsTrue());
        all_ok(opt);
      });

      describe("with no arguments", [&](){
        argv_helper argv({});
        bd::options opt(argv.argc(), argv.argv());

        it("is valid", [&] {
          all_ok(opt);
        });

        it("cannot find '--help'", [&](){
          AssertThat(opt.help(), IsFalse());
        });

        it("cannot find '--version'", [&](){
          AssertThat(opt.version(), IsFalse());
        });

        it("cannot find '--no-color'", [&](){
          AssertThat(opt.no_color(), IsFalse());
        });

        it("cannot find '--break-on-failure'", [&](){
          AssertThat(opt.break_on_failure(), IsFalse())
        });

        it("cannot find '--dry-run'", [&](){
          AssertThat(opt.dry_run(), IsFalse())
        });

        it("uses default formatter for '--formatter'", [&](){
          AssertThat(opt.formatter(), Equals(bd::options::formatters::FORMATTER_DEFAULT));
        });
      });
    });

});
<commit_msg>Make options spec more concise<commit_after>#include <specs/util/argv_helper.h>
#include <specs/specs.h>

using namespace bandit::specs::util;
namespace bd = bandit::detail;

static void all_ok(const bd::options &opt) {
  AssertThat(opt.parsed_ok(), IsTrue());
  AssertThat(opt.has_further_arguments(), IsFalse());
  AssertThat(opt.has_unknown_options(), IsFalse());
}

struct options : private argv_helper, public bd::options {
  options(std::list<std::string>&& args)
    : argv_helper(std::move(args))
    , bd::options(argc(), argv())
  {}
};

go_bandit([](){

    describe("options:", [&](){

      it("parses the '--help' option", [&](){
        options opt({"--help"});
        AssertThat(opt.help(), IsTrue());
        all_ok(opt);
      });

      it("parses the '--version' option", [&](){
        options opt({"--version"});
        AssertThat(opt.version(), IsTrue());
        all_ok(opt);
      });

      it("parses the '--no-color' option", [&](){
        options opt({"--no-color"});
        AssertThat(opt.no_color(), IsTrue());
        all_ok(opt);
      });

      it("parses the '--formatter=vs' option", [&](){
        options opt({"--formatter=vs"});
        AssertThat(opt.formatter(), Equals(bd::options::formatters::FORMATTER_VS));
        all_ok(opt);
      });

      it("parses the '--formatter=default' option", [&](){
        options opt({"--formatter=default"});
        AssertThat(opt.formatter(), Equals(bd::options::formatters::FORMATTER_DEFAULT));
        all_ok(opt);
      });

      it("parses the '--skip=\"substring\"' option", [&](){
        options opt({"--skip=substring"});
        AssertThat(opt.skip(), Equals("substring"));
        all_ok(opt);
      });

      it("parses skip as empty string if not present", [&](){
        options opt({});
        AssertThat(opt.skip(), Equals(""));
        all_ok(opt);
      });

      it("parses the '--only=\"substring\"' option", [&](){
        options opt({"--only=substring"});
        AssertThat(opt.only(), Equals("substring"));
        all_ok(opt);
      });

      it("parses only as empty string if not present", [&](){
        options opt({});
        AssertThat(opt.only(), Equals(""));
        all_ok(opt);
      });

      it("parses the '--break-on-failure' option", [&](){
        options opt({"--break-on-failure"});
        AssertThat(opt.break_on_failure(), IsTrue());
        all_ok(opt);
      });

      it("parses the '--dry-run' option", [&](){
        options opt({"--dry-run"});
        AssertThat(opt.dry_run(), IsTrue());
        all_ok(opt);
      });

      describe("with no arguments", [&](){
        options opt({});

        it("is valid", [&] {
          all_ok(opt);
        });

        it("cannot find '--help'", [&](){
          AssertThat(opt.help(), IsFalse());
        });

        it("cannot find '--version'", [&](){
          AssertThat(opt.version(), IsFalse());
        });

        it("cannot find '--no-color'", [&](){
          AssertThat(opt.no_color(), IsFalse());
        });

        it("cannot find '--break-on-failure'", [&](){
          AssertThat(opt.break_on_failure(), IsFalse())
        });

        it("cannot find '--dry-run'", [&](){
          AssertThat(opt.dry_run(), IsFalse())
        });

        it("uses default formatter for '--formatter'", [&](){
          AssertThat(opt.formatter(), Equals(bd::options::formatters::FORMATTER_DEFAULT));
        });
      });
    });

});
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: NeonPropFindRequest.cxx,v $
 *
 *  $Revision: 1.19 $
 *
 *  last change: $Author: rt $ $Date: 2007-07-03 12:13:17 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_ucb.hxx"

#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif

#ifndef _NEONTYPES_HXX_
#include "NeonTypes.hxx"
#endif
#ifndef _DAVEXCEPTION_HXX_
#include "DAVException.hxx"
#endif
#ifndef _DAVPROPERTIES_HXX_
#include "DAVProperties.hxx"
#endif
#ifndef _NEONPROPFINDREQUEST_HXX_
#include "NeonPropFindRequest.hxx"
#endif
#ifndef _LINKSEQUENCE_HXX_
#include "LinkSequence.hxx"
#endif
#ifndef _LOCKSEQUENCE_HXX_
#include "LockSequence.hxx"
#endif
#ifndef _LOCKENTRYSEQUENCE_HXX_
#include "LockEntrySequence.hxx"
#endif
#ifndef _UCBDEADPROPERTYVALUE_HXX_
#include "UCBDeadPropertyValue.hxx"
#endif

using namespace rtl;
using namespace com::sun::star::uno;
using namespace com::sun::star::ucb;
using namespace std;
using namespace webdav_ucp;

// -------------------------------------------------------------------
extern "C" int NPFR_propfind_iter( void* userdata,
                                   const NeonPropName* pname,
                                   const char* value,
                                   const HttpStatus* status )
{
    /*
        HTTP Response Status Classes:

          - 1: Informational - Request received, continuing process

          - 2: Success - The action was successfully received,
          understood, and accepted

        - 3: Redirection - Further action must be taken in order to
          complete the request

        - 4: Client Error - The request contains bad syntax or cannot
          be fulfilled

        - 5: Server Error - The server failed to fulfill an apparently
          valid request
    */

    if ( status->klass > 2 )
        return 0; // Error getting this property. Go on.

    // Create & set the PropertyValue
    DAVPropertyValue thePropertyValue;
    thePropertyValue.IsCaseSensitive = true;

    DAVProperties::createUCBPropName( pname->nspace,
                                        pname->name,
                                        thePropertyValue.Name );
    bool bHasValue = false;
    if ( DAVProperties::isUCBDeadProperty( *pname ) )
    {
        // DAV dead property added by WebDAV UCP?
        if ( UCBDeadPropertyValue::createFromXML(
                                        value, thePropertyValue.Value ) )
            OSL_ENSURE( thePropertyValue.Value.hasValue(),
                        "NeonPropFindRequest::propfind_iter - No value!" );
            bHasValue = true;
    }

    if ( !bHasValue )
    {
        if ( rtl_str_compareIgnoreAsciiCase(
                                    pname->name, "resourcetype" ) == 0 )
        {
            OString aValue( value );
            aValue = aValue.trim(); // #107358# remove leading/trailing spaces
            if ( aValue.getLength() )
            {
                aValue = aValue.toAsciiLowerCase();
                if ( aValue.compareTo(
                        RTL_CONSTASCII_STRINGPARAM( "<collection" ) ) == 0 )
                {
                    thePropertyValue.Value
                        <<= OUString::createFromAscii( "collection" );
                }
            }

            if ( !thePropertyValue.Value.hasValue() )
            {
                // Take over the value exactly as supplied by the server.
                thePropertyValue.Value <<= OUString::createFromAscii( value );
            }
        }
        else if ( rtl_str_compareIgnoreAsciiCase(
                                    pname->name, "supportedlock" ) == 0 )
        {
            Sequence< LockEntry > aEntries;
            LockEntrySequence::createFromXML( value, aEntries );
            thePropertyValue.Value <<= aEntries;
        }
        else if ( rtl_str_compareIgnoreAsciiCase(
                                    pname->name, "lockdiscovery" ) == 0 )
        {
            Sequence< Lock > aLocks;
            LockSequence::createFromXML( value, aLocks );
            thePropertyValue.Value <<= aLocks;
        }
        else if ( rtl_str_compareIgnoreAsciiCase( pname->name, "source" ) == 0 )
        {
            Sequence< Link > aLinks;
            LinkSequence::createFromXML( value, aLinks );
            thePropertyValue.Value <<= aLinks;
        }
        else
        {
            thePropertyValue.Value
                <<= OStringToOUString( value, RTL_TEXTENCODING_UTF8 );
        }
    }

    // Add the newly created PropertyValue
    DAVResource* theResource = static_cast< DAVResource * >( userdata );
    theResource->properties.push_back( thePropertyValue );

    return 0; // Go on.
}

// -------------------------------------------------------------------
extern "C" void NPFR_propfind_results( void* userdata,
                                       const ne_uri* href_uri,
                                       const NeonPropFindResultSet* set )
{
    // @@@ href is not the uri! DAVResource ctor wants uri!

    // href should be free'd? says header ...
    char* href = ne_uri_unparse(href_uri);

    DAVResource theResource(
                        OStringToOUString( href, RTL_TEXTENCODING_UTF8 ) );

    ne_propset_iterate( set, NPFR_propfind_iter, &theResource );

    // Add entry to resources list.
    vector< DAVResource > * theResources
        = static_cast< vector< DAVResource > * >( userdata );
    theResources->push_back( theResource );
}

// -------------------------------------------------------------------
extern "C" int NPFR_propnames_iter( void* userdata,
                                    const NeonPropName* pname,
                                    const char* /*value*/,
                                    const HttpStatus* /*status*/ )
{
    OUString aFullName;
    DAVProperties::createUCBPropName( pname->nspace,
                                      pname->name,
                                      aFullName );

    DAVResourceInfo* theResource = static_cast< DAVResourceInfo * >( userdata );
    theResource->properties.push_back( aFullName );
    return 0;
}

// -------------------------------------------------------------------
extern "C" void NPFR_propnames_results( void* userdata,
                                        const ne_uri* href_uri,
                                        const NeonPropFindResultSet* results )
{
    // @@@ href is not the uri! DAVResourceInfo ctor wants uri!

    // href should be free'd? says header ...
    char* href = ne_uri_unparse(href_uri);

    // Create entry for the resource.
    DAVResourceInfo theResource(
                        OStringToOUString( href, RTL_TEXTENCODING_UTF8 ) );
    // Fill entry.
    ne_propset_iterate( results, NPFR_propnames_iter, &theResource );

    // Add entry to resources list.
    vector< DAVResourceInfo > * theResources
        = static_cast< vector< DAVResourceInfo > * >( userdata );
    theResources->push_back( theResource );
}

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------

NeonPropFindRequest::NeonPropFindRequest( HttpSession* inSession,
                                          const char* inPath,
                                          const Depth inDepth,
                                          const vector< OUString >& inPropNames,
                                          vector< DAVResource >& ioResources,
                                          int & nError )
{
    // Generate the list of properties we're looking for
    int thePropCount = inPropNames.size();
    if ( thePropCount > 0 )
    {
        NeonPropName* thePropNames = new NeonPropName[ thePropCount + 1 ];
        int theIndex;

        for ( theIndex = 0; theIndex < thePropCount; theIndex ++ )
        {
            // Split fullname into namespace and name!
            DAVProperties::createNeonPropName(
                             inPropNames[ theIndex ], thePropNames[ theIndex ] );
        }
        thePropNames[ theIndex ].nspace = NULL;
        thePropNames[ theIndex ].name   = NULL;

        nError = ne_simple_propfind( inSession,
                                     inPath,
                                     inDepth,
                                     thePropNames,
                                     NPFR_propfind_results,
                                     &ioResources );

        for ( theIndex = 0; theIndex < thePropCount; theIndex ++ )
            free( (void *)thePropNames[ theIndex ].name );

        delete [] thePropNames;
    }
    else
    {
        // ALLPROP
        nError = ne_simple_propfind( inSession,
                                     inPath,
                                     inDepth,
                                     NULL, // 0 == allprop
                                     NPFR_propfind_results,
                                     &ioResources );
    }

    // #87585# - Sometimes neon lies (because some servers lie).
    if ( ( nError == NE_OK ) && ioResources.empty() )
        nError = NE_ERROR;
}

// -------------------------------------------------------------------
// Constructor
// - obtains property names
// -------------------------------------------------------------------

NeonPropFindRequest::NeonPropFindRequest(
                            HttpSession* inSession,
                            const char* inPath,
                                const Depth inDepth,
                            std::vector< DAVResourceInfo > & ioResInfo,
                            int & nError )
{
    nError = ne_propnames( inSession,
                           inPath,
                           inDepth,
                           NPFR_propnames_results,
                           &ioResInfo );

    // #87585# - Sometimes neon lies (because some servers lie).
    if ( ( nError == NE_OK ) && ioResInfo.empty() )
        nError = NE_ERROR;
}

// -------------------------------------------------------------------
// Destructor
// -------------------------------------------------------------------
NeonPropFindRequest::~NeonPropFindRequest( )
{
}
<commit_msg>INTEGRATION: CWS pmladek08 (1.19.34); FILE MERGED 2007/12/10 14:15:41 pmladek 1.19.34.1: #i82569# add back support for build with neon-0.24.X<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: NeonPropFindRequest.cxx,v $
 *
 *  $Revision: 1.20 $
 *
 *  last change: $Author: kz $ $Date: 2007-12-12 15:33:42 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_ucb.hxx"

#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif

#ifndef _NEONTYPES_HXX_
#include "NeonTypes.hxx"
#endif
#ifndef _DAVEXCEPTION_HXX_
#include "DAVException.hxx"
#endif
#ifndef _DAVPROPERTIES_HXX_
#include "DAVProperties.hxx"
#endif
#ifndef _NEONPROPFINDREQUEST_HXX_
#include "NeonPropFindRequest.hxx"
#endif
#ifndef _LINKSEQUENCE_HXX_
#include "LinkSequence.hxx"
#endif
#ifndef _LOCKSEQUENCE_HXX_
#include "LockSequence.hxx"
#endif
#ifndef _LOCKENTRYSEQUENCE_HXX_
#include "LockEntrySequence.hxx"
#endif
#ifndef _UCBDEADPROPERTYVALUE_HXX_
#include "UCBDeadPropertyValue.hxx"
#endif

using namespace rtl;
using namespace com::sun::star::uno;
using namespace com::sun::star::ucb;
using namespace std;
using namespace webdav_ucp;

// -------------------------------------------------------------------
extern "C" int NPFR_propfind_iter( void* userdata,
                                   const NeonPropName* pname,
                                   const char* value,
                                   const HttpStatus* status )
{
    /*
        HTTP Response Status Classes:

          - 1: Informational - Request received, continuing process

          - 2: Success - The action was successfully received,
          understood, and accepted

        - 3: Redirection - Further action must be taken in order to
          complete the request

        - 4: Client Error - The request contains bad syntax or cannot
          be fulfilled

        - 5: Server Error - The server failed to fulfill an apparently
          valid request
    */

    if ( status->klass > 2 )
        return 0; // Error getting this property. Go on.

    // Create & set the PropertyValue
    DAVPropertyValue thePropertyValue;
    thePropertyValue.IsCaseSensitive = true;

    DAVProperties::createUCBPropName( pname->nspace,
                                        pname->name,
                                        thePropertyValue.Name );
    bool bHasValue = false;
    if ( DAVProperties::isUCBDeadProperty( *pname ) )
    {
        // DAV dead property added by WebDAV UCP?
        if ( UCBDeadPropertyValue::createFromXML(
                                        value, thePropertyValue.Value ) )
            OSL_ENSURE( thePropertyValue.Value.hasValue(),
                        "NeonPropFindRequest::propfind_iter - No value!" );
            bHasValue = true;
    }

    if ( !bHasValue )
    {
        if ( rtl_str_compareIgnoreAsciiCase(
                                    pname->name, "resourcetype" ) == 0 )
        {
            OString aValue( value );
            aValue = aValue.trim(); // #107358# remove leading/trailing spaces
            if ( aValue.getLength() )
            {
                aValue = aValue.toAsciiLowerCase();
                if ( aValue.compareTo(
                        RTL_CONSTASCII_STRINGPARAM( "<collection" ) ) == 0 )
                {
                    thePropertyValue.Value
                        <<= OUString::createFromAscii( "collection" );
                }
            }

            if ( !thePropertyValue.Value.hasValue() )
            {
                // Take over the value exactly as supplied by the server.
                thePropertyValue.Value <<= OUString::createFromAscii( value );
            }
        }
        else if ( rtl_str_compareIgnoreAsciiCase(
                                    pname->name, "supportedlock" ) == 0 )
        {
            Sequence< LockEntry > aEntries;
            LockEntrySequence::createFromXML( value, aEntries );
            thePropertyValue.Value <<= aEntries;
        }
        else if ( rtl_str_compareIgnoreAsciiCase(
                                    pname->name, "lockdiscovery" ) == 0 )
        {
            Sequence< Lock > aLocks;
            LockSequence::createFromXML( value, aLocks );
            thePropertyValue.Value <<= aLocks;
        }
        else if ( rtl_str_compareIgnoreAsciiCase( pname->name, "source" ) == 0 )
        {
            Sequence< Link > aLinks;
            LinkSequence::createFromXML( value, aLinks );
            thePropertyValue.Value <<= aLinks;
        }
        else
        {
            thePropertyValue.Value
                <<= OStringToOUString( value, RTL_TEXTENCODING_UTF8 );
        }
    }

    // Add the newly created PropertyValue
    DAVResource* theResource = static_cast< DAVResource * >( userdata );
    theResource->properties.push_back( thePropertyValue );

    return 0; // Go on.
}

// -------------------------------------------------------------------
extern "C" void NPFR_propfind_results( void* userdata,
#if NEON_VERSION >= 0260
                                       const ne_uri* href_uri,
#else
                                       const char* href,
#endif
                                       const NeonPropFindResultSet* set )
{
    // @@@ href is not the uri! DAVResource ctor wants uri!

#if NEON_VERSION >= 0260
    // href should be free'd? says header ...
    char* href = ne_uri_unparse(href_uri);
#endif
    DAVResource theResource(
                        OStringToOUString( href, RTL_TEXTENCODING_UTF8 ) );

    ne_propset_iterate( set, NPFR_propfind_iter, &theResource );

    // Add entry to resources list.
    vector< DAVResource > * theResources
        = static_cast< vector< DAVResource > * >( userdata );
    theResources->push_back( theResource );
}

// -------------------------------------------------------------------
extern "C" int NPFR_propnames_iter( void* userdata,
                                    const NeonPropName* pname,
                                    const char* /*value*/,
                                    const HttpStatus* /*status*/ )
{
    OUString aFullName;
    DAVProperties::createUCBPropName( pname->nspace,
                                      pname->name,
                                      aFullName );

    DAVResourceInfo* theResource = static_cast< DAVResourceInfo * >( userdata );
    theResource->properties.push_back( aFullName );
    return 0;
}

// -------------------------------------------------------------------
extern "C" void NPFR_propnames_results( void* userdata,
#if NEON_VERSION >= 0260
                                        const ne_uri* href_uri,
#else
                                        const char* href,
#endif
                                        const NeonPropFindResultSet* results )
{
    // @@@ href is not the uri! DAVResourceInfo ctor wants uri!

#if NEON_VERSION >= 0260
    // href should be free'd? says header ...
    char* href = ne_uri_unparse(href_uri);
#endif
    // Create entry for the resource.
    DAVResourceInfo theResource(
                        OStringToOUString( href, RTL_TEXTENCODING_UTF8 ) );
    // Fill entry.
    ne_propset_iterate( results, NPFR_propnames_iter, &theResource );

    // Add entry to resources list.
    vector< DAVResourceInfo > * theResources
        = static_cast< vector< DAVResourceInfo > * >( userdata );
    theResources->push_back( theResource );
}

// -------------------------------------------------------------------
// Constructor
// -------------------------------------------------------------------

NeonPropFindRequest::NeonPropFindRequest( HttpSession* inSession,
                                          const char* inPath,
                                          const Depth inDepth,
                                          const vector< OUString >& inPropNames,
                                          vector< DAVResource >& ioResources,
                                          int & nError )
{
    // Generate the list of properties we're looking for
    int thePropCount = inPropNames.size();
    if ( thePropCount > 0 )
    {
        NeonPropName* thePropNames = new NeonPropName[ thePropCount + 1 ];
        int theIndex;

        for ( theIndex = 0; theIndex < thePropCount; theIndex ++ )
        {
            // Split fullname into namespace and name!
            DAVProperties::createNeonPropName(
                             inPropNames[ theIndex ], thePropNames[ theIndex ] );
        }
        thePropNames[ theIndex ].nspace = NULL;
        thePropNames[ theIndex ].name   = NULL;

        nError = ne_simple_propfind( inSession,
                                     inPath,
                                     inDepth,
                                     thePropNames,
                                     NPFR_propfind_results,
                                     &ioResources );

        for ( theIndex = 0; theIndex < thePropCount; theIndex ++ )
            free( (void *)thePropNames[ theIndex ].name );

        delete [] thePropNames;
    }
    else
    {
        // ALLPROP
        nError = ne_simple_propfind( inSession,
                                     inPath,
                                     inDepth,
                                     NULL, // 0 == allprop
                                     NPFR_propfind_results,
                                     &ioResources );
    }

    // #87585# - Sometimes neon lies (because some servers lie).
    if ( ( nError == NE_OK ) && ioResources.empty() )
        nError = NE_ERROR;
}

// -------------------------------------------------------------------
// Constructor
// - obtains property names
// -------------------------------------------------------------------

NeonPropFindRequest::NeonPropFindRequest(
                            HttpSession* inSession,
                            const char* inPath,
                                const Depth inDepth,
                            std::vector< DAVResourceInfo > & ioResInfo,
                            int & nError )
{
    nError = ne_propnames( inSession,
                           inPath,
                           inDepth,
                           NPFR_propnames_results,
                           &ioResInfo );

    // #87585# - Sometimes neon lies (because some servers lie).
    if ( ( nError == NE_OK ) && ioResInfo.empty() )
        nError = NE_ERROR;
}

// -------------------------------------------------------------------
// Destructor
// -------------------------------------------------------------------
NeonPropFindRequest::~NeonPropFindRequest( )
{
}
<|endoftext|>


<commit_before>/*****************************************************************************************
*                                                                                *
* OpenSpace                                                                             *
*                                                                                *
* Copyright (c) 2014-2015                                                               *
*                                                                                *
* 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 <modules/iswa/util/dataprocessortext.h>
#include <algorithm>
#include <iterator>
#include <boost/iostreams/device/mapped_file.hpp>

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>

namespace {
    const std::string _loggerCat = "DataProcessorText";
}

namespace openspace{

DataProcessorText::DataProcessorText()
    :DataProcessor()
{}

DataProcessorText::~DataProcessorText(){}

std::vector<std::string> DataProcessorText::readMetadata(std::string data, glm::size3_t& dimensions){
    //The intresting part of the file looks like this:
    //# Output data: field with 61x61=3721 elements
    //# x           y           z           N           V_x         B_x

    std::vector<std::string> options = std::vector<std::string>();
    std::string info = "# Output data: field with "; //The string where the interesting data begins
    if(!data.empty()){
        std::string line;
        std::stringstream memorystream(data);

        while(getline(memorystream, line)){
            if(line.find(info) == 0){
                line = line.substr(info.size());
                std::stringstream ss(line);

                std::string token;
                getline(ss, token, 'x');
                int x = std::stoi(token);

                getline(ss, token, '=');
                int y = std::stoi(token);

                dimensions = glm::size3_t(x, y, 1);

                getline(memorystream, line);
                line = line.substr(1); //because of the # char

                ss = std::stringstream(line);
                std::string option;
                while(ss >> option){
                    if(_coordinateVariables.find(option) == _coordinateVariables.end())
                        options.push_back(option);
                }
            }
        }
    }

    return options;
}

void DataProcessorText::addDataValues(std::string data, properties::SelectionProperty& dataOptions){
    int numOptions = dataOptions.options().size();
    initializeVectors(numOptions);

    if(!data.empty()){
        std::string line;
        std::stringstream memorystream(data);

        std::vector<float> sum(numOptions, 0.0f); //for standard diviation in the add() function
        std::vector<std::vector<float>> optionValues(numOptions, std::vector<float>());

        std::vector<float> values;
        float value;

        int first, last, option, lineSize;

        while(getline(memorystream, line)){
            if(line.find("#") == 0) continue;

            values = std::vector<float>();
            std::istringstream ss(line);
			std::istream_iterator<float> it(ss);
			std::advance(it, 3); //+3 because options x, y and z in the file
            copy(
                it,
                std::istream_iterator<float> (),
                back_inserter(values)
            );

            if(values.size() <= 0) continue;

            for(int i=0; i<numOptions; i++){
                value = values[i];

                optionValues[i].push_back(value);
                _min[i] = std::min(_min[i], value);
                _max[i] = std::max(_max[i], value);
                sum[i] += value;
            }
        }

        add(optionValues, sum);
    }
}

std::vector<float*> DataProcessorText::processData(std::string data, properties::SelectionProperty& dataOptions, glm::size3_t& dimensions){
    if(!data.empty()){

        std::string line;
        std::stringstream memorystream(data);

        std::vector<int> selectedOptions = dataOptions.value();
        int numSelected = selectedOptions.size();
        int numOptions  = dataOptions.options().size();

        std::vector<float> values;
        float value;

        int first, last, option, lineSize;

        std::vector<float*> dataOptions(numOptions, nullptr);
        for(int option : selectedOptions){
            dataOptions[option] = new float[dimensions.x*dimensions.y]{0.0f};
        }

        int numValues = 0;
        while(getline(memorystream, line)){
            if(line.find("#") == 0) continue;

            // ----------- OLD METHODS ------------------------
            // values = std::vector<float>();
            // std::stringstream ss(line);
            // float v;
            // while(ss >> v){
            //     values.push_back(v);
            // }

            // copy(
            //     std::istream_iterator<float> (ss),
            //     std::istream_iterator<float> (),
            //     back_inserter(values)
            // );

            // copy(
            //     std::next( std::istream_iterator<float> (ss), 3 ), //+3 because options x, y and z in the file
            //     std::istream_iterator<float> (),
            //     back_inserter(values)
            // );

            // for(int option : selectedOptions){
            //     value = values[option];
            //     //value = values[option+3]; //+3 because options x, y and z in the file
            //     dataOptions[option][numValues] = processDataPoint(value, option);
            // }
            // ----------- OLD METHODS ------------------------

            first = 0;
            last = 0;
            option = -3;
            lineSize = line.size();

            while(last < lineSize){

                first = line.find_first_not_of(" \t", last);
                last =  line.find_first_of(" \t", first);
                last = (last > 0)? last : lineSize;

                if(option >= 0 && std::find(selectedOptions.begin(), selectedOptions.end(), option) != selectedOptions.end()){
                    // boost::spirit::qi::parse(&line[first], &line[last], boost::spirit::qi::float_, value);
                    value = std::stof(line.substr(first, last));
                    dataOptions[option][numValues] = processDataPoint(value, option);
                }

                option++;
            }

            numValues++;
        }

        calculateFilterValues(selectedOptions);

        return dataOptions;
    }
    return std::vector<float*>();
}

}//namespace openspace<commit_msg>change method for adding data values in dataprocessortext<commit_after>/*****************************************************************************************
*                                                                                *
* OpenSpace                                                                             *
*                                                                                *
* Copyright (c) 2014-2016                                                               *
*                                                                                *
* 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 <modules/iswa/util/dataprocessortext.h>
#include <algorithm>
#include <iterator>
#include <boost/iostreams/device/mapped_file.hpp>

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>

namespace {
    const std::string _loggerCat = "DataProcessorText";
}

namespace openspace{

DataProcessorText::DataProcessorText()
    :DataProcessor()
{}

DataProcessorText::~DataProcessorText(){}

std::vector<std::string> DataProcessorText::readMetadata(std::string data, glm::size3_t& dimensions){
    //The intresting part of the file looks like this:
    //# Output data: field with 61x61=3721 elements
    //# x           y           z           N           V_x         B_x

    std::vector<std::string> options = std::vector<std::string>();
    std::string info = "# Output data: field with "; //The string where the interesting data begins
    if(!data.empty()){
        std::string line;
        std::stringstream memorystream(data);

        while(getline(memorystream, line)){
            if(line.find(info) == 0){
                line = line.substr(info.size());
                std::stringstream ss(line);

                std::string token;
                getline(ss, token, 'x');
                int x = std::stoi(token);

                getline(ss, token, '=');
                int y = std::stoi(token);

                dimensions = glm::size3_t(x, y, 1);

                getline(memorystream, line);
                line = line.substr(1); //because of the # char

                ss = std::stringstream(line);
                std::string option;
                while(ss >> option){
                    if(_coordinateVariables.find(option) == _coordinateVariables.end())
                        options.push_back(option);
                }
            }
        }
    }

    return options;
}

void DataProcessorText::addDataValues(std::string data, properties::SelectionProperty& dataOptions){
    int numOptions = dataOptions.options().size();
    initializeVectors(numOptions);

    if(!data.empty()){
        std::string line;
        std::stringstream memorystream(data);

        std::vector<float> sum(numOptions, 0.0f); //for standard diviation in the add() function
        std::vector<std::vector<float>> optionValues(numOptions, std::vector<float>());

        std::vector<float> values;
        float value;

        int first, last, option, lineSize;

        // for each data point
        while(getline(memorystream, line)){
            if(line.find("#") == 0) continue;
            values = std::vector<float>();
            std::istringstream ss(line);
            std::string val;
            int skip = 0;
            //for each data option (variable)
            while(ss >> val){
                // first three values are coordinates
                if( skip < 3 ){
                    skip++;
                    continue;
                }

                float v = std::stof(val);
                // Some values are "NaN", use 0 instead
                if(!std::isnan(v)){
                    values.push_back(v);
                } else {
                    values.push_back(0.0f);
                }
                val.clear();
            }

            if(values.size() <= 0) continue;

            for(int i=0; i<numOptions; i++){
                value = values[i];

                optionValues[i].push_back(value);
                _min[i] = std::min(_min[i], value);
                _max[i] = std::max(_max[i], value);
                sum[i] += value;
            }
        }

        add(optionValues, sum);
    }
}

std::vector<float*> DataProcessorText::processData(std::string data, properties::SelectionProperty& dataOptions, glm::size3_t& dimensions){
    if(!data.empty()){

        std::string line;
        std::stringstream memorystream(data);

        std::vector<int> selectedOptions = dataOptions.value();
        int numSelected = selectedOptions.size();
        int numOptions  = dataOptions.options().size();

        std::vector<float> values;
        float value;

        int first, last, option, lineSize;

        std::vector<float*> dataOptions(numOptions, nullptr);
        for(int option : selectedOptions){
            dataOptions[option] = new float[dimensions.x*dimensions.y]{0.0f};
        }

        int numValues = 0;
        while(getline(memorystream, line)){
            if(line.find("#") == 0) continue;

            // ----------- OLD METHODS ------------------------
            // values = std::vector<float>();
            // std::stringstream ss(line);
            // float v;
            // while(ss >> v){
            //     values.push_back(v);
            // }

            // copy(
            //     std::istream_iterator<float> (ss),
            //     std::istream_iterator<float> (),
            //     back_inserter(values)
            // );

            // copy(
            //     std::next( std::istream_iterator<float> (ss), 3 ), //+3 because options x, y and z in the file
            //     std::istream_iterator<float> (),
            //     back_inserter(values)
            // );

            // for(int option : selectedOptions){
            //     value = values[option];
            //     //value = values[option+3]; //+3 because options x, y and z in the file
            //     dataOptions[option][numValues] = processDataPoint(value, option);
            // }
            // ----------- OLD METHODS ------------------------

            first = 0;
            last = 0;
            option = -3;
            lineSize = line.size();

            while(last < lineSize){

                first = line.find_first_not_of(" \t", last);
                last =  line.find_first_of(" \t", first);
                last = (last > 0)? last : lineSize;

                if(option >= 0 && std::find(selectedOptions.begin(), selectedOptions.end(), option) != selectedOptions.end()){
                    // boost::spirit::qi::parse(&line[first], &line[last], boost::spirit::qi::float_, value);
                    value = std::stof(line.substr(first, last));
                    dataOptions[option][numValues] = processDataPoint(value, option);
                }

                option++;
            }

            numValues++;
        }

        calculateFilterValues(selectedOptions);

        return dataOptions;
    }
    return std::vector<float*>();
}

}//namespace openspace<|endoftext|>


<commit_before>// -----------------------------------------------------------------------
// pion-common: a collection of common libraries used by the Pion Platform
// -----------------------------------------------------------------------
// Copyright (C) 2007-2009 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
//

#ifndef __PION_PIONID_HEADER__
#define __PION_PIONID_HEADER__

#include <string>
#include <limits>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <boost/functional/hash.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/variate_generator.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <pion/PionConfig.hpp>

namespace pion {	// begin namespace pion

///
/// PionId: a random-number based universally unique identifier (UUID v4)
///
class PionId {
public:

	/// data type for iterating PionId byte values
	typedef unsigned char *			iterator;

	/// const data type for iterating PionId byte values
	typedef const unsigned char *	const_iterator;

	enum {
		PION_ID_DATA_BYTES = 16,			//< total number of data bytes
		PION_ID_HEX_BYTES = 16 * 2 + 4		//< number of bytes in hexadecimal representation
	};

	/// class may be extended (virtual destructor)
	virtual ~PionId() {}

	/// default constructor
	PionId(void) {
		typedef boost::mt19937 gen_type;
		typedef boost::uniform_int<unsigned long> dist_type;
		typedef boost::variate_generator<gen_type,dist_type> die_type;
		gen_type rng_gen(PionId::make_seed());
		dist_type rng_dist((std::numeric_limits<unsigned long>::min)(), (std::numeric_limits<unsigned long>::max)());
		die_type rng_die(rng_gen, rng_dist);
		generate(m_data, rng_die);
	}

	/// construction using a string representation (bb49b9ca-e733-47c0-9a26-0f8f53ea1660)
	explicit PionId(const std::string& str) {
		from_string(str.c_str());
	}

	/// construction using a null-terminated c-style string (bb49b9ca-e733-47c0-9a26-0f8f53ea1660)
	explicit PionId(const char *str) {
		from_string(str);
	}

	/// construction using an existing random number generator
	template<typename base_generator_type, typename distribution_type>
	explicit PionId(boost::variate_generator<base_generator_type, distribution_type>& rng) {
		generate(m_data, rng);
	}

	/// copy constructor
	PionId(const PionId& id) {
		memcpy(m_data, id.m_data, PION_ID_DATA_BYTES);
	}

	/// assignment operator
	PionId& operator=(const PionId& id) {
		memcpy(m_data, id.m_data, PION_ID_DATA_BYTES);
		return *this;
	}

	/// returns id value at byte offset
	inline unsigned char operator[](const std::size_t n) const {
		return m_data[n];
	}

	/// returns true if id equals this
	inline bool operator==(const PionId& id) const {
		return (memcmp(m_data, id.m_data, PION_ID_DATA_BYTES) == 0);
	}

	/// returns true if id does not equal this
	inline bool operator!=(const PionId& id) const {
		return (memcmp(m_data, id.m_data, PION_ID_DATA_BYTES) != 0);
	}

	/// returns true if id is less than this
	inline bool operator<(const PionId& id) const {
		return (memcmp(m_data, id.m_data, PION_ID_DATA_BYTES) < 0);
	}

	/// returns true if id is greater than this
	inline bool operator>(const PionId& id) const {
		return (memcmp(m_data, id.m_data, PION_ID_DATA_BYTES) > 0);
	}

	/// returns the beginning iterator
	inline iterator begin(void) { return m_data; }

	/// returns the ending iterator
	inline iterator end(void) { return m_data + PION_ID_DATA_BYTES; }

	/// returns the beginning iterator (const)
	inline const_iterator begin(void) const { return m_data; }

	/// returns the ending iterator (const)
	inline const_iterator end(void) const { return m_data + PION_ID_DATA_BYTES; }

	/// returns hexadecimal representation as a string (bb49b9ca-e733-47c0-9a26-0f8f53ea1660)
	inline std::string to_string(void) const {
		std::string hex_str;
		static const char hex[] = "0123456789abcdef";
		for (std::size_t i = 0; i < PION_ID_DATA_BYTES; i++) {
			hex_str += hex[m_data[i] >> 4];
			hex_str += hex[m_data[i] & 0x0f];
			if (i == 3 || i == 5 || i == 7 || i == 9)
				hex_str += '-';
		}
		return hex_str;
	}

	/// sets the data value based upon a null-terminated string representation (bb49b9ca-e733-47c0-9a26-0f8f53ea1660)
	void from_string(const char *str) {
		std::size_t data_pos = 0;
		char buf[3];
		buf[2] = '\0';
		while (*str != '\0' && data_pos < PION_ID_DATA_BYTES) {
			if (isxdigit(*str)) {
				buf[0] = *str;
				if (*(++str) == '\0' || !isxdigit(*str))	// sanity check
					break;
				buf[1] = *str;
				m_data[data_pos++] = strtoul(buf, NULL, 16);
			}
			++str;
		}
	}

	/// return a seed value for random number generators
	static inline boost::uint64_t make_seed(void) {
		// this could be much better...  and is probably far too trivial...
		boost::uint64_t seed = boost::posix_time::microsec_clock::local_time().time_of_day().total_microseconds();
std::cout << seed << std::endl;
		seed += (time(NULL) * 1000000);
		return seed;
	}

protected:

	/**
	 * generates a new data value using an existing random number generator
	 *
	 * @param data pointer to a data buffer that is PION_ID_DATA_BYTES in size
	 * @param rng initialized random number generator
	 */
	template<typename base_generator_type, typename distribution_type>
	static inline void generate(unsigned char *data, boost::variate_generator<base_generator_type, distribution_type>& rng) {
		// Note: this code is adapted from the Boost UUID library, (c) 2006 Andy Tompkins
		for (std::size_t i = 0; i < PION_ID_DATA_BYTES; i += sizeof(unsigned long)) {
            *reinterpret_cast<unsigned long*>(&data[i]) = rng();
		}

        // set variant
        // should be 0b10xxxxxx
        data[8] &= 0xBF;
        data[8] |= 0x80;

        // set version
        // should be 0b0100xxxx
        data[6] &= 0x4F; //0b01001111
        data[6] |= 0x40; //0b01000000
	}

	/// sequence of bytes representing the unique identifier
	unsigned char	m_data[PION_ID_DATA_BYTES];
};

/// returns hash value for a PionId object (used by boost::hash_map)
static inline std::size_t hash_value(const PionId& id) {
	std::size_t seed = 0;
	const unsigned char * data = id.begin();
	const unsigned char * const end = id.end();
	while (data < end) {
		boost::hash_combine(seed, *reinterpret_cast<const unsigned long*>(data));
		data += sizeof(unsigned long);
	}
	return seed;
}

///
/// PionIdGeneratorBase: class used to generated new PionId's
///
template <typename BaseGeneratorType>
class PionIdGeneratorBase {
public:

	/// make dynamic type for base generator available
	typedef BaseGeneratorType	base_generator_type;

	/// random number distribution type
	typedef boost::uniform_int<unsigned long>	distribution_type;

	/// random number generator type
	typedef boost::variate_generator<base_generator_type, distribution_type>	gen_type;

	/// class may be extended (virtual destructor)
	virtual ~PionIdGeneratorBase() {}

	/// default constructor
	PionIdGeneratorBase(void)
		: m_random_gen(PionId::make_seed()),
		m_random_dist((std::numeric_limits<unsigned long>::min)(), (std::numeric_limits<unsigned long>::max)()),
		m_random_die(m_random_gen, m_random_dist)
	{}

	/// returns a newly generated PionId object
	inline PionId operator()(void) { return PionId(m_random_die); }

	/// return random number generator
	inline gen_type& getRNG(void) { return m_random_die; }

	/// return random number generator
	inline unsigned long getNumber(void) { return m_random_die(); }

protected:

	/// random number generator
	base_generator_type				m_random_gen;

	/// random number distribution
	distribution_type				m_random_dist;

	/// random number die
	gen_type						m_random_die;
};

/// data type for the default PionId generator class
typedef PionIdGeneratorBase<boost::mt19937>	PionIdGenerator;

}	// end namespace pion

#endif
<commit_msg>Undid accidental commit of debugging code.<commit_after>// -----------------------------------------------------------------------
// pion-common: a collection of common libraries used by the Pion Platform
// -----------------------------------------------------------------------
// Copyright (C) 2007-2009 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
//

#ifndef __PION_PIONID_HEADER__
#define __PION_PIONID_HEADER__

#include <string>
#include <limits>
#include <ctime>
#include <cstring>
#include <cstdlib>
#include <boost/functional/hash.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/variate_generator.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <pion/PionConfig.hpp>

namespace pion {	// begin namespace pion

///
/// PionId: a random-number based universally unique identifier (UUID v4)
///
class PionId {
public:

	/// data type for iterating PionId byte values
	typedef unsigned char *			iterator;

	/// const data type for iterating PionId byte values
	typedef const unsigned char *	const_iterator;

	enum {
		PION_ID_DATA_BYTES = 16,			//< total number of data bytes
		PION_ID_HEX_BYTES = 16 * 2 + 4		//< number of bytes in hexadecimal representation
	};

	/// class may be extended (virtual destructor)
	virtual ~PionId() {}

	/// default constructor
	PionId(void) {
		typedef boost::mt19937 gen_type;
		typedef boost::uniform_int<unsigned long> dist_type;
		typedef boost::variate_generator<gen_type,dist_type> die_type;
		gen_type rng_gen(PionId::make_seed());
		dist_type rng_dist((std::numeric_limits<unsigned long>::min)(), (std::numeric_limits<unsigned long>::max)());
		die_type rng_die(rng_gen, rng_dist);
		generate(m_data, rng_die);
	}

	/// construction using a string representation (bb49b9ca-e733-47c0-9a26-0f8f53ea1660)
	explicit PionId(const std::string& str) {
		from_string(str.c_str());
	}

	/// construction using a null-terminated c-style string (bb49b9ca-e733-47c0-9a26-0f8f53ea1660)
	explicit PionId(const char *str) {
		from_string(str);
	}

	/// construction using an existing random number generator
	template<typename base_generator_type, typename distribution_type>
	explicit PionId(boost::variate_generator<base_generator_type, distribution_type>& rng) {
		generate(m_data, rng);
	}

	/// copy constructor
	PionId(const PionId& id) {
		memcpy(m_data, id.m_data, PION_ID_DATA_BYTES);
	}

	/// assignment operator
	PionId& operator=(const PionId& id) {
		memcpy(m_data, id.m_data, PION_ID_DATA_BYTES);
		return *this;
	}

	/// returns id value at byte offset
	inline unsigned char operator[](const std::size_t n) const {
		return m_data[n];
	}

	/// returns true if id equals this
	inline bool operator==(const PionId& id) const {
		return (memcmp(m_data, id.m_data, PION_ID_DATA_BYTES) == 0);
	}

	/// returns true if id does not equal this
	inline bool operator!=(const PionId& id) const {
		return (memcmp(m_data, id.m_data, PION_ID_DATA_BYTES) != 0);
	}

	/// returns true if id is less than this
	inline bool operator<(const PionId& id) const {
		return (memcmp(m_data, id.m_data, PION_ID_DATA_BYTES) < 0);
	}

	/// returns true if id is greater than this
	inline bool operator>(const PionId& id) const {
		return (memcmp(m_data, id.m_data, PION_ID_DATA_BYTES) > 0);
	}

	/// returns the beginning iterator
	inline iterator begin(void) { return m_data; }

	/// returns the ending iterator
	inline iterator end(void) { return m_data + PION_ID_DATA_BYTES; }

	/// returns the beginning iterator (const)
	inline const_iterator begin(void) const { return m_data; }

	/// returns the ending iterator (const)
	inline const_iterator end(void) const { return m_data + PION_ID_DATA_BYTES; }

	/// returns hexadecimal representation as a string (bb49b9ca-e733-47c0-9a26-0f8f53ea1660)
	inline std::string to_string(void) const {
		std::string hex_str;
		static const char hex[] = "0123456789abcdef";
		for (std::size_t i = 0; i < PION_ID_DATA_BYTES; i++) {
			hex_str += hex[m_data[i] >> 4];
			hex_str += hex[m_data[i] & 0x0f];
			if (i == 3 || i == 5 || i == 7 || i == 9)
				hex_str += '-';
		}
		return hex_str;
	}

	/// sets the data value based upon a null-terminated string representation (bb49b9ca-e733-47c0-9a26-0f8f53ea1660)
	void from_string(const char *str) {
		std::size_t data_pos = 0;
		char buf[3];
		buf[2] = '\0';
		while (*str != '\0' && data_pos < PION_ID_DATA_BYTES) {
			if (isxdigit(*str)) {
				buf[0] = *str;
				if (*(++str) == '\0' || !isxdigit(*str))	// sanity check
					break;
				buf[1] = *str;
				m_data[data_pos++] = strtoul(buf, NULL, 16);
			}
			++str;
		}
	}

	/// return a seed value for random number generators
	static inline boost::uint64_t make_seed(void) {
		// this could be much better...  and is probably far too trivial...
		boost::uint64_t seed = boost::posix_time::microsec_clock::local_time().time_of_day().total_microseconds();
		seed += (time(NULL) * 1000000);
		return seed;
	}

protected:

	/**
	 * generates a new data value using an existing random number generator
	 *
	 * @param data pointer to a data buffer that is PION_ID_DATA_BYTES in size
	 * @param rng initialized random number generator
	 */
	template<typename base_generator_type, typename distribution_type>
	static inline void generate(unsigned char *data, boost::variate_generator<base_generator_type, distribution_type>& rng) {
		// Note: this code is adapted from the Boost UUID library, (c) 2006 Andy Tompkins
		for (std::size_t i = 0; i < PION_ID_DATA_BYTES; i += sizeof(unsigned long)) {
            *reinterpret_cast<unsigned long*>(&data[i]) = rng();
		}

        // set variant
        // should be 0b10xxxxxx
        data[8] &= 0xBF;
        data[8] |= 0x80;

        // set version
        // should be 0b0100xxxx
        data[6] &= 0x4F; //0b01001111
        data[6] |= 0x40; //0b01000000
	}

	/// sequence of bytes representing the unique identifier
	unsigned char	m_data[PION_ID_DATA_BYTES];
};

/// returns hash value for a PionId object (used by boost::hash_map)
static inline std::size_t hash_value(const PionId& id) {
	std::size_t seed = 0;
	const unsigned char * data = id.begin();
	const unsigned char * const end = id.end();
	while (data < end) {
		boost::hash_combine(seed, *reinterpret_cast<const unsigned long*>(data));
		data += sizeof(unsigned long);
	}
	return seed;
}

///
/// PionIdGeneratorBase: class used to generated new PionId's
///
template <typename BaseGeneratorType>
class PionIdGeneratorBase {
public:

	/// make dynamic type for base generator available
	typedef BaseGeneratorType	base_generator_type;

	/// random number distribution type
	typedef boost::uniform_int<unsigned long>	distribution_type;

	/// random number generator type
	typedef boost::variate_generator<base_generator_type, distribution_type>	gen_type;

	/// class may be extended (virtual destructor)
	virtual ~PionIdGeneratorBase() {}

	/// default constructor
	PionIdGeneratorBase(void)
		: m_random_gen(PionId::make_seed()),
		m_random_dist((std::numeric_limits<unsigned long>::min)(), (std::numeric_limits<unsigned long>::max)()),
		m_random_die(m_random_gen, m_random_dist)
	{}

	/// returns a newly generated PionId object
	inline PionId operator()(void) { return PionId(m_random_die); }

	/// return random number generator
	inline gen_type& getRNG(void) { return m_random_die; }

	/// return random number generator
	inline unsigned long getNumber(void) { return m_random_die(); }

protected:

	/// random number generator
	base_generator_type				m_random_gen;

	/// random number distribution
	distribution_type				m_random_dist;

	/// random number die
	gen_type						m_random_die;
};

/// data type for the default PionId generator class
typedef PionIdGeneratorBase<boost::mt19937>	PionIdGenerator;

}	// end namespace pion

#endif
<|endoftext|>


<commit_before>#include "elzip_fallback.hpp"

void createDir(std::string dir) {
#ifdef _WIN32
	return bool(CreateDirectory(path.c_str(), LPSECURITY_ATTRIBUTES(NULL)));
#else
	return bool(mkdir(path.c_str(), S_IRUSR | S_IWUSR | S_IXUSR));
#endif
}

std::vector<std::string> split(const std::string &str, const std::string &delimiters) {
	std::vector<std::string> tokens;
	std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
	std::string::size_type pos = str.find_first_of(delimiters, lastPos);
	while (std::string::npos != pos || std::string::npos != lastPos) {
		tokens.push_back(str.substr(lastPos, pos - lastPos));
		lastPos = str.find_first_not_of(delimiters, pos);
		pos = str.find_first_of(delimiters, lastPos);
	}
	return tokens;
}

std::vector<std::string> listDirInDir(std::string path) {
	tinydir_dir dir;
	tinydir_open(&dir, path.c_str());

	std::vector<std::string> fileList;
	while (dir.has_next)
	{
		tinydir_file file;
		tinydir_readfile(&dir, &file);
		if (file.is_dir)
		{
			if (std::string(file.name) != "." && std::string(file.name) != "..") { fileList.push_back(std::string(file.name)); }
		}
		tinydir_next(&dir);
	}
	tinydir_close(&dir);
	return fileList;
}

std::string join(std::vector<std::string>& vector, std::string sep, int start, int end)
{
	std::string result = "";
	if (end >= vector.size())
		end = vector.size();
	if (start >= vector.size() - 1)
		start = vector.size() - 1;
	for (int i = start; i < vector.size() - end; i++)
	{
		if (i != vector.size() - 1)
			result += vector[i] + sep;
		else
			result += vector[i];
	}
	return result;
}

namespace elz
{
	void extractZip(std::string zipname, std::string target)
	{
		ziputils::unzipper zipFile;
		zipFile.open(zipname.c_str());
		for (std::string filename : zipFile.getFilenames())
		{
			std::vector<std::string> splittedPath = split(filename, "/");
			std::string parentPath = join(splittedPath, "/", 0, 1);
			std::string cDir(target + ((parentPath == "") ? "" : "/") + parentPath);
			std::string cFile(target + "/" + filename);
			std::string fillPath;
			std::string buffTest = ".";
			for (std::string pathPart : split(cDir, "/")) {

				fillPath += ((fillPath != "") ? "/" : "") + pathPart;
				if (!isInList(fillPath, listDirInDir(buffTest))) {
					createDir(fillPath.c_str());
				}
				buffTest = fillPath;
			}
			std::cout << "fb] Opening file : " << filename << std::endl;
			zipFile.openEntry(filename.c_str());
			std::ofstream wFile;
			wFile.open(cFile, std::ios_base::binary | std::ios_base::out);
			std::string dumped = zipFile.dump();
			wFile.write(dumped.c_str(), dumped.size());
			wFile.close();
		}
	}
	void extractFile(std::string zipname, std::string filename, std::string target)
	{
		ziputils::unzipper zipFile;
		zipFile.open(zipname.c_str());
		zipFile.openEntry(filename.c_str());
		std::ofstream wFile;
		wFile.open(target, std::ios_base::binary | std::ios_base::out);
		std::string dumped = zipFile.dump();
		wFile.write(dumped.c_str(), dumped.size());
		wFile.close();
	}
}<commit_msg>Fixed Elizip fallback again<commit_after>#include "elzip_fallback.hpp"

void createDir(std::string dir) {
#ifdef _WIN32
	return bool(CreateDirectory(dir.c_str(), LPSECURITY_ATTRIBUTES(NULL)));
#else
	return bool(mkdir(dir.c_str(), S_IRUSR | S_IWUSR | S_IXUSR));
#endif
}

std::vector<std::string> split(const std::string &str, const std::string &delimiters) {
	std::vector<std::string> tokens;
	std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
	std::string::size_type pos = str.find_first_of(delimiters, lastPos);
	while (std::string::npos != pos || std::string::npos != lastPos) {
		tokens.push_back(str.substr(lastPos, pos - lastPos));
		lastPos = str.find_first_not_of(delimiters, pos);
		pos = str.find_first_of(delimiters, lastPos);
	}
	return tokens;
}

std::vector<std::string> listDirInDir(std::string path) {
	tinydir_dir dir;
	tinydir_open(&dir, path.c_str());

	std::vector<std::string> fileList;
	while (dir.has_next)
	{
		tinydir_file file;
		tinydir_readfile(&dir, &file);
		if (file.is_dir)
		{
			if (std::string(file.name) != "." && std::string(file.name) != "..") { fileList.push_back(std::string(file.name)); }
		}
		tinydir_next(&dir);
	}
	tinydir_close(&dir);
	return fileList;
}

std::string join(std::vector<std::string>& vector, std::string sep, int start, int end)
{
	std::string result = "";
	if (end >= vector.size())
		end = vector.size();
	if (start >= vector.size() - 1)
		start = vector.size() - 1;
	for (int i = start; i < vector.size() - end; i++)
	{
		if (i != vector.size() - 1)
			result += vector[i] + sep;
		else
			result += vector[i];
	}
	return result;
}

namespace elz
{
	void extractZip(std::string zipname, std::string target)
	{
		ziputils::unzipper zipFile;
		zipFile.open(zipname.c_str());
		for (std::string filename : zipFile.getFilenames())
		{
			std::vector<std::string> splittedPath = split(filename, "/");
			std::string parentPath = join(splittedPath, "/", 0, 1);
			std::string cDir(target + ((parentPath == "") ? "" : "/") + parentPath);
			std::string cFile(target + "/" + filename);
			std::string fillPath;
			std::string buffTest = ".";
			for (std::string pathPart : split(cDir, "/")) {

				fillPath += ((fillPath != "") ? "/" : "") + pathPart;
				if (!isInList(fillPath, listDirInDir(buffTest))) {
					createDir(fillPath.c_str());
				}
				buffTest = fillPath;
			}
			std::cout << "fb] Opening file : " << filename << std::endl;
			zipFile.openEntry(filename.c_str());
			std::ofstream wFile;
			wFile.open(cFile, std::ios_base::binary | std::ios_base::out);
			std::string dumped = zipFile.dump();
			wFile.write(dumped.c_str(), dumped.size());
			wFile.close();
		}
	}
	void extractFile(std::string zipname, std::string filename, std::string target)
	{
		ziputils::unzipper zipFile;
		zipFile.open(zipname.c_str());
		zipFile.openEntry(filename.c_str());
		std::ofstream wFile;
		wFile.open(target, std::ios_base::binary | std::ios_base::out);
		std::string dumped = zipFile.dump();
		wFile.write(dumped.c_str(), dumped.size());
		wFile.close();
	}
}<|endoftext|>