<commit_before>#include "types.h"
#include "mmu.h"
#include "kernel.hh"
#include "spinlock.h"
#include "condvar.h"
#include "queue.h"
#include "proc.hh"
#include "fs.h"
#include "file.hh"
#include "cpu.hh"
#include "ilist.hh"
#include "uk/unistd.h"
#include "rnd.hh"

#define PIPESIZE 512

struct pipe {
  virtual ~pipe() { };
  virtual int write(const char *addr, int n) = 0;
  virtual int read(char *addr, int n) = 0;
  virtual int close(int writable) = 0;
  NEW_DELETE_OPS(pipe);
};

struct ordered : pipe {
  struct spinlock lock;
  struct condvar  cv;
  int readopen;   // read fd is still open
  int writeopen;  // write fd is still open
  u32 nread;      // number of bytes read
  u32 nwrite;     // number of bytes written
  char data[PIPESIZE];

  ordered() : readopen(1), writeopen(1), nread(0), nwrite(0) {
    lock = spinlock("pipe", LOCKSTAT_PIPE);
    cv = condvar("pipe");
  };
  ~ordered() {
  };
  NEW_DELETE_OPS(ordered);

  virtual int write(const char *addr, int n) {
    acquire(&lock);
    for(int i = 0; i < n; i++){
      while(nwrite == nread + PIPESIZE){
        if(readopen == 0 || myproc()->killed){
          release(&lock);
          return -1;
        }
        cv.wake_all();
        cv.sleep(&lock);
      }
      data[nwrite++ % PIPESIZE] = addr[i];
    }
    cv.wake_all();
    release(&lock);
    return n;
  }

  virtual int read(char *addr, int n) {
    int i;
    acquire(&lock);
    while(nread == nwrite && writeopen) {
      if(myproc()->killed){
        release(&lock);
        return -1;
      }
      cv.sleep(&lock);
    }
    for(i = 0; i < n; i++) {
      if(nread == nwrite)
        break;
      addr[i] = data[nread++ % PIPESIZE];
    }
    cv.wake_all();
    release(&lock);
    return i;
  }

  virtual int close(int writable) {
    acquire(&lock);
    if(writable){
      writeopen = 0;
    } else {
      readopen = 0;
    }
    cv.wake_all();
    if(readopen == 0 && writeopen == 0){
      release(&lock);
      return 1;
    } else
      release(&lock);
    return 0;
  }
};

// Initial support for unordered pipes by having per-core pipes.  A writer
// writes n bytes as a single unit in its local per-core pipe, from which the
// neighbor is intended to read the n bytes.  If a writer's local pipe is full,
// it sleeps until a reader to wake it up.  A reader cycles through all per-core
// pipes, starting from the next core.  If it reads from a full pipe, it wakes up
// the local writer.  If all pipes are empty, then it keeps trying.
//
// tension between load balance and performance: if there is no need for load
// balance, reader and writer should agree on a given pipe and use only that
// one.
//
// tension between space sharing and time sharing: maybe should read from local
// pipe, maybe should give up cpu when no pipe has data.
//
// XXX shouldn't cpuid has index in pipes because process may be rescheduled.
//
// XXX Should pipe track #readers, #writers?  so that we don't have to allocate
// NCPU per-core pipes.

struct corepipe {
  u32 nread;
  u32 nwrite;
  int readopen;
  char data[PIPESIZE];
  struct spinlock lock;
  struct condvar  cv;
  corepipe() : nread(0), nwrite(0), readopen(1),
               lock("corepipe", LOCKSTAT_PIPE),
               cv("pipe") {};
  ~corepipe() {};
  NEW_DELETE_OPS(corepipe);

  int write(const char *addr, int n, int sleep) {
    int r = 0;
    acquire(&lock);
    while (1) {
      if(readopen == 0 || myproc()->killed) {
        r = -1;
        break;
      }
      if (nwrite + n < nread + PIPESIZE) {
        for (int i = 0; i < n; i++)
          data[nwrite++ % PIPESIZE] = addr[i];
        r = n;
        break;
      } else if (sleep) {
        cprintf("w");
        cv.sleep(&lock);
      } else {
        break;
      }
    }
    release(&lock);
    return r;
  }

  int read(char *addr, int n) {
    int r = 0;
    acquire(&lock);
    if (nread + n <= nwrite) {
      for(int i = 0; i < n; i++)
        addr[i] = data[nread++ % PIPESIZE];
      r = n;
      // cv.wake_all();   // XXX only wakeup when it was full?
    }
    release(&lock);
    return r;
  }
};

struct unordered : pipe {
  atomic<corepipe*> pipes[NCPU];
  int writeopen;
  unordered() : writeopen(1) {
    for (int i = 0; i < NCPU; i++)
      pipes[i] = 0;
  };
  ~unordered() {
    for (int i = 0; i < NCPU; i++) {
      corepipe* c = pipes[i].load();
      if (c)
        delete c;
    }
  };
  NEW_DELETE_OPS(unordered);

  corepipe* mycorepipe(int id) {
    for (;;) {
      corepipe* c = pipes[id];
      if (c)
        return c;

      c = new corepipe;
      if (cmpxch(&pipes[id], (corepipe*) 0, c))
        return c;
      delete c;
    }
  }

  int write(const char *addr, int n) {
    int r;
    corepipe *cp = mycorepipe((mycpu()->id) % NCPU);
    do {
      r = cp->write(addr, n, 0);
      if (r < 0) break;
      cp = mycorepipe(rnd() % NCPU);    // try another pipe if cp is full
      // XXX should we give up the CPU at some point?
    } while (r != n);
    return r;
  };

  int read(char *addr, int n) {
    int r;
    while (1) {
      for (int i = (mycpu()->id + 1) % NCPU; i != mycpu()->id;
           i = (i + 1) % NCPU) {
        r = mycorepipe(i)->read(addr, n);
        if (r == n) return r;
      }
      if (writeopen == 0 || myproc()->killed) return -1;
      r = mycorepipe(mycpu()->id)->read(addr, n);
      if (r == n) return r;
      // XXX should we give up the CPU at some point?
    }

    return r;
  }

  int close(int writeable) {
    int readopen = 1;
    int r = 0;
    for (int i = 0; i < NCPU; i++) acquire(&mycorepipe(i)->lock);
    if(writeable){
      writeopen = 0;
    } else {
      for (int i = 0; i < NCPU; i++) mycorepipe(i)->readopen = 0;
      readopen = 0;
    }
    for (int i = 0; i < NCPU; i++) mycorepipe(i)->cv.wake_all();
    if(readopen == 0 && writeopen == 0) {
      r = 1;
    }
    for (int i = 0; i < NCPU; i++) release(&mycorepipe(i)->lock);
    return r;
  }
};

int
pipealloc(struct file **f0, struct file **f1, int flag)
{
  struct pipe *p;

  p = 0;
  *f0 = *f1 = 0;
  if((*f0 = file::alloc()) == 0 || (*f1 = file::alloc()) == 0)
    goto bad;
  if (flag & PIPE_UNORDED) {
    p = new unordered();
  } else {
    p = new ordered();
  }
  (*f0)->type = file::FD_PIPE;
  (*f0)->readable = 1;
  (*f0)->writable = 0;
  (*f0)->pipe = p;
  (*f1)->type = file::FD_PIPE;
  (*f1)->readable = 0;
  (*f1)->writable = 1;
  (*f1)->pipe = p;
  return 0;

 bad:
  if(p)
    delete p;
  if(*f0)
    (*f0)->dec();
  if(*f1)
    (*f1)->dec();
  return -1;
}

void
pipeclose(struct pipe *p, int writable)
{
  if (p->close(writable))
    delete p;
}

int
pipewrite(struct pipe *p, const char *addr, int n)
{
  return p->write(addr, n);
}

int
piperead(struct pipe *p, char *addr, int n)
{
  return p->read(addr, n);
}
<commit_msg>minor corepipe cleanup<commit_after>#include "types.h"
#include "mmu.h"
#include "kernel.hh"
#include "spinlock.h"
#include "condvar.h"
#include "queue.h"
#include "proc.hh"
#include "fs.h"
#include "file.hh"
#include "cpu.hh"
#include "ilist.hh"
#include "uk/unistd.h"
#include "rnd.hh"

#define PIPESIZE 512

struct pipe {
  virtual ~pipe() { };
  virtual int write(const char *addr, int n) = 0;
  virtual int read(char *addr, int n) = 0;
  virtual int close(int writable) = 0;
  NEW_DELETE_OPS(pipe);
};

struct ordered : pipe {
  struct spinlock lock;
  struct condvar  cv;
  int readopen;   // read fd is still open
  int writeopen;  // write fd is still open
  u32 nread;      // number of bytes read
  u32 nwrite;     // number of bytes written
  char data[PIPESIZE];

  ordered() : readopen(1), writeopen(1), nread(0), nwrite(0) {
    lock = spinlock("pipe", LOCKSTAT_PIPE);
    cv = condvar("pipe");
  };
  ~ordered() {
  };
  NEW_DELETE_OPS(ordered);

  virtual int write(const char *addr, int n) {
    acquire(&lock);
    for(int i = 0; i < n; i++){
      while(nwrite == nread + PIPESIZE){
        if(readopen == 0 || myproc()->killed){
          release(&lock);
          return -1;
        }
        cv.wake_all();
        cv.sleep(&lock);
      }
      data[nwrite++ % PIPESIZE] = addr[i];
    }
    cv.wake_all();
    release(&lock);
    return n;
  }

  virtual int read(char *addr, int n) {
    int i;
    acquire(&lock);
    while(nread == nwrite && writeopen) {
      if(myproc()->killed){
        release(&lock);
        return -1;
      }
      cv.sleep(&lock);
    }
    for(i = 0; i < n; i++) {
      if(nread == nwrite)
        break;
      addr[i] = data[nread++ % PIPESIZE];
    }
    cv.wake_all();
    release(&lock);
    return i;
  }

  virtual int close(int writable) {
    acquire(&lock);
    if(writable){
      writeopen = 0;
    } else {
      readopen = 0;
    }
    cv.wake_all();
    if(readopen == 0 && writeopen == 0){
      release(&lock);
      return 1;
    } else
      release(&lock);
    return 0;
  }
};

// Initial support for unordered pipes by having per-core pipes.  A writer
// writes n bytes as a single unit in its local per-core pipe, from which the
// neighbor is intended to read the n bytes.  If a writer's local pipe is full,
// it sleeps until a reader to wake it up.  A reader cycles through all per-core
// pipes, starting from the next core.  If it reads from a full pipe, it wakes up
// the local writer.  If all pipes are empty, then it keeps trying.
//
// tension between load balance and performance: if there is no need for load
// balance, reader and writer should agree on a given pipe and use only that
// one.
//
// tension between space sharing and time sharing: maybe should read from local
// pipe, maybe should give up cpu when no pipe has data.
//
// XXX shouldn't cpuid has index in pipes because process may be rescheduled.
//
// XXX Should pipe track #readers, #writers?  so that we don't have to allocate
// NCPU per-core pipes.

struct corepipe {
  u32 nread;
  u32 nwrite;
  int readopen;
  char data[PIPESIZE];
  struct spinlock lock;
  corepipe() : nread(0), nwrite(0), readopen(1),
               lock("corepipe", LOCKSTAT_PIPE) {};
  ~corepipe() {};
  NEW_DELETE_OPS(corepipe);

  int write(const char *addr, int n) {
    scoped_acquire l(&lock);

    if (readopen == 0 || myproc()->killed)
      return -1;

    if (nwrite + n < nread + PIPESIZE) {
      for (int i = 0; i < n; i++)
        data[nwrite++ % PIPESIZE] = addr[i];
      return n;
    }

    return 0;
  }

  int read(char *addr, int n) {
    scoped_acquire l(&lock);

    if (nread + n <= nwrite) {
      for (int i = 0; i < n; i++)
        addr[i] = data[nread++ % PIPESIZE];
      return n;
    }

    return 0;
  }
};

struct unordered : pipe {
  atomic<corepipe*> pipes[NCPU];
  int writeopen;
  unordered() : writeopen(1) {
    for (int i = 0; i < NCPU; i++)
      pipes[i] = 0;
  };
  ~unordered() {
    for (int i = 0; i < NCPU; i++) {
      corepipe* c = pipes[i].load();
      if (c)
        delete c;
    }
  };
  NEW_DELETE_OPS(unordered);

  corepipe* mycorepipe(int id) {
    for (;;) {
      corepipe* c = pipes[id];
      if (c)
        return c;

      c = new corepipe;
      if (cmpxch(&pipes[id], (corepipe*) 0, c))
        return c;
      delete c;
    }
  }

  int write(const char *addr, int n) {
    int r;
    corepipe *cp = mycorepipe((mycpu()->id) % NCPU);
    do {
      r = cp->write(addr, n);
      if (r < 0) break;
      cp = mycorepipe(rnd() % NCPU);    // try another pipe if cp is full
      // XXX should we give up the CPU at some point?
    } while (r != n);
    return r;
  };

  int read(char *addr, int n) {
    int r;
    while (1) {
      for (int i = (mycpu()->id + 1) % NCPU; i != mycpu()->id;
           i = (i + 1) % NCPU) {
        r = mycorepipe(i)->read(addr, n);
        if (r == n) return r;
      }
      if (writeopen == 0 || myproc()->killed) return -1;
      r = mycorepipe(mycpu()->id)->read(addr, n);
      if (r == n) return r;
      // XXX should we give up the CPU at some point?
    }

    return r;
  }

  int close(int writeable) {
    int readopen = 1;
    int r = 0;
    for (int i = 0; i < NCPU; i++) acquire(&mycorepipe(i)->lock);
    if(writeable){
      writeopen = 0;
    } else {
      for (int i = 0; i < NCPU; i++) mycorepipe(i)->readopen = 0;
      readopen = 0;
    }
    if(readopen == 0 && writeopen == 0) {
      r = 1;
    }
    for (int i = 0; i < NCPU; i++) release(&mycorepipe(i)->lock);
    return r;
  }
};

int
pipealloc(struct file **f0, struct file **f1, int flag)
{
  struct pipe *p;

  p = 0;
  *f0 = *f1 = 0;
  if((*f0 = file::alloc()) == 0 || (*f1 = file::alloc()) == 0)
    goto bad;
  if (flag & PIPE_UNORDED) {
    p = new unordered();
  } else {
    p = new ordered();
  }
  (*f0)->type = file::FD_PIPE;
  (*f0)->readable = 1;
  (*f0)->writable = 0;
  (*f0)->pipe = p;
  (*f1)->type = file::FD_PIPE;
  (*f1)->readable = 0;
  (*f1)->writable = 1;
  (*f1)->pipe = p;
  return 0;

 bad:
  if(p)
    delete p;
  if(*f0)
    (*f0)->dec();
  if(*f1)
    (*f1)->dec();
  return -1;
}

void
pipeclose(struct pipe *p, int writable)
{
  if (p->close(writable))
    delete p;
}

int
pipewrite(struct pipe *p, const char *addr, int n)
{
  return p->write(addr, n);
}

int
piperead(struct pipe *p, char *addr, int n)
{
  return p->read(addr, n);
}
<|endoftext|>


<commit_before>// Copyright 2019 Global Phasing Ltd.
//
// convert SF-mmCIF to MTZ

#include <algorithm>
#include <cstdlib>            // for exit
#include <stdio.h>
#ifndef GEMMI_ALL_IN_ONE
# define GEMMI_WRITE_IMPLEMENTATION 1
#endif
#include <gemmi/atox.hpp>     // for read_word
#include <gemmi/fileutil.hpp> // for file_open
#include <gemmi/gzread.hpp>   // for read_cif_gz
#include <gemmi/mtz.hpp>      // for Mtz
#include <gemmi/refln.hpp>    // for ReflnBlock
#include <gemmi/version.hpp>  // for GEMMI_VERSION
#define GEMMI_PROG cif2mtz
#include "options.h"

namespace cif = gemmi::cif;

enum OptionIndex { Verbose=3, BlockName, Dir, Title, History };

static const option::Descriptor Usage[] = {
  { NoOp, 0, "", "", Arg::None,
    "Usage:"
    "\n  " EXE_NAME " [options] CIF_FILE MTZ_FILE"
    "\n  " EXE_NAME " [options] CIF_FILE --dir=DIRECTORY"
    "\nOptions:"},
  { Help, 0, "h", "help", Arg::None, "  -h, --help  \tPrint usage and exit." },
  { Version, 0, "V", "version", Arg::None,
    "  -V, --version  \tPrint version and exit." },
  { Verbose, 0, "v", "verbose", Arg::None, "  --verbose  \tVerbose output." },
  { BlockName, 0, "b", "block", Arg::Required,
    "  -b NAME, --block=NAME  \tmmCIF block to convert." },
  { Dir, 0, "d", "dir", Arg::Required,
    "  -d DIR, --dir=NAME  \tOutput directory." },
  { Title, 0, "", "title", Arg::Required,
    "  --title  \tMTZ title." },
  { History, 0, "-H", "history", Arg::Required,
    "  -H LINE, --history=LINE  \tAdd a history line." },
  { NoOp, 0, "", "", Arg::None,
    "\nFirst variant: converts the first block of CIF_FILE, or the block"
    "\nspecified with --block=NAME, to MTZ file with given name."
    "\n\nSecond variant: converts each block of CIF_FILE to one MTZ file"
    "\n(block-name.mtz) in the specified DIRECTORY."
    "\n\nIf CIF_FILE is -, the input is read from stdin."
  },
  { 0, 0, 0, 0, 0, 0 }
};

struct Entry {
  const char* refln_tag;
  const char* col_label;
  char col_type;
  unsigned char dataset_id;
};

// When we have a few alternative mmCIF tags for the same MTZ label,
// they are in consecutive rows and all but the last one have null col_label.
static Entry conv_table[] = {
  {"index_h",                    "H",          'H', 0},
  {"index_k",                    "K",          'H', 0},
  {"index_l",                    "L",          'H', 0},
  {"pdbx_r_free_flag",           nullptr,      'I', 0},
  {"status",                     "FreeR_flag", 's', 0}, // s is a special flag
  {"intensity_meas",             nullptr,      'J', 1},
  {"intensity_net",              "I",          'J', 1},
  {"intensity_sigma",            "SIGI",       'Q', 1},
  {"pdbx_I_plus",                "I(+)",       'K', 1},
  {"pdbx_I_plus_sigma",          "SIGI(+)",    'M', 1},
  {"pdbx_I_minus",               "I(-)",       'K', 1},
  {"pdbx_I_minus_sigma",         "SIGI(-)",    'M', 1},
  {"F_meas_au",                  "FP",         'F', 1},
  {"F_meas_sigma_au",            "SIGFP",      'Q', 1},
  {"pdbx_F_plus",                "F(+)",       'G', 1},
  {"pdbx_F_plus_sigma",          "SIGF(+)",    'L', 1},
  {"pdbx_F_minus",               "F(-)",       'G', 1},
  {"pdbx_F_minus_sigma",         "SIGF(-)",    'L', 1},
  {"pdbx_anom_difference",       "DP",         'D', 1},
  {"pdbx_anom_difference_sigma", "SIGDP",      'Q', 1},
  {"F_calc",                     "FC",         'F', 1},
  {"phase_calc",                 "PHIC",       'P', 1},
  {"fom",                        nullptr,      'W', 1},
  {"weight",                     "FOM",        'W', 1},
  {"pdbx_HL_A_iso",              "HLA",        'A', 1},
  {"pdbx_HL_B_iso",              "HLB",        'A', 1},
  {"pdbx_HL_C_iso",              "HLC",        'A', 1},
  {"pdbx_HL_D_iso",              "HLD",        'A', 1},
  {"pdbx_FWT",                   "FWT",        'F', 1},
  {"pdbx_PHWT",                  "PHWT",       'P', 1},
  {"pdbx_DELFWT",                "DELFWT",     'F', 1},
  {"pdbx_DELPHWT",               "DELPHWT",    'P', 1},
};

inline float status_to_freeflag(const std::string& str) {
  char c = str[0];
  if (c == '\'' || c == '"')
    c = str[1];
  if (c == 'o')
    return 1.f;
  if (c == 'f')
    return 0.f;
  return NAN;
}

static
gemmi::ReflnBlock& get_block_by_name(std::vector<gemmi::ReflnBlock>& rblocks,
                                     const std::string& name) {
  for (gemmi::ReflnBlock& rb : rblocks)
    if (rb.block.name == name)
      return rb;
  gemmi::fail("block not found: " + name);
}

static
void convert_cif_block_to_mtz(const gemmi::ReflnBlock& rb,
                              const std::string& mtz_path,
                              const std::vector<option::Option>& options) {
  gemmi::Mtz mtz;
  if (options[Title])
    mtz.title = options[Title].arg;
  for (const option::Option* opt = options[History]; opt; opt = opt->next())
    mtz.history.push_back(opt->arg);
  mtz.cell = rb.cell;
  mtz.spacegroup = rb.spacegroup;
  mtz.add_dataset("HKL_base");
  mtz.add_dataset("unknown").wavelength = rb.wavelength;
  const cif::Loop* loop = rb.refln_loop ? rb.refln_loop : rb.diffrn_refln_loop;
  if (!loop)
    gemmi::fail("_refln category not found in mmCIF block: " + rb.block.name);
  if (options[Verbose])
    fprintf(stderr, "Searching tags with known MTZ equivalents ...\n");
  bool uses_status = false;
  std::vector<int> indices;
  std::string tag = loop->tags[0].substr(0, loop->tags[0].find('.') + 1);
  const size_t len = tag.length();
  for (auto c = std::begin(conv_table); c != std::end(conv_table); ++c) {
    tag.replace(len, std::string::npos, c->refln_tag);
    int index = loop->find_tag(tag);
    if (index != -1) {
      indices.push_back(index);
      mtz.columns.emplace_back();
      gemmi::Mtz::Column& col = mtz.columns.back();
      col.dataset_id = c->dataset_id;
      col.type = c->col_type;
      if (col.type == 's') {
        col.type = 'I';
        uses_status = true;
      }
      while (!c->col_label)
        ++c;
      col.label = c->col_label;
      col.parent = &mtz;
      col.idx = mtz.columns.size() - 1;
      if (options[Verbose])
        fprintf(stderr, "  %s -> %s\n", tag.c_str(), col.label.c_str());
    } else if (c->col_type == 'H') {
      gemmi::fail("Miller index tag not found: " + tag);
    }
  }
  mtz.nreflections = loop->length();
  mtz.data.resize(mtz.columns.size() * mtz.nreflections);
  int k = 0;
  for (size_t i = 0; i < loop->values.size(); i += loop->tags.size()) {
    size_t j = 0;
    for (; j != 3; ++j)
      mtz.data[k++] = (float) cif::as_int(loop->values[i + indices[j]]);
    if (uses_status)
      mtz.data[k++] = status_to_freeflag(loop->values[i + indices[j++]]);
    for (; j != indices.size(); ++j)
      mtz.data[k++] = (float) cif::as_number(loop->values[i + indices[j]]);
  }
  if (options[Verbose])
    fprintf(stderr, "Writing %s ...\n", mtz_path.c_str());
  try {
    mtz.write_to_file(mtz_path);
  } catch (std::runtime_error& e) {
    fprintf(stderr, "ERROR writing %s: %s\n", mtz_path.c_str(), e.what());
    std::exit(3);
  }
}

int GEMMI_MAIN(int argc, char **argv) {
  OptParser p(EXE_NAME);
  p.simple_parse(argc, argv, Usage);
  bool convert_all = p.options[Dir];
  p.require_positional_args(convert_all ? 1 : 2);
  bool verbose = p.options[Verbose];
  const char* cif_path = p.nonOption(0);
  if (verbose)
    fprintf(stderr, "Reading %s ...\n", cif_path);
  auto rblocks = gemmi::as_refln_blocks(gemmi::read_cif_gz(cif_path).blocks);
  if (convert_all) {
    bool ok = true;
    for (gemmi::ReflnBlock& rb : rblocks) {
      std::string path = p.options[Dir].arg;
      path += '/';
      path += rb.block.name;
      path += ".mtz";
      try {
        convert_cif_block_to_mtz(rb, path, p.options);
      } catch (std::runtime_error& e) {
        fprintf(stderr, "ERROR: %s\n", e.what());
        ok = false;
      }
    }
    if (!ok)
      return 1;
  } else {
    const char* mtz_path = p.nonOption(1);
    try {
      const gemmi::ReflnBlock& rb = p.options[BlockName]
        ? get_block_by_name(rblocks, p.options[BlockName].arg)
        : rblocks.at(0);
      convert_cif_block_to_mtz(rb, mtz_path, p.options);
    } catch (std::runtime_error& e) {
      fprintf(stderr, "ERROR: %s\n", e.what());
      return 1;
    }
  }
  if (verbose)
    fprintf(stderr, "Done.\n");
  return 0;
}

// vim:sw=2:ts=2:et:path^=../include,../third_party
<commit_msg>cif2mtz.cpp: better error handling<commit_after>// Copyright 2019 Global Phasing Ltd.
//
// convert SF-mmCIF to MTZ

#include <algorithm>
#include <cstdlib>            // for exit
#include <stdio.h>
#ifndef GEMMI_ALL_IN_ONE
# define GEMMI_WRITE_IMPLEMENTATION 1
#endif
#include <gemmi/atox.hpp>     // for read_word
#include <gemmi/fileutil.hpp> // for file_open
#include <gemmi/gzread.hpp>   // for read_cif_gz
#include <gemmi/mtz.hpp>      // for Mtz
#include <gemmi/refln.hpp>    // for ReflnBlock
#include <gemmi/version.hpp>  // for GEMMI_VERSION
#define GEMMI_PROG cif2mtz
#include "options.h"

namespace cif = gemmi::cif;

enum OptionIndex { Verbose=3, BlockName, Dir, Title, History };

static const option::Descriptor Usage[] = {
  { NoOp, 0, "", "", Arg::None,
    "Usage:"
    "\n  " EXE_NAME " [options] CIF_FILE MTZ_FILE"
    "\n  " EXE_NAME " [options] CIF_FILE --dir=DIRECTORY"
    "\nOptions:"},
  { Help, 0, "h", "help", Arg::None, "  -h, --help  \tPrint usage and exit." },
  { Version, 0, "V", "version", Arg::None,
    "  -V, --version  \tPrint version and exit." },
  { Verbose, 0, "v", "verbose", Arg::None, "  --verbose  \tVerbose output." },
  { BlockName, 0, "b", "block", Arg::Required,
    "  -b NAME, --block=NAME  \tmmCIF block to convert." },
  { Dir, 0, "d", "dir", Arg::Required,
    "  -d DIR, --dir=NAME  \tOutput directory." },
  { Title, 0, "", "title", Arg::Required,
    "  --title  \tMTZ title." },
  { History, 0, "-H", "history", Arg::Required,
    "  -H LINE, --history=LINE  \tAdd a history line." },
  { NoOp, 0, "", "", Arg::None,
    "\nFirst variant: converts the first block of CIF_FILE, or the block"
    "\nspecified with --block=NAME, to MTZ file with given name."
    "\n\nSecond variant: converts each block of CIF_FILE to one MTZ file"
    "\n(block-name.mtz) in the specified DIRECTORY."
    "\n\nIf CIF_FILE is -, the input is read from stdin."
  },
  { 0, 0, 0, 0, 0, 0 }
};

struct Entry {
  const char* refln_tag;
  const char* col_label;
  char col_type;
  unsigned char dataset_id;
};

// When we have a few alternative mmCIF tags for the same MTZ label,
// they are in consecutive rows and all but the last one have null col_label.
static Entry conv_table[] = {
  {"index_h",                    "H",          'H', 0},
  {"index_k",                    "K",          'H', 0},
  {"index_l",                    "L",          'H', 0},
  {"pdbx_r_free_flag",           nullptr,      'I', 0},
  {"status",                     "FreeR_flag", 's', 0}, // s is a special flag
  {"intensity_meas",             nullptr,      'J', 1},
  {"intensity_net",              "I",          'J', 1},
  {"intensity_sigma",            "SIGI",       'Q', 1},
  {"pdbx_I_plus",                "I(+)",       'K', 1},
  {"pdbx_I_plus_sigma",          "SIGI(+)",    'M', 1},
  {"pdbx_I_minus",               "I(-)",       'K', 1},
  {"pdbx_I_minus_sigma",         "SIGI(-)",    'M', 1},
  {"F_meas_au",                  "FP",         'F', 1},
  {"F_meas_sigma_au",            "SIGFP",      'Q', 1},
  {"pdbx_F_plus",                "F(+)",       'G', 1},
  {"pdbx_F_plus_sigma",          "SIGF(+)",    'L', 1},
  {"pdbx_F_minus",               "F(-)",       'G', 1},
  {"pdbx_F_minus_sigma",         "SIGF(-)",    'L', 1},
  {"pdbx_anom_difference",       "DP",         'D', 1},
  {"pdbx_anom_difference_sigma", "SIGDP",      'Q', 1},
  {"F_calc",                     "FC",         'F', 1},
  {"phase_calc",                 "PHIC",       'P', 1},
  {"fom",                        nullptr,      'W', 1},
  {"weight",                     "FOM",        'W', 1},
  {"pdbx_HL_A_iso",              "HLA",        'A', 1},
  {"pdbx_HL_B_iso",              "HLB",        'A', 1},
  {"pdbx_HL_C_iso",              "HLC",        'A', 1},
  {"pdbx_HL_D_iso",              "HLD",        'A', 1},
  {"pdbx_FWT",                   "FWT",        'F', 1},
  {"pdbx_PHWT",                  "PHWT",       'P', 1},
  {"pdbx_DELFWT",                "DELFWT",     'F', 1},
  {"pdbx_DELPHWT",               "DELPHWT",    'P', 1},
};

inline float status_to_freeflag(const std::string& str) {
  char c = str[0];
  if (c == '\'' || c == '"')
    c = str[1];
  if (c == 'o')
    return 1.f;
  if (c == 'f')
    return 0.f;
  return NAN;
}

static
gemmi::ReflnBlock& get_block_by_name(std::vector<gemmi::ReflnBlock>& rblocks,
                                     const std::string& name) {
  for (gemmi::ReflnBlock& rb : rblocks)
    if (rb.block.name == name)
      return rb;
  gemmi::fail("block not found: " + name);
}

static
void convert_cif_block_to_mtz(const gemmi::ReflnBlock& rb,
                              const std::string& mtz_path,
                              const std::vector<option::Option>& options) {
  gemmi::Mtz mtz;
  if (options[Title])
    mtz.title = options[Title].arg;
  for (const option::Option* opt = options[History]; opt; opt = opt->next())
    mtz.history.push_back(opt->arg);
  mtz.cell = rb.cell;
  mtz.spacegroup = rb.spacegroup;
  mtz.add_dataset("HKL_base");
  mtz.add_dataset("unknown").wavelength = rb.wavelength;
  const cif::Loop* loop = rb.refln_loop ? rb.refln_loop : rb.diffrn_refln_loop;
  if (!loop)
    gemmi::fail("_refln category not found in mmCIF block: " + rb.block.name);
  if (options[Verbose])
    fprintf(stderr, "Searching tags with known MTZ equivalents ...\n");
  bool uses_status = false;
  std::vector<int> indices;
  std::string tag = loop->tags[0].substr(0, loop->tags[0].find('.') + 1);
  const size_t len = tag.length();
  for (auto c = std::begin(conv_table); c != std::end(conv_table); ++c) {
    tag.replace(len, std::string::npos, c->refln_tag);
    int index = loop->find_tag(tag);
    if (index != -1) {
      indices.push_back(index);
      mtz.columns.emplace_back();
      gemmi::Mtz::Column& col = mtz.columns.back();
      col.dataset_id = c->dataset_id;
      col.type = c->col_type;
      if (col.type == 's') {
        col.type = 'I';
        uses_status = true;
      }
      while (!c->col_label)
        ++c;
      col.label = c->col_label;
      col.parent = &mtz;
      col.idx = mtz.columns.size() - 1;
      if (options[Verbose])
        fprintf(stderr, "  %s -> %s\n", tag.c_str(), col.label.c_str());
    } else if (c->col_type == 'H') {
      gemmi::fail("Miller index tag not found: " + tag);
    }
  }
  mtz.nreflections = loop->length();
  mtz.data.resize(mtz.columns.size() * mtz.nreflections);
  int k = 0;
  for (size_t i = 0; i < loop->values.size(); i += loop->tags.size()) {
    size_t j = 0;
    for (; j != 3; ++j)
      mtz.data[k++] = (float) cif::as_int(loop->values[i + indices[j]]);
    if (uses_status)
      mtz.data[k++] = status_to_freeflag(loop->values[i + indices[j++]]);
    for (; j != indices.size(); ++j)
      mtz.data[k++] = (float) cif::as_number(loop->values[i + indices[j]]);
  }
  if (options[Verbose])
    fprintf(stderr, "Writing %s ...\n", mtz_path.c_str());
  try {
    mtz.write_to_file(mtz_path);
  } catch (std::runtime_error& e) {
    fprintf(stderr, "ERROR writing %s: %s\n", mtz_path.c_str(), e.what());
    std::exit(3);
  }
}

int GEMMI_MAIN(int argc, char **argv) {
  OptParser p(EXE_NAME);
  p.simple_parse(argc, argv, Usage);
  bool convert_all = p.options[Dir];
  p.require_positional_args(convert_all ? 1 : 2);
  bool verbose = p.options[Verbose];
  const char* cif_path = p.nonOption(0);
  if (verbose)
    fprintf(stderr, "Reading %s ...\n", cif_path);
  try {
    auto rblocks = gemmi::as_refln_blocks(gemmi::read_cif_gz(cif_path).blocks);
    if (convert_all) {
      bool ok = true;
      for (gemmi::ReflnBlock& rb : rblocks) {
        std::string path = p.options[Dir].arg;
        path += '/';
        path += rb.block.name;
        path += ".mtz";
        try {
          convert_cif_block_to_mtz(rb, path, p.options);
        } catch (std::runtime_error& e) {
          fprintf(stderr, "ERROR: %s\n", e.what());
          ok = false;
        }
      }
      if (!ok)
        return 1;
    } else {
      const char* mtz_path = p.nonOption(1);
      const gemmi::ReflnBlock& rb = p.options[BlockName]
        ? get_block_by_name(rblocks, p.options[BlockName].arg)
        : rblocks.at(0);
      convert_cif_block_to_mtz(rb, mtz_path, p.options);
    }
  } catch (std::runtime_error& e) {
    fprintf(stderr, "ERROR: %s\n", e.what());
    return 1;
  }
  if (verbose)
    fprintf(stderr, "Done.\n");
  return 0;
}

// vim:sw=2:ts=2:et:path^=../include,../third_party
<|endoftext|>


<commit_before>#include "circles.h"

using namespace cv;

circleFinder::circleFinder(int in_var)
{
  my_pri_val = in_var;
  my_pub_val = in_var;
}

int circleFinder::getVal()
{
  return my_pri_val;
}
<commit_msg>notes<commit_after>#include "circles.h"

using namespace cv;

/*
The class circleFinder is the visual front end that provides the pixel locations
of spheres in the given frame. This can be replaced by any other class so long
as it generates information for the structureFromMotion object in a compatible
format.
*/

// perhaps this class is passed to the sfm object upon initialization
// I would need to look into the best way to do this, perhaps inheritance

circleFinder::circleFinder(int in_var)
{
  my_pri_val = in_var;
  my_pub_val = in_var;
}

int circleFinder::getVal()
{
  return my_pri_val;
}
<|endoftext|>


<commit_before>// Time:  O(2 * (1 + (9/49) + (9/49)^2 + ...)) = O(2/(1-(9/49)) = O(2.45)
// Space: O(1)

// The rand7() API is already defined for you.
// int rand7();
// @return a random integer in the range 1 to 7

class Solution {
public:
    int rand10() {
        while (true) {
            int x = (rand7() - 1) * 7 + (rand7() - 1);
            if (x < 40) {
                return x % 10 + 1;
            }
        }
    }
};
<commit_msg>Update implement-rand10-using-rand7.cpp<commit_after>// Time:  O(1.199), counted by statistics, limit would be O(log10/log7) = O(1.183)
// Space: O(1)

// The rand7() API is already defined for you.
// int rand7();
// @return a random integer in the range 1 to 7

// Reference: https://leetcode.com/problems/implement-rand10-using-rand7/discuss/151567/C++JavaPython-Average-1.199-Call-rand7-Per-rand10
class Solution {
public:
    int rand10() {
        while (cache_.empty()) {
            generate();
        }
        auto result = cache_.back(); cache_.pop_back();
        return result;
    }

private:
    void generate() {
        static const int n = 19;
        uint64_t curr = 0, range = static_cast<uint64_t>(pow(7, n));
        for (int i = 0; i < n; ++i) {
            curr += static_cast<uint64_t>(pow(7, i)) * (rand7() - 1);
        }
        while (curr < range / 10 * 10) {
            cache_.emplace_back(curr % 10 + 1);
            curr /= 10;
            range /= 10;
        }
    }
    vector<int> cache_;
};

// Time:  O(2 * (1 + (9/49) + (9/49)^2 + ...)) = O(2/(1-(9/49)) = O(2.45)
// Space: O(1)
class Solution 2{
public:
    int rand10() {
        while (true) {
            int x = (rand7() - 1) * 7 + (rand7() - 1);
            if (x < 40) {
                return x % 10 + 1;
            }
        }
    }
};
<|endoftext|>


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

#include <QStatusBar>
#include <rl/math/Constants.h>
#include <rl/math/Rotation.h>
#include <rl/mdl/Exception.h>
#include <rl/mdl/Kinematic.h>
#include <rl/mdl/JacobianInverseKinematics.h>
#include <rl/sg/Body.h>

#ifdef RL_MDL_NLOPT
#include <rl/mdl/NloptInverseKinematics.h>
#endif

#include "ConfigurationModel.h"
#include "OperationalModel.h"
#include "MainWindow.h"

OperationalModel::OperationalModel(QObject* parent) :
	QAbstractTableModel(parent),
	id(0)
{
}

OperationalModel::~OperationalModel()
{
}

int
OperationalModel::columnCount(const QModelIndex& parent) const
{
	return 6;
}

void
OperationalModel::configurationChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
{
	this->beginResetModel();
	this->endResetModel();
}

QVariant
OperationalModel::data(const QModelIndex& index, int role) const
{
	if (nullptr == MainWindow::instance()->kinematicModels[this->id])
	{
		return QVariant();
	}

	if (!index.isValid())
	{
		return QVariant();
	}

	const rl::math::Transform& transform = MainWindow::instance()->kinematicModels[this->id]->getOperationalPosition(index.row());
	rl::math::Transform::ConstTranslationPart position = transform.translation();
	rl::math::Vector3 orientation = transform.rotation().eulerAngles(2, 1, 0).reverse();

	switch (role)
	{
	case Qt::CheckStateRole:
		switch (index.column())
		{
		case 0:
			return MainWindow::instance()->operationalGoals[this->id][index.row()] ? Qt::Checked : Qt::Unchecked;
			break;
		default:
			break;
		}
		break;
	case Qt::DisplayRole:
		switch (index.column())
		{
		case 0:
		case 1:
		case 2:
			return QString::number(position(index.column()), 'f', 4) + QString(" m");
			break;
		case 3:
		case 4:
		case 5:
			return QString::number(orientation(index.column() - 3) * rl::math::constants::rad2deg, 'f', 2) + QChar(176);
			break;
		default:
			break;
		}
		break;
	case Qt::EditRole:
		switch (index.column())
		{
		case 0:
		case 1:
		case 2:
			return position(index.column());
			break;
		case 3:
		case 4:
		case 5:
			return orientation(index.column() - 3) * rl::math::constants::rad2deg;
			break;
		default:
			break;
		}
		break;
	case Qt::TextAlignmentRole:
		return QVariant(Qt::AlignRight | Qt::AlignVCenter);
		break;
	default:
		break;
	}

	return QVariant();
}

Qt::ItemFlags
OperationalModel::flags(const QModelIndex &index) const
{
	if (!index.isValid())
	{
		return Qt::NoItemFlags;
	}

	if (0 == index.column())
	{
		return QAbstractItemModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsUserCheckable;
	}

	return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}

QVariant
OperationalModel::headerData(int section, Qt::Orientation orientation, int role) const
{
	if (nullptr == MainWindow::instance()->kinematicModels[this->id])
	{
		return QVariant();
	}

	if (Qt::DisplayRole == role && Qt::Horizontal == orientation)
	{
		switch (section)
		{
		case 0:
			return "x";
			break;
		case 1:
			return "y";
			break;
		case 2:
			return "z";
			break;
		case 3:
			return "a";
			break;
		case 4:
			return "b";
			break;
		case 5:
			return "c";
			break;
		default:
			break;
		}
	}

	if (Qt::DisplayRole == role && Qt::Vertical == orientation)
	{
		return section;
	}

	return QVariant();
}

int
OperationalModel::rowCount(const QModelIndex& parent) const
{
	if (nullptr == MainWindow::instance()->kinematicModels[this->id])
	{
		return 0;
	}

	return MainWindow::instance()->kinematicModels[this->id]->getOperationalDof();
}

bool
OperationalModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
	if (nullptr == MainWindow::instance()->kinematicModels[this->id])
	{
		return false;
	}

	if (!index.isValid())
	{
		return false;
	}

	if (Qt::CheckStateRole == role)
	{
		if (0 == index.column())
		{
			MainWindow::instance()->operationalGoals[this->id][index.row()] = value.value<bool>();
		}
	}
	else if (Qt::EditRole == role)
	{
		if (rl::mdl::Kinematic* kinematic = dynamic_cast<rl::mdl::Kinematic*>(MainWindow::instance()->kinematicModels[this->id].get()))
		{
			rl::math::Transform transform = kinematic->getOperationalPosition(index.row());
			rl::math::Vector3 orientation = transform.linear().eulerAngles(2, 1, 0).reverse();

			switch (index.column())
			{
			case 0:
			case 1:
			case 2:
				transform.translation()(index.column()) = value.value<rl::math::Real>();
				break;
			case 3:
				transform.linear() = (
					rl::math::AngleAxis(orientation.z(), rl::math::Vector3::UnitZ()) *
					rl::math::AngleAxis(orientation.y(), rl::math::Vector3::UnitY()) *
					rl::math::AngleAxis(value.value<rl::math::Real>() * rl::math::constants::deg2rad, rl::math::Vector3::UnitX())
				).toRotationMatrix();
				break;
			case 4:
				transform.linear() = (
					rl::math::AngleAxis(orientation.z(), rl::math::Vector3::UnitZ()) *
					rl::math::AngleAxis(value.value<rl::math::Real>() * rl::math::constants::deg2rad, rl::math::Vector3::UnitY()) *
					rl::math::AngleAxis(orientation.x(), rl::math::Vector3::UnitX())
				).toRotationMatrix();
				break;
			case 5:
				transform.linear() = (
					rl::math::AngleAxis(value.value<rl::math::Real>() * rl::math::constants::deg2rad, rl::math::Vector3::UnitZ()) *
					rl::math::AngleAxis(orientation.y(), rl::math::Vector3::UnitY()) *
					rl::math::AngleAxis(orientation.x(), rl::math::Vector3::UnitX())
				).toRotationMatrix();
				break;
			default:
				break;
			}

			rl::math::Vector q = kinematic->getPosition();

			std::shared_ptr<rl::mdl::InverseKinematics> ik;

			if ("JacobianInverseKinematics" == MainWindow::instance()->ikAlgorithmComboBox->currentText())
			{
				ik = std::make_shared<rl::mdl::JacobianInverseKinematics>(kinematic);
				rl::mdl::JacobianInverseKinematics* jacobianIk = static_cast<rl::mdl::JacobianInverseKinematics*>(ik.get());
				jacobianIk->setDuration(std::chrono::milliseconds(MainWindow::instance()->ikDurationSpinBox->cleanText().toUInt()));
				jacobianIk->setIterations(MainWindow::instance()->ikIterationsSpinBox->cleanText().toUInt());

				if ("DLS" == MainWindow::instance()->ikJacobianComboBox->currentText())
				{
					jacobianIk->setMethod(rl::mdl::JacobianInverseKinematics::Method::dls);
				}
				else if ("SVD" == MainWindow::instance()->ikJacobianComboBox->currentText())
				{
					jacobianIk->setMethod(rl::mdl::JacobianInverseKinematics::Method::svd);
				}
				else if ("Transpose" == MainWindow::instance()->ikJacobianComboBox->currentText())
				{
					jacobianIk->setMethod(rl::mdl::JacobianInverseKinematics::Method::transpose);
				}
			}
#ifdef RL_MDL_NLOPT
			else if ("NloptInverseKinematics" == MainWindow::instance()->ikAlgorithmComboBox->currentText())
			{
				ik = std::make_shared<rl::mdl::NloptInverseKinematics>(kinematic);
				rl::mdl::NloptInverseKinematics* nloptIk = static_cast<rl::mdl::NloptInverseKinematics*>(ik.get());
				nloptIk->setDuration(std::chrono::milliseconds(MainWindow::instance()->ikDurationSpinBox->cleanText().toUInt()));
				nloptIk->setIterations(MainWindow::instance()->ikIterationsSpinBox->cleanText().toUInt());
			}
#endif

			for (std::size_t i = 0; i < kinematic->getOperationalDof(); ++i)
			{
				if (MainWindow::instance()->operationalGoals[this->id][i])
				{
					ik->addGoal(i == index.row() ? transform : kinematic->getOperationalPosition(i), i);
				}
			}

			std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
			bool solved = ik->solve();
			std::chrono::steady_clock::time_point stop = std::chrono::steady_clock::now();

			if (solved)
			{
				MainWindow::instance()->statusBar()->showMessage("IK solved in " + QString::number(std::chrono::duration<double>(stop - start).count() * rl::math::constants::unit2milli) + " ms", 2000);

				kinematic->forwardPosition();

				for (std::size_t i = 0; i < MainWindow::instance()->geometryModels[this->id]->getNumBodies(); ++i)
				{
					MainWindow::instance()->geometryModels[this->id]->getBody(i)->setFrame(kinematic->getBodyFrame(i));
				}

				emit dataChanged(this->createIndex(0, 0), this->createIndex(this->rowCount(), this->columnCount()));

				return true;
			}
			else
			{
				MainWindow::instance()->statusBar()->showMessage("IK failed", 2000);

				kinematic->setPosition(q);
				kinematic->forwardPosition();
			}
		}
	}

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

#include <QStatusBar>
#include <rl/math/Constants.h>
#include <rl/math/Rotation.h>
#include <rl/mdl/Exception.h>
#include <rl/mdl/Kinematic.h>
#include <rl/mdl/JacobianInverseKinematics.h>
#include <rl/sg/Body.h>

#ifdef RL_MDL_NLOPT
#include <rl/mdl/NloptInverseKinematics.h>
#endif

#include "ConfigurationModel.h"
#include "OperationalModel.h"
#include "MainWindow.h"

OperationalModel::OperationalModel(QObject* parent) :
	QAbstractTableModel(parent),
	id(0)
{
}

OperationalModel::~OperationalModel()
{
}

int
OperationalModel::columnCount(const QModelIndex& parent) const
{
	return 6;
}

void
OperationalModel::configurationChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
{
	this->beginResetModel();
	this->endResetModel();
}

QVariant
OperationalModel::data(const QModelIndex& index, int role) const
{
	if (nullptr == MainWindow::instance()->kinematicModels[this->id])
	{
		return QVariant();
	}

	if (!index.isValid())
	{
		return QVariant();
	}

	const rl::math::Transform& transform = MainWindow::instance()->kinematicModels[this->id]->getOperationalPosition(index.row());
	rl::math::Transform::ConstTranslationPart position = transform.translation();
	rl::math::Vector3 orientation = transform.rotation().eulerAngles(2, 1, 0).reverse();

	switch (role)
	{
	case Qt::CheckStateRole:
		switch (index.column())
		{
		case 0:
			return MainWindow::instance()->operationalGoals[this->id][index.row()] ? Qt::Checked : Qt::Unchecked;
			break;
		default:
			break;
		}
		break;
	case Qt::DisplayRole:
		switch (index.column())
		{
		case 0:
		case 1:
		case 2:
			return QString::number(position(index.column()), 'f', 4) + QString(" m");
			break;
		case 3:
		case 4:
		case 5:
			return QString::number(orientation(index.column() - 3) * rl::math::constants::rad2deg, 'f', 2) + QChar(176);
			break;
		default:
			break;
		}
		break;
	case Qt::EditRole:
		switch (index.column())
		{
		case 0:
		case 1:
		case 2:
			return position(index.column());
			break;
		case 3:
		case 4:
		case 5:
			return orientation(index.column() - 3) * rl::math::constants::rad2deg;
			break;
		default:
			break;
		}
		break;
	case Qt::TextAlignmentRole:
		return QVariant(Qt::AlignRight | Qt::AlignVCenter);
		break;
	default:
		break;
	}

	return QVariant();
}

Qt::ItemFlags
OperationalModel::flags(const QModelIndex &index) const
{
	if (!index.isValid())
	{
		return Qt::NoItemFlags;
	}

	if (0 == index.column())
	{
		return QAbstractItemModel::flags(index) | Qt::ItemIsEditable | Qt::ItemIsUserCheckable;
	}

	return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}

QVariant
OperationalModel::headerData(int section, Qt::Orientation orientation, int role) const
{
	if (nullptr == MainWindow::instance()->kinematicModels[this->id])
	{
		return QVariant();
	}

	if (Qt::DisplayRole == role && Qt::Horizontal == orientation)
	{
		switch (section)
		{
		case 0:
			return "x";
			break;
		case 1:
			return "y";
			break;
		case 2:
			return "z";
			break;
		case 3:
			return "a";
			break;
		case 4:
			return "b";
			break;
		case 5:
			return "c";
			break;
		default:
			break;
		}
	}

	if (Qt::DisplayRole == role && Qt::Vertical == orientation)
	{
		return QString::fromStdString(MainWindow::instance()->kinematicModels[this->id]->getOperationalFrame(section)->getName());
	}

	return QVariant();
}

int
OperationalModel::rowCount(const QModelIndex& parent) const
{
	if (nullptr == MainWindow::instance()->kinematicModels[this->id])
	{
		return 0;
	}

	return MainWindow::instance()->kinematicModels[this->id]->getOperationalDof();
}

bool
OperationalModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
	if (nullptr == MainWindow::instance()->kinematicModels[this->id])
	{
		return false;
	}

	if (!index.isValid())
	{
		return false;
	}

	if (Qt::CheckStateRole == role)
	{
		if (0 == index.column())
		{
			MainWindow::instance()->operationalGoals[this->id][index.row()] = value.value<bool>();
		}
	}
	else if (Qt::EditRole == role)
	{
		if (rl::mdl::Kinematic* kinematic = dynamic_cast<rl::mdl::Kinematic*>(MainWindow::instance()->kinematicModels[this->id].get()))
		{
			rl::math::Transform transform = kinematic->getOperationalPosition(index.row());
			rl::math::Vector3 orientation = transform.linear().eulerAngles(2, 1, 0).reverse();

			switch (index.column())
			{
			case 0:
			case 1:
			case 2:
				transform.translation()(index.column()) = value.value<rl::math::Real>();
				break;
			case 3:
				transform.linear() = (
					rl::math::AngleAxis(orientation.z(), rl::math::Vector3::UnitZ()) *
					rl::math::AngleAxis(orientation.y(), rl::math::Vector3::UnitY()) *
					rl::math::AngleAxis(value.value<rl::math::Real>() * rl::math::constants::deg2rad, rl::math::Vector3::UnitX())
				).toRotationMatrix();
				break;
			case 4:
				transform.linear() = (
					rl::math::AngleAxis(orientation.z(), rl::math::Vector3::UnitZ()) *
					rl::math::AngleAxis(value.value<rl::math::Real>() * rl::math::constants::deg2rad, rl::math::Vector3::UnitY()) *
					rl::math::AngleAxis(orientation.x(), rl::math::Vector3::UnitX())
				).toRotationMatrix();
				break;
			case 5:
				transform.linear() = (
					rl::math::AngleAxis(value.value<rl::math::Real>() * rl::math::constants::deg2rad, rl::math::Vector3::UnitZ()) *
					rl::math::AngleAxis(orientation.y(), rl::math::Vector3::UnitY()) *
					rl::math::AngleAxis(orientation.x(), rl::math::Vector3::UnitX())
				).toRotationMatrix();
				break;
			default:
				break;
			}

			rl::math::Vector q = kinematic->getPosition();

			std::shared_ptr<rl::mdl::InverseKinematics> ik;

			if ("JacobianInverseKinematics" == MainWindow::instance()->ikAlgorithmComboBox->currentText())
			{
				ik = std::make_shared<rl::mdl::JacobianInverseKinematics>(kinematic);
				rl::mdl::JacobianInverseKinematics* jacobianIk = static_cast<rl::mdl::JacobianInverseKinematics*>(ik.get());
				jacobianIk->setDuration(std::chrono::milliseconds(MainWindow::instance()->ikDurationSpinBox->cleanText().toUInt()));
				jacobianIk->setIterations(MainWindow::instance()->ikIterationsSpinBox->cleanText().toUInt());

				if ("DLS" == MainWindow::instance()->ikJacobianComboBox->currentText())
				{
					jacobianIk->setMethod(rl::mdl::JacobianInverseKinematics::Method::dls);
				}
				else if ("SVD" == MainWindow::instance()->ikJacobianComboBox->currentText())
				{
					jacobianIk->setMethod(rl::mdl::JacobianInverseKinematics::Method::svd);
				}
				else if ("Transpose" == MainWindow::instance()->ikJacobianComboBox->currentText())
				{
					jacobianIk->setMethod(rl::mdl::JacobianInverseKinematics::Method::transpose);
				}
			}
#ifdef RL_MDL_NLOPT
			else if ("NloptInverseKinematics" == MainWindow::instance()->ikAlgorithmComboBox->currentText())
			{
				ik = std::make_shared<rl::mdl::NloptInverseKinematics>(kinematic);
				rl::mdl::NloptInverseKinematics* nloptIk = static_cast<rl::mdl::NloptInverseKinematics*>(ik.get());
				nloptIk->setDuration(std::chrono::milliseconds(MainWindow::instance()->ikDurationSpinBox->cleanText().toUInt()));
				nloptIk->setIterations(MainWindow::instance()->ikIterationsSpinBox->cleanText().toUInt());
			}
#endif

			for (std::size_t i = 0; i < kinematic->getOperationalDof(); ++i)
			{
				if (MainWindow::instance()->operationalGoals[this->id][i])
				{
					ik->addGoal(i == index.row() ? transform : kinematic->getOperationalPosition(i), i);
				}
			}

			std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
			bool solved = ik->solve();
			std::chrono::steady_clock::time_point stop = std::chrono::steady_clock::now();

			if (solved)
			{
				MainWindow::instance()->statusBar()->showMessage("IK solved in " + QString::number(std::chrono::duration<double>(stop - start).count() * rl::math::constants::unit2milli) + " ms", 2000);

				kinematic->forwardPosition();

				for (std::size_t i = 0; i < MainWindow::instance()->geometryModels[this->id]->getNumBodies(); ++i)
				{
					MainWindow::instance()->geometryModels[this->id]->getBody(i)->setFrame(kinematic->getBodyFrame(i));
				}

				emit dataChanged(this->createIndex(0, 0), this->createIndex(this->rowCount(), this->columnCount()));

				return true;
			}
			else
			{
				MainWindow::instance()->statusBar()->showMessage("IK failed", 2000);

				kinematic->setPosition(q);
				kinematic->forwardPosition();
			}
		}
	}

	return false;
}
<|endoftext|>


<commit_before>#ifndef MP_INTRUSIVEPTR_HPP
#define MP_INTRUSIVEPTR_HPP

#include <boost/atomic.hpp>

// boost::intrusive_ptr but safe/atomic

template<typename T>
struct IntrusivePtr {
	boost::atomic<T*> ptr;

	IntrusivePtr(T* _p = NULL) : ptr(NULL) {
		if(_p) {
			intrusive_ptr_add_ref(_p);
			ptr = _p;
		}
	}

	IntrusivePtr(const IntrusivePtr& other) : ptr(NULL) {
		T* p = other.ptr.load();
		swap(IntrusivePtr(p));
	}

	~IntrusivePtr() {
		T* _p = ptr.exchange(NULL);
		if(_p)
			intrusive_ptr_release(_p);
	}

	IntrusivePtr& operator=(const IntrusivePtr& other) {
		T* p = other.ptr.load();
		swap(IntrusivePtr(p));
		return *this;
	}

	T* get() const { return ptr; }
	T& operator*() const { return *ptr; }
	T* operator->() const { return ptr; }
	operator bool() const { return ptr; }
	operator T*() const { return ptr; }
	bool operator==(const IntrusivePtr& other) const { return ptr == other.ptr; }
	bool operator!=(const IntrusivePtr& other) const { return ptr != other.ptr; }

	IntrusivePtr& swap(IntrusivePtr&& other) {
		T* old = ptr.exchange(other.ptr);
		other.ptr = old;
		return other;
	}

	IntrusivePtr exchange(T* other) {
		IntrusivePtr old = swap(IntrusivePtr(other));
		return old;
	}

	bool compare_exchange(T* expected, T* desired, T** old = NULL) {
		bool success = ptr.compare_exchange_strong(expected, desired);
		if(success && expected != desired) {
			intrusive_ptr_add_ref(desired);
			intrusive_ptr_release(expected);
		}
		if(old)
			*old = expected;
		return success;
	}

	void reset(T* _p = NULL) {
		swap(IntrusivePtr(_p));
	}
};

#endif // INTRUSIVEPTR_HPP
<commit_msg>comment IntrusivePtr<commit_after>#ifndef MP_INTRUSIVEPTR_HPP
#define MP_INTRUSIVEPTR_HPP

#include <boost/atomic.hpp>

// boost::intrusive_ptr but safe/atomic.
// I.e. pointer to an object with an embedded reference count.
// intrusive_ptr_add_ref(T*) and intrusive_ptr_release(T*) must be declared.
// You can also derive from boost::intrusive_ref_counter.

template<typename T>
struct IntrusivePtr {
	boost::atomic<T*> ptr;

	IntrusivePtr(T* _p = NULL) : ptr(NULL) {
		if(_p) {
			intrusive_ptr_add_ref(_p);
			ptr = _p;
		}
	}

	IntrusivePtr(const IntrusivePtr& other) : ptr(NULL) {
		T* p = other.ptr.load();
		swap(IntrusivePtr(p));
	}

	~IntrusivePtr() {
		T* _p = ptr.exchange(NULL);
		if(_p)
			intrusive_ptr_release(_p);
	}

	IntrusivePtr& operator=(const IntrusivePtr& other) {
		T* p = other.ptr.load();
		swap(IntrusivePtr(p));
		return *this;
	}

	T* get() const { return ptr; }
	T& operator*() const { return *ptr; }
	T* operator->() const { return ptr; }
	operator bool() const { return ptr; }
	operator T*() const { return ptr; }
	bool operator==(const IntrusivePtr& other) const { return ptr == other.ptr; }
	bool operator!=(const IntrusivePtr& other) const { return ptr != other.ptr; }

	IntrusivePtr& swap(IntrusivePtr&& other) {
		T* old = ptr.exchange(other.ptr);
		other.ptr = old;
		return other;
	}

	IntrusivePtr exchange(T* other) {
		IntrusivePtr old = swap(IntrusivePtr(other));
		return old;
	}

	bool compare_exchange(T* expected, T* desired, T** old = NULL) {
		bool success = ptr.compare_exchange_strong(expected, desired);
		if(success && expected != desired) {
			intrusive_ptr_add_ref(desired);
			intrusive_ptr_release(expected);
		}
		if(old)
			*old = expected;
		return success;
	}

	void reset(T* _p = NULL) {
		swap(IntrusivePtr(_p));
	}
};

#endif // INTRUSIVEPTR_HPP
<|endoftext|>


<commit_before>// @(#)root/rootx:$Name:  $:$Id: rootx.cxx,v 1.18 2005/09/04 09:13:27 brun Exp $
// Author: Fons Rademakers   19/02/98

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Rootx                                                                //
//                                                                      //
// Rootx is a small front-end program that starts the main ROOT module. //
// This program is called "root" in the $ROOTSYS/bin directory and the  //
// real ROOT executable is now called "root.exe" (formerly "root").     //
// Rootx puts up a splash screen giving some info about the current     //
// version of ROOT and, more importanly, it sets up the required        //
// LD_LIBRARY_PATH, SHLIB_PATH and LIBPATH environment variables        //
// (depending on the platform).                                         //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#ifdef HAVE_CONFIG
#include "config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <errno.h>

#include <netdb.h>
#include <sys/socket.h>

#if defined(__sgi) || defined(__sun)
#define HAVE_UTMPX_H
#define UTMP_NO_ADDR
#endif
#if (defined(__alpha) && !defined(__linux)) || defined(_AIX) || \
    defined(__FreeBSD__) || defined(__Lynx__) || defined(__APPLE__) || \
    defined(__OpenBSD__)
#define UTMP_NO_ADDR
#endif

#ifdef __sun
#   ifndef _REENTRANT
#      if __SUNPRO_CC > 0x420
#         define GLOBAL_ERRNO
#      endif
#   endif
#endif

#ifndef __VMS
# ifdef HAVE_UTMPX_H
# include <utmpx.h>
# define STRUCT_UTMP struct utmpx
# else
# if defined(__linux) && defined(__powerpc) && (__GNUC__ == 2) && (__GNUC_MINOR__ < 90)
   extern "C" {
# endif
# include <utmp.h>
# define STRUCT_UTMP struct utmp
# endif
#endif

#if !defined(UTMP_FILE) && defined(_PATH_UTMP)      // 4.4BSD
#define UTMP_FILE _PATH_UTMP
#endif
#if defined(UTMPX_FILE)                             // Solaris, SysVr4
#undef  UTMP_FILE
#define UTMP_FILE UTMPX_FILE
#endif
#ifndef UTMP_FILE
#define UTMP_FILE "/etc/utmp"
#endif

#if defined(__CYGWIN__) && defined(__GNUC__)
#define ROOTBINARY "root_exe.exe"
#else
#define ROOTBINARY "root.exe"
#endif

extern void PopupLogo(bool);
extern void WaitLogo();
extern void PopdownLogo();
extern void CloseDisplay();

static STRUCT_UTMP *gUtmpContents;
static bool gNoLogo = false;

static int GetErrno()
{
#ifdef GLOBAL_ERRNO
   return ::errno;
#else
   return errno;
#endif
}

static void ResetErrno()
{
#ifdef GLOBAL_ERRNO
   ::errno = 0;
#else
   errno = 0;
#endif
}

static int ReadUtmp()
{
   FILE  *utmp;
   struct stat file_stats;
   size_t n_read, size;

   gUtmpContents = 0;

   utmp = fopen(UTMP_FILE, "r");
   if (!utmp)
      return 0;

   fstat(fileno(utmp), &file_stats);
   size = file_stats.st_size;
   if (size <= 0) {
      fclose(utmp);
      return 0;
   }

   gUtmpContents = (STRUCT_UTMP *) malloc(size);
   if (!gUtmpContents) return 0;

   n_read = fread(gUtmpContents, 1, size, utmp);
   if (ferror(utmp) || fclose(utmp) == EOF || n_read < size) {
      free(gUtmpContents);
      gUtmpContents = 0;
      return 0;
   }

   return size / sizeof(STRUCT_UTMP);
}

static STRUCT_UTMP *SearchEntry(int n, const char *tty)
{
   STRUCT_UTMP *ue = gUtmpContents;

   while (n--) {
      if (ue->ut_name[0] && !strncmp(tty, ue->ut_line, sizeof(ue->ut_line)))
         return ue;
      ue++;
   }
   return 0;
}

static void SetDisplay()
{
   // Set DISPLAY environment variable.

   if (!getenv("DISPLAY")) {
      char *tty = ttyname(0);  // device user is logged in on
      if (tty) {
         tty += 5;             // remove "/dev/"
         STRUCT_UTMP *utmp_entry = SearchEntry(ReadUtmp(), tty);
         if (utmp_entry) {
            static char display[64];
            if (utmp_entry->ut_host[0]) {
               if (strchr(utmp_entry->ut_host, ':')) {
                  sprintf(display, "DISPLAY=%s", utmp_entry->ut_host);
                  fprintf(stderr, "*** DISPLAY not set, setting it to %s\n",
                          utmp_entry->ut_host);
               } else {
                  sprintf(display, "DISPLAY=%s:0.0", utmp_entry->ut_host);
                  fprintf(stderr, "*** DISPLAY not set, setting it to %s:0.0\n",
                          utmp_entry->ut_host);
               }
               putenv((char *)display);
#ifndef UTMP_NO_ADDR
            } else if (utmp_entry->ut_addr) {
               struct hostent *he;
               if ((he = gethostbyaddr((const char*)&utmp_entry->ut_addr,
                                       sizeof(utmp_entry->ut_addr), AF_INET))) {
                  sprintf(display, "DISPLAY=%s:0.0", he->h_name);
                  fprintf(stderr, "*** DISPLAY not set, setting it to %s:0.0\n",
                          he->h_name);
                  putenv((char *)display);
               }
#endif
            }
         }
         free(gUtmpContents);
      }
   }
}

static void SetLibraryPath()
{
#ifndef ROOTLIBDIR
   // Set library path for the different platforms.

   char *msg;

#  if defined(__hpux)  || defined(_HIUX_SOURCE)
   if (getenv("SHLIB_PATH")) {
      msg = new char [strlen(getenv("ROOTSYS"))+strlen(getenv("SHLIB_PATH"))+100];
      sprintf(msg, "SHLIB_PATH=%s/lib:%s", getenv("ROOTSYS"),
                                           getenv("SHLIB_PATH"));
   } else {
      msg = new char [strlen(getenv("ROOTSYS"))+100];
      sprintf(msg, "SHLIB_PATH=%s/lib", getenv("ROOTSYS"));
   }
#  elif defined(_AIX)
   if (getenv("LIBPATH")) {
      msg = new char [strlen(getenv("ROOTSYS"))+strlen(getenv("LIBPATH"))+100];
      sprintf(msg, "LIBPATH=%s/lib:%s", getenv("ROOTSYS"),
                                        getenv("LIBPATH"));
   } else {
      msg = new char [strlen(getenv("ROOTSYS"))+100];
      sprintf(msg, "LIBPATH=%s/lib:/lib:/usr/lib", getenv("ROOTSYS"));
   }
#  elif defined(__APPLE__)
   if (getenv("DYLD_LIBRARY_PATH")) {
      msg = new char [strlen(getenv("ROOTSYS"))+strlen(getenv("DYLD_LIBRARY_PATH"))+100];
      sprintf(msg, "DYLD_LIBRARY_PATH=%s/lib:%s", getenv("ROOTSYS"),
                                                  getenv("DYLD_LIBRARY_PATH"));
   } else {
      msg = new char [strlen(getenv("ROOTSYS"))+100];
      sprintf(msg, "DYLD_LIBRARY_PATH=%s/lib", getenv("ROOTSYS"));
   }
#  else
   if (getenv("LD_LIBRARY_PATH")) {
      msg = new char [strlen(getenv("ROOTSYS"))+strlen(getenv("LD_LIBRARY_PATH"))+100];
      sprintf(msg, "LD_LIBRARY_PATH=%s/lib:%s", getenv("ROOTSYS"),
                                                getenv("LD_LIBRARY_PATH"));
   } else {
      msg = new char [strlen(getenv("ROOTSYS"))+100];
#  if defined(__sun)
      sprintf(msg, "LD_LIBRARY_PATH=%s/lib:/usr/dt/lib", getenv("ROOTSYS"));
#  else
      sprintf(msg, "LD_LIBRARY_PATH=%s/lib", getenv("ROOTSYS"));
#  endif
   }
#  endif
   putenv(msg);
#endif
}

extern "C" {
   static void SigUsr1(int);
}

static void SigUsr1(int)
{
   // When we get SIGUSR1 from child (i.e. ROOT) then pop down logo.

   if (!gNoLogo)
      PopdownLogo();
}

static void WaitChild(int childpid)
{
   // Wait till child (i.e. ROOT) is finished.

   int status;

   do {
      while (waitpid(childpid, &status, WUNTRACED) < 0) {
         if (GetErrno() != EINTR)
            break;
         ResetErrno();
      }

      if (WIFEXITED(status))
         exit(WEXITSTATUS(status));

      if (WIFSIGNALED(status))
         exit(WTERMSIG(status));

      if (WIFSTOPPED(status)) {         // child got ctlr-Z
         raise(SIGTSTP);                // stop also parent
         kill(childpid, SIGCONT);       // if parent wakes up, wake up child
      }
   } while (WIFSTOPPED(status));

   exit(0);
}

static void PrintUsage(char *pname)
{
   // This is a copy of the text in TApplication::GetOptions().

   fprintf(stderr, "Usage: %s [-l] [-b] [-n] [-q] [dir] [file1.C ... fileN.C]\n", pname);
   fprintf(stderr, "Options:\n");
   fprintf(stderr, "  -b : run in batch mode without graphics\n");
   fprintf(stderr, "  -n : do not execute logon and logoff macros as specified in .rootrc\n");
   fprintf(stderr, "  -q : exit after processing command line macro files\n");
   fprintf(stderr, "  -l : do not show splash screen\n");
   fprintf(stderr, " dir : if dir is a valid directory cd to it before executing\n");
   fprintf(stderr, "\n");
   fprintf(stderr, "  -?      : print usage\n");
   fprintf(stderr, "  -h      : print usage\n");
   fprintf(stderr, "  --help  : print usage\n");
   fprintf(stderr, "  -config : print ./configure options\n");
   fprintf(stderr, "\n");
}

int main(int argc, char **argv)
{
   const int kMAXARGS = 256;
   char *argvv[kMAXARGS];
   char  arg0[2048];

#ifndef ROOTPREFIX
   if (!getenv("ROOTSYS")) {
      fprintf(stderr, "%s: ROOTSYS not set. Set it before trying to run %s.\n",
              argv[0], argv[0]);
      return 1;
   }
#endif

   // In batch mode don't show splash screen, idem for no logo mode,
   // in about mode show always splash screen
   bool batch = false, about = false;
   int i;
   for (i = 1; i < argc; i++) {
      if (!strcmp(argv[i], "-?") || !strncmp(argv[i], "-h", 2) ||
          !strncmp(argv[i], "--help", 6)) {
         PrintUsage(argv[0]);
         return 1;
      }
      if (!strcmp(argv[i], "-b"))      batch   = true;
      if (!strcmp(argv[i], "-l"))      gNoLogo = true;
      if (!strcmp(argv[i], "-a"))      about   = true;
      if (!strcmp(argv[i], "-config")) gNoLogo = true;
   }
   if (batch)
      gNoLogo = true;
   if (about) {
      batch   = false;
      gNoLogo = false;
   }

   if (!batch) {
      SetDisplay();
      if (!getenv("DISPLAY")) {
         fprintf(stderr, "%s: can't figure out DISPLAY, set it manually\n", argv[0]);
         return 1;
      }
      if (about) {
         PopupLogo(true);
         WaitLogo();
         return 0;
      } else if (!gNoLogo)
         PopupLogo(false);
   }

   // Ignore SIGINT and SIGQUIT. Install handler for SIGUSR1.

   struct sigaction ignore, handle, saveintr, savequit, saveusr1;

#if defined(__sun) && !defined(__i386) && !defined(__SVR4)
   ignore.sa_handler = (void (*)())SIG_IGN;
#elif defined(__sun) && defined(__SVR4)
   ignore.sa_handler = (void (*)(int))SIG_IGN;
#else
   ignore.sa_handler = SIG_IGN;
#endif
   sigemptyset(&ignore.sa_mask);
   ignore.sa_flags = 0;
   handle = ignore;
#if defined(__sun) && !defined(__i386) && !defined(__SVR4)
   handle.sa_handler = (void (*)())SigUsr1;
#elif defined(__sun) && defined(__SVR4)
   handle.sa_handler = SigUsr1;
#elif (defined(__sgi) && !defined(__KCC)) || defined(__Lynx__)
#   if defined(IRIX64) || (__GNUG__>=3)
   handle.sa_handler = SigUsr1;
#   else
   handle.sa_handler = (void (*)(...))SigUsr1;
#   endif
#else
   handle.sa_handler = SigUsr1;
#endif
   sigaction(SIGINT,  &ignore, &saveintr);
   sigaction(SIGQUIT, &ignore, &savequit);
   sigaction(SIGUSR1, &handle, &saveusr1);

   // Create child...

   int childpid;
   if ((childpid = fork()) < 0) {
      fprintf(stderr, "%s: error forking child\n", argv[0]);
      return 1;
   } else if (childpid > 0) {
      if (!gNoLogo)
         WaitLogo();
      WaitChild(childpid);
   }

   // Continue with child...

   // Restore original signal actions
   sigaction(SIGINT,  &saveintr, 0);
   sigaction(SIGQUIT, &savequit, 0);
   sigaction(SIGUSR1, &saveusr1, 0);

   // Close X display connection
   CloseDisplay();

   // Child is going to overlay itself with the actual ROOT module...

   // Build argv vector
#ifdef ROOTBINDIR
   sprintf(arg0, "%s/%s", ROOTBINDIR, ROOTBINARY);
#else
   sprintf(arg0, "%s/bin/%s", getenv("ROOTSYS"), ROOTBINARY);
#endif
   argvv[0] = arg0;
   argvv[1] = (char *) "-splash";

   int iargc = argc;
   if (iargc > kMAXARGS-2) iargc = kMAXARGS-2;
   for (i = 1; i < iargc; i++)
      argvv[1+i] = argv[i];
   argvv[1+i] = 0;

   // Make sure library path is set
   SetLibraryPath();

   // Execute actual ROOT module
   execv(arg0, argvv);

   // Exec failed
#ifndef ROOTBINDIR
   fprintf(stderr,
           "%s: can't start ROOT -- check that %s/bin/%s exists!\n",
           argv[0], getenv("ROOTSYS"), ROOTBINARY);
#else
   fprintf(stderr, "%s: can't start ROOT -- check that %s/%s exists!\n",
           argv[0], ROOTBINDIR, ROOTBINARY);
#endif

   return 1;
}

<commit_msg>make sure that the utmp host field is not truncated. Could easily happen on Mac OS X where the host field is only 16 long.<commit_after>// @(#)root/rootx:$Name:  $:$Id: rootx.cxx,v 1.19 2005/09/13 13:29:51 rdm Exp $
// Author: Fons Rademakers   19/02/98

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Rootx                                                                //
//                                                                      //
// Rootx is a small front-end program that starts the main ROOT module. //
// This program is called "root" in the $ROOTSYS/bin directory and the  //
// real ROOT executable is now called "root.exe" (formerly "root").     //
// Rootx puts up a splash screen giving some info about the current     //
// version of ROOT and, more importanly, it sets up the required        //
// LD_LIBRARY_PATH, SHLIB_PATH and LIBPATH environment variables        //
// (depending on the platform).                                         //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#ifdef HAVE_CONFIG
#include "config.h"
#endif

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <errno.h>

#include <netdb.h>
#include <sys/socket.h>

#if defined(__sgi) || defined(__sun)
#define HAVE_UTMPX_H
#define UTMP_NO_ADDR
#endif
#if (defined(__alpha) && !defined(__linux)) || defined(_AIX) || \
    defined(__FreeBSD__) || defined(__Lynx__) || defined(__APPLE__) || \
    defined(__OpenBSD__)
#define UTMP_NO_ADDR
#endif

#ifdef __sun
#   ifndef _REENTRANT
#      if __SUNPRO_CC > 0x420
#         define GLOBAL_ERRNO
#      endif
#   endif
#endif

#ifndef __VMS
# ifdef HAVE_UTMPX_H
# include <utmpx.h>
# define STRUCT_UTMP struct utmpx
# else
# if defined(__linux) && defined(__powerpc) && (__GNUC__ == 2) && (__GNUC_MINOR__ < 90)
   extern "C" {
# endif
# include <utmp.h>
# define STRUCT_UTMP struct utmp
# endif
#endif

#if !defined(UTMP_FILE) && defined(_PATH_UTMP)      // 4.4BSD
#define UTMP_FILE _PATH_UTMP
#endif
#if defined(UTMPX_FILE)                             // Solaris, SysVr4
#undef  UTMP_FILE
#define UTMP_FILE UTMPX_FILE
#endif
#ifndef UTMP_FILE
#define UTMP_FILE "/etc/utmp"
#endif

#if defined(__CYGWIN__) && defined(__GNUC__)
#define ROOTBINARY "root_exe.exe"
#else
#define ROOTBINARY "root.exe"
#endif

extern void PopupLogo(bool);
extern void WaitLogo();
extern void PopdownLogo();
extern void CloseDisplay();

static STRUCT_UTMP *gUtmpContents;
static bool gNoLogo = false;

static int GetErrno()
{
#ifdef GLOBAL_ERRNO
   return ::errno;
#else
   return errno;
#endif
}

static void ResetErrno()
{
#ifdef GLOBAL_ERRNO
   ::errno = 0;
#else
   errno = 0;
#endif
}

static int ReadUtmp()
{
   FILE  *utmp;
   struct stat file_stats;
   size_t n_read, size;

   gUtmpContents = 0;

   utmp = fopen(UTMP_FILE, "r");
   if (!utmp)
      return 0;

   fstat(fileno(utmp), &file_stats);
   size = file_stats.st_size;
   if (size <= 0) {
      fclose(utmp);
      return 0;
   }

   gUtmpContents = (STRUCT_UTMP *) malloc(size);
   if (!gUtmpContents) return 0;

   n_read = fread(gUtmpContents, 1, size, utmp);
   if (ferror(utmp) || fclose(utmp) == EOF || n_read < size) {
      free(gUtmpContents);
      gUtmpContents = 0;
      return 0;
   }

   return size / sizeof(STRUCT_UTMP);
}

static STRUCT_UTMP *SearchEntry(int n, const char *tty)
{
   STRUCT_UTMP *ue = gUtmpContents;

   while (n--) {
      if (ue->ut_name[0] && !strncmp(tty, ue->ut_line, sizeof(ue->ut_line)))
         return ue;
      ue++;
   }
   return 0;
}

static void SetDisplay()
{
   // Set DISPLAY environment variable.

   if (!getenv("DISPLAY")) {
      char *tty = ttyname(0);  // device user is logged in on
      if (tty) {
         tty += 5;             // remove "/dev/"
         STRUCT_UTMP *utmp_entry = SearchEntry(ReadUtmp(), tty);
         if (utmp_entry) {
            static char display[64];
            if (utmp_entry->ut_host[0] &&
                !utmp_entry->ut_host[sizeof(utmp_entry->ut_host)-1]) {
               if (strchr(utmp_entry->ut_host, ':')) {
                  sprintf(display, "DISPLAY=%s", utmp_entry->ut_host);
                  fprintf(stderr, "*** DISPLAY not set, setting it to %s\n",
                          utmp_entry->ut_host);
               } else {
                  sprintf(display, "DISPLAY=%s:0.0", utmp_entry->ut_host);
                  fprintf(stderr, "*** DISPLAY not set, setting it to %s:0.0\n",
                          utmp_entry->ut_host);
               }
               putenv((char *)display);
#ifndef UTMP_NO_ADDR
            } else if (utmp_entry->ut_addr) {
               struct hostent *he;
               if ((he = gethostbyaddr((const char*)&utmp_entry->ut_addr,
                                       sizeof(utmp_entry->ut_addr), AF_INET))) {
                  sprintf(display, "DISPLAY=%s:0.0", he->h_name);
                  fprintf(stderr, "*** DISPLAY not set, setting it to %s:0.0\n",
                          he->h_name);
                  putenv((char *)display);
               }
#endif
            }
         }
         free(gUtmpContents);
      }
   }
}

static void SetLibraryPath()
{
#ifndef ROOTLIBDIR
   // Set library path for the different platforms.

   char *msg;

#  if defined(__hpux)  || defined(_HIUX_SOURCE)
   if (getenv("SHLIB_PATH")) {
      msg = new char [strlen(getenv("ROOTSYS"))+strlen(getenv("SHLIB_PATH"))+100];
      sprintf(msg, "SHLIB_PATH=%s/lib:%s", getenv("ROOTSYS"),
                                           getenv("SHLIB_PATH"));
   } else {
      msg = new char [strlen(getenv("ROOTSYS"))+100];
      sprintf(msg, "SHLIB_PATH=%s/lib", getenv("ROOTSYS"));
   }
#  elif defined(_AIX)
   if (getenv("LIBPATH")) {
      msg = new char [strlen(getenv("ROOTSYS"))+strlen(getenv("LIBPATH"))+100];
      sprintf(msg, "LIBPATH=%s/lib:%s", getenv("ROOTSYS"),
                                        getenv("LIBPATH"));
   } else {
      msg = new char [strlen(getenv("ROOTSYS"))+100];
      sprintf(msg, "LIBPATH=%s/lib:/lib:/usr/lib", getenv("ROOTSYS"));
   }
#  elif defined(__APPLE__)
   if (getenv("DYLD_LIBRARY_PATH")) {
      msg = new char [strlen(getenv("ROOTSYS"))+strlen(getenv("DYLD_LIBRARY_PATH"))+100];
      sprintf(msg, "DYLD_LIBRARY_PATH=%s/lib:%s", getenv("ROOTSYS"),
                                                  getenv("DYLD_LIBRARY_PATH"));
   } else {
      msg = new char [strlen(getenv("ROOTSYS"))+100];
      sprintf(msg, "DYLD_LIBRARY_PATH=%s/lib", getenv("ROOTSYS"));
   }
#  else
   if (getenv("LD_LIBRARY_PATH")) {
      msg = new char [strlen(getenv("ROOTSYS"))+strlen(getenv("LD_LIBRARY_PATH"))+100];
      sprintf(msg, "LD_LIBRARY_PATH=%s/lib:%s", getenv("ROOTSYS"),
                                                getenv("LD_LIBRARY_PATH"));
   } else {
      msg = new char [strlen(getenv("ROOTSYS"))+100];
#  if defined(__sun)
      sprintf(msg, "LD_LIBRARY_PATH=%s/lib:/usr/dt/lib", getenv("ROOTSYS"));
#  else
      sprintf(msg, "LD_LIBRARY_PATH=%s/lib", getenv("ROOTSYS"));
#  endif
   }
#  endif
   putenv(msg);
#endif
}

extern "C" {
   static void SigUsr1(int);
}

static void SigUsr1(int)
{
   // When we get SIGUSR1 from child (i.e. ROOT) then pop down logo.

   if (!gNoLogo)
      PopdownLogo();
}

static void WaitChild(int childpid)
{
   // Wait till child (i.e. ROOT) is finished.

   int status;

   do {
      while (waitpid(childpid, &status, WUNTRACED) < 0) {
         if (GetErrno() != EINTR)
            break;
         ResetErrno();
      }

      if (WIFEXITED(status))
         exit(WEXITSTATUS(status));

      if (WIFSIGNALED(status))
         exit(WTERMSIG(status));

      if (WIFSTOPPED(status)) {         // child got ctlr-Z
         raise(SIGTSTP);                // stop also parent
         kill(childpid, SIGCONT);       // if parent wakes up, wake up child
      }
   } while (WIFSTOPPED(status));

   exit(0);
}

static void PrintUsage(char *pname)
{
   // This is a copy of the text in TApplication::GetOptions().

   fprintf(stderr, "Usage: %s [-l] [-b] [-n] [-q] [dir] [file1.C ... fileN.C]\n", pname);
   fprintf(stderr, "Options:\n");
   fprintf(stderr, "  -b : run in batch mode without graphics\n");
   fprintf(stderr, "  -n : do not execute logon and logoff macros as specified in .rootrc\n");
   fprintf(stderr, "  -q : exit after processing command line macro files\n");
   fprintf(stderr, "  -l : do not show splash screen\n");
   fprintf(stderr, " dir : if dir is a valid directory cd to it before executing\n");
   fprintf(stderr, "\n");
   fprintf(stderr, "  -?      : print usage\n");
   fprintf(stderr, "  -h      : print usage\n");
   fprintf(stderr, "  --help  : print usage\n");
   fprintf(stderr, "  -config : print ./configure options\n");
   fprintf(stderr, "\n");
}

int main(int argc, char **argv)
{
   const int kMAXARGS = 256;
   char *argvv[kMAXARGS];
   char  arg0[2048];

#ifndef ROOTPREFIX
   if (!getenv("ROOTSYS")) {
      fprintf(stderr, "%s: ROOTSYS not set. Set it before trying to run %s.\n",
              argv[0], argv[0]);
      return 1;
   }
#endif

   // In batch mode don't show splash screen, idem for no logo mode,
   // in about mode show always splash screen
   bool batch = false, about = false;
   int i;
   for (i = 1; i < argc; i++) {
      if (!strcmp(argv[i], "-?") || !strncmp(argv[i], "-h", 2) ||
          !strncmp(argv[i], "--help", 6)) {
         PrintUsage(argv[0]);
         return 1;
      }
      if (!strcmp(argv[i], "-b"))      batch   = true;
      if (!strcmp(argv[i], "-l"))      gNoLogo = true;
      if (!strcmp(argv[i], "-a"))      about   = true;
      if (!strcmp(argv[i], "-config")) gNoLogo = true;
   }
   if (batch)
      gNoLogo = true;
   if (about) {
      batch   = false;
      gNoLogo = false;
   }

   if (!batch) {
      SetDisplay();
      if (!getenv("DISPLAY")) {
         fprintf(stderr, "%s: can't figure out DISPLAY, set it manually\n", argv[0]);
         return 1;
      }
      if (about) {
         PopupLogo(true);
         WaitLogo();
         return 0;
      } else if (!gNoLogo)
         PopupLogo(false);
   }

   // Ignore SIGINT and SIGQUIT. Install handler for SIGUSR1.

   struct sigaction ignore, handle, saveintr, savequit, saveusr1;

#if defined(__sun) && !defined(__i386) && !defined(__SVR4)
   ignore.sa_handler = (void (*)())SIG_IGN;
#elif defined(__sun) && defined(__SVR4)
   ignore.sa_handler = (void (*)(int))SIG_IGN;
#else
   ignore.sa_handler = SIG_IGN;
#endif
   sigemptyset(&ignore.sa_mask);
   ignore.sa_flags = 0;
   handle = ignore;
#if defined(__sun) && !defined(__i386) && !defined(__SVR4)
   handle.sa_handler = (void (*)())SigUsr1;
#elif defined(__sun) && defined(__SVR4)
   handle.sa_handler = SigUsr1;
#elif (defined(__sgi) && !defined(__KCC)) || defined(__Lynx__)
#   if defined(IRIX64) || (__GNUG__>=3)
   handle.sa_handler = SigUsr1;
#   else
   handle.sa_handler = (void (*)(...))SigUsr1;
#   endif
#else
   handle.sa_handler = SigUsr1;
#endif
   sigaction(SIGINT,  &ignore, &saveintr);
   sigaction(SIGQUIT, &ignore, &savequit);
   sigaction(SIGUSR1, &handle, &saveusr1);

   // Create child...

   int childpid;
   if ((childpid = fork()) < 0) {
      fprintf(stderr, "%s: error forking child\n", argv[0]);
      return 1;
   } else if (childpid > 0) {
      if (!gNoLogo)
         WaitLogo();
      WaitChild(childpid);
   }

   // Continue with child...

   // Restore original signal actions
   sigaction(SIGINT,  &saveintr, 0);
   sigaction(SIGQUIT, &savequit, 0);
   sigaction(SIGUSR1, &saveusr1, 0);

   // Close X display connection
   CloseDisplay();

   // Child is going to overlay itself with the actual ROOT module...

   // Build argv vector
#ifdef ROOTBINDIR
   sprintf(arg0, "%s/%s", ROOTBINDIR, ROOTBINARY);
#else
   sprintf(arg0, "%s/bin/%s", getenv("ROOTSYS"), ROOTBINARY);
#endif
   argvv[0] = arg0;
   argvv[1] = (char *) "-splash";

   int iargc = argc;
   if (iargc > kMAXARGS-2) iargc = kMAXARGS-2;
   for (i = 1; i < iargc; i++)
      argvv[1+i] = argv[i];
   argvv[1+i] = 0;

   // Make sure library path is set
   SetLibraryPath();

   // Execute actual ROOT module
   execv(arg0, argvv);

   // Exec failed
#ifndef ROOTBINDIR
   fprintf(stderr,
           "%s: can't start ROOT -- check that %s/bin/%s exists!\n",
           argv[0], getenv("ROOTSYS"), ROOTBINARY);
#else
   fprintf(stderr, "%s: can't start ROOT -- check that %s/%s exists!\n",
           argv[0], ROOTBINDIR, ROOTBINARY);
#endif

   return 1;
}

<|endoftext|>