<commit_before>#include <node.h>
#include <node_buffer.h>
#include <v8.h>

#define FUSE_USE_VERSION 26

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/time.h>
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#endif

#include <fuse.h>
#include <semaphore.h>
#include <string>

using namespace v8;

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

static struct {
  uv_async_t async;
  sem_t sem;
  pthread_t fuse_thread;
  char root[256];
  Persistent<Object> handlers;
  Persistent<Object> nodeBuffer;
} f4js;

enum fuseop_t {
  OP_GETATTR = 0,
  OP_READDIR,
  OP_OPEN,
  OP_READ,
  OP_WRITE,
  OP_CREATE,
  OP_UNLINK,
  OP_RENAME,
  OP_MKDIR,
  OP_RMDIR,
  OP_INIT,
  OP_DESTROY
};

const char* fuseop_names[] = {
    "getattr",
    "readdir",
    "open",
    "read",
    "write",
    "create",
    "unlink",
    "rename",
    "mkdir",
    "rmdir",
    "init",
    "destroy"
};

static struct {
  enum fuseop_t op;
  const char *in_path;
  union {
    struct {
      struct stat *stbuf;
    } getattr;
    struct {
      void *buf;
      fuse_fill_dir_t filler;
    } readdir;
    struct {
      off_t offset;
      size_t len;
      char *dstBuf;
      const char *srcBuf;
    } rw;
    struct {
      const char *dst;
    } rename;
  } u;
  int retval;
} f4js_cmd;

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

static int f4js_rpc(enum fuseop_t op, const char *path)
{
  f4js_cmd.op = op;
  f4js_cmd.in_path = path;
  uv_async_send(&f4js.async);
  sem_wait(&f4js.sem);
  return f4js_cmd.retval;
}

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

static int f4js_getattr(const char *path, struct stat *stbuf)
{
  f4js_cmd.u.getattr.stbuf = stbuf;
  return f4js_rpc(OP_GETATTR, path);
}

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

static int f4js_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
		         off_t offset, struct fuse_file_info *fi)
{
  f4js_cmd.u.readdir.buf = buf;
  f4js_cmd.u.readdir.filler = filler;
  return f4js_rpc(OP_READDIR, path);
}

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

int f4js_open(const char *path, struct fuse_file_info *)
{
  return f4js_rpc(OP_OPEN, path);
}

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

int f4js_read (const char *path,
               char *buf,
               size_t len,
               off_t offset,
               struct fuse_file_info *)
{
  f4js_cmd.u.rw.offset = offset;
  f4js_cmd.u.rw.len = len;
  f4js_cmd.u.rw.dstBuf = buf;
  return f4js_rpc(OP_READ, path);
}

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

int f4js_write (const char *path,
                const char *buf,
                size_t len,
                off_t offset,
                struct fuse_file_info *)
{
  f4js_cmd.u.rw.offset = offset;
  f4js_cmd.u.rw.len = len;
  f4js_cmd.u.rw.srcBuf = buf;
  return f4js_rpc(OP_WRITE, path);
}

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

int f4js_create (const char *path,
                 mode_t mode,
                 struct fuse_file_info *)
{
  return f4js_rpc(OP_CREATE, path);
}

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

int f4js_utimens (const char *,
                  const struct timespec tv[2])
{
  return 0; // stub out for now to make "touch" command succeed
}

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

int f4js_unlink (const char *path)
{
  return f4js_rpc(OP_UNLINK, path);
}

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

int f4js_rename (const char *src, const char *dst)
{
  f4js_cmd.u.rename.dst = dst;
  return f4js_rpc(OP_RENAME, src);
}

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

int f4js_mkdir (const char *path, mode_t mode)
{
  // TODO: pass 'mode'
  return f4js_rpc(OP_MKDIR, path);
}

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

int f4js_rmdir (const char *path)
{
  return f4js_rpc(OP_RMDIR, path);
}

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

void* f4js_init(struct fuse_conn_info *conn)
{
  // We currently always return NULL
  return (void*)f4js_rpc(OP_INIT, "");
}

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

void f4js_destroy (void *data)
{
  // We currently ignore the data pointer, which init() always sets to NULL
  f4js_rpc(OP_DESTROY, "");
}

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

void *fuse_thread(void *)
{
  struct fuse_operations ops = { 0 };
  ops.getattr = f4js_getattr;
  ops.readdir = f4js_readdir;
  ops.open = f4js_open;
  ops.read = f4js_read;
  ops.write = f4js_write;
  ops.create = f4js_create;
  ops.utimens = f4js_utimens;
  ops.unlink = f4js_unlink;
  ops.rename = f4js_rename;
  ops.mkdir = f4js_mkdir;
  ops.rmdir = f4js_rmdir;
  ops.init = f4js_init;
  ops.destroy = f4js_destroy;
  char *argv[] = { (char*)"dummy", (char*)"-s", (char*)"-d", f4js.root };
  fuse_main(4, argv, &ops, NULL);
  return NULL;
}

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

Handle<Value> GetAttrCompletion(const Arguments& args)
{
  HandleScope scope;
  if (args.Length() >= 1 && args[0]->IsNumber()) {
    Local<Number> retval = Local<Number>::Cast(args[0]);
    f4js_cmd.retval = (int)retval->Value();
    if (f4js_cmd.retval == 0 && args.Length() >= 2 && args[1]->IsObject()) {
      memset(f4js_cmd.u.getattr.stbuf, 0, sizeof(*f4js_cmd.u.getattr.stbuf));
      Handle<Object> stat = Handle<Object>::Cast(args[1]);

      Local<Value> prop = stat->Get(String::NewSymbol("st_size"));
      if (!prop->IsUndefined() && prop->IsNumber()) {
        Local<Number> num = Local<Number>::Cast(prop);
        f4js_cmd.u.getattr.stbuf->st_size = (off_t)num->Value();
      }

      prop = stat->Get(String::NewSymbol("st_mode"));
      if (!prop->IsUndefined() && prop->IsNumber()) {
        Local<Number> num = Local<Number>::Cast(prop);
        f4js_cmd.u.getattr.stbuf->st_mode = (mode_t)num->Value();
      }
    }
  }
  sem_post(&f4js.sem);
  return scope.Close(Undefined());
}

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

Handle<Value> ReadDirCompletion(const Arguments& args)
{
  HandleScope scope;
  if (args.Length() >= 1 && args[0]->IsNumber()) {
    Local<Number> retval = Local<Number>::Cast(args[0]);
    f4js_cmd.retval = (int)retval->Value();
    if (f4js_cmd.retval == 0 && args.Length() >= 2 && args[1]->IsArray()) {
      Handle<Array> ar = Handle<Array>::Cast(args[1]);
      for (uint32_t i = 0; i < ar->Length(); i++) {
        Local<Value> el = ar->Get(i);
        if (!el->IsUndefined() && el->IsString()) {
          Local<String> name = Local<String>::Cast(el);
          String::AsciiValue av(name);
          struct stat st;
          memset(&st, 0, sizeof(st)); // structure not used. Zero everything.
          if (f4js_cmd.u.readdir.filler(f4js_cmd.u.readdir.buf, *av, &st, 0))
            break;
        }
      }
    }
  }
  sem_post(&f4js.sem);
  return scope.Close(Undefined());
}

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

Handle<Value> GenericCompletion(const Arguments& args)
{
  HandleScope scope;
  bool exiting = (f4js_cmd.op == OP_DESTROY);

  if (args.Length() >= 1 && args[0]->IsNumber()) {
    Local<Number> retval = Local<Number>::Cast(args[0]);
    f4js_cmd.retval = (int)retval->Value();
  }
  sem_post(&f4js.sem);

  if (exiting) {
    pthread_join(f4js.fuse_thread, NULL);
    uv_unref((uv_handle_t*) &f4js.async);
  }
  return scope.Close(Undefined());
}

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

Handle<Value> ReadCompletion(const Arguments& args)
{
  HandleScope scope;
  if (args.Length() >= 1 && args[0]->IsNumber()) {
    Local<Number> retval = Local<Number>::Cast(args[0]);
    f4js_cmd.retval = (int)retval->Value();
    if (f4js_cmd.retval >= 0) {
      char *buffer_data = node::Buffer::Data(f4js.nodeBuffer);
      if ((size_t)f4js_cmd.retval > f4js_cmd.u.rw.len) {
        f4js_cmd.retval = f4js_cmd.u.rw.len;
      }
      memcpy(f4js_cmd.u.rw.dstBuf, buffer_data, f4js_cmd.retval);
    }
  }
  f4js.nodeBuffer.Dispose();
  sem_post(&f4js.sem);
  return scope.Close(Undefined());
}

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

Handle<Value> WriteCompletion(const Arguments& args)
{
  HandleScope scope;
  if (args.Length() >= 1 && args[0]->IsNumber()) {
    Local<Number> retval = Local<Number>::Cast(args[0]);
    f4js_cmd.retval = (int)retval->Value();
  }
  f4js.nodeBuffer.Dispose();
  sem_post(&f4js.sem);
  return scope.Close(Undefined());
}

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

// Called from the main thread.
static void DispatchOp(uv_async_t* handle, int status)
{
  HandleScope scope;
  std::string symName(fuseop_names[f4js_cmd.op]);
  Local<FunctionTemplate> tpl = FunctionTemplate::New(GenericCompletion); // default
  f4js_cmd.retval = -EPERM;
  int argc = 0;
  Handle<Value> argv[5];
  Local<String> path = String::New(f4js_cmd.in_path);
  argv[argc++] = path;
  node::Buffer* buffer = NULL; // used for read/write operations

  switch (f4js_cmd.op) {

  case OP_INIT:
  case OP_DESTROY:
    f4js_cmd.retval = 0; // Will be used as the return value of OP_INIT.
    --argc;              // Ugly. Remove the first argument (path) because not needed.
    break;

  case OP_GETATTR:
    tpl = FunctionTemplate::New(GetAttrCompletion);
    break;

  case OP_READDIR:
    tpl = FunctionTemplate::New(ReadDirCompletion);
    break;

  case OP_RENAME:
    argv[argc++] = String::New(f4js_cmd.u.rename.dst);
    break;

  case OP_READ:
    tpl = FunctionTemplate::New(ReadCompletion);
    buffer = node::Buffer::New(f4js_cmd.u.rw.len);
    break;

  case OP_WRITE:
    tpl = FunctionTemplate::New(WriteCompletion);
    buffer = node::Buffer::New((char*)f4js_cmd.u.rw.srcBuf, f4js_cmd.u.rw.len);
    break;

  default:
    break;
  }

  // Additional args for read/write operations
  if (buffer) {
    // FIXME: 64-bit off_t cannot always fit in a JS number
    argv[argc++] = Number::New((double)f4js_cmd.u.rw.offset);
    argv[argc++] = Number::New((double)f4js_cmd.u.rw.len);
    f4js.nodeBuffer = Persistent<Object>::New(buffer->handle_);
    argv[argc++] = f4js.nodeBuffer;
  }

  Local<Function> handler = Local<Function>::Cast(f4js.handlers->Get(String::NewSymbol(symName.c_str())));
  if (handler->IsUndefined()) {
    sem_post(&f4js.sem);
    return;
  }

  Local<Function> cb = tpl->GetFunction();
  std::string cbName = symName + "Completion";
  cb->SetName(String::NewSymbol(cbName.c_str()));
  argv[argc++] = cb;
  handler->Call(Context::GetCurrent()->Global(), argc, argv);
}

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

Handle<Value> Start(const Arguments& args)
{
  HandleScope scope;
  if (args.Length() < 2) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  if (!args[0]->IsString() || !args[1]->IsObject()) {
    ThrowException(Exception::TypeError(String::New("Wrong argument types")));
    return scope.Close(Undefined());
  }

  String::AsciiValue av(args[0]);
  char *root = *av;
  if (root == NULL) {
    ThrowException(Exception::TypeError(String::New("Path is incorrect")));
    return scope.Close(Undefined());
  }
  strncpy(f4js.root, root, sizeof(f4js.root));
  f4js.handlers = Persistent<Object>::New(Local<Object>::Cast(args[1]));

  sem_init(&f4js.sem, 0, 0);
  uv_async_init(uv_default_loop(), &f4js.async, DispatchOp);

  pthread_attr_t attr;
  pthread_attr_init(&attr);
  pthread_create(&f4js.fuse_thread, &attr, fuse_thread, NULL);
  return scope.Close(String::New("dummy"));
}

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

void init(Handle<Object> target)
{
  target->Set(String::NewSymbol("start"), FunctionTemplate::New(Start)->GetFunction());
}

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

NODE_MODULE(fuse4js, init)
<commit_msg>Make f4js.root a std::string.<commit_after>#include <node.h>
#include <node_buffer.h>
#include <v8.h>

#define FUSE_USE_VERSION 26

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/time.h>
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#endif

#include <fuse.h>
#include <semaphore.h>
#include <string>

using namespace v8;

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

static struct {
  uv_async_t async;
  sem_t sem;
  pthread_t fuse_thread;
  std::string root;
  Persistent<Object> handlers;
  Persistent<Object> nodeBuffer;
} f4js;

enum fuseop_t {
  OP_GETATTR = 0,
  OP_READDIR,
  OP_OPEN,
  OP_READ,
  OP_WRITE,
  OP_CREATE,
  OP_UNLINK,
  OP_RENAME,
  OP_MKDIR,
  OP_RMDIR,
  OP_INIT,
  OP_DESTROY
};

const char* fuseop_names[] = {
    "getattr",
    "readdir",
    "open",
    "read",
    "write",
    "create",
    "unlink",
    "rename",
    "mkdir",
    "rmdir",
    "init",
    "destroy"
};

static struct {
  enum fuseop_t op;
  const char *in_path;
  union {
    struct {
      struct stat *stbuf;
    } getattr;
    struct {
      void *buf;
      fuse_fill_dir_t filler;
    } readdir;
    struct {
      off_t offset;
      size_t len;
      char *dstBuf;
      const char *srcBuf;
    } rw;
    struct {
      const char *dst;
    } rename;
  } u;
  int retval;
} f4js_cmd;

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

static int f4js_rpc(enum fuseop_t op, const char *path)
{
  f4js_cmd.op = op;
  f4js_cmd.in_path = path;
  uv_async_send(&f4js.async);
  sem_wait(&f4js.sem);
  return f4js_cmd.retval;
}

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

static int f4js_getattr(const char *path, struct stat *stbuf)
{
  f4js_cmd.u.getattr.stbuf = stbuf;
  return f4js_rpc(OP_GETATTR, path);
}

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

static int f4js_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
		         off_t offset, struct fuse_file_info *fi)
{
  f4js_cmd.u.readdir.buf = buf;
  f4js_cmd.u.readdir.filler = filler;
  return f4js_rpc(OP_READDIR, path);
}

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

int f4js_open(const char *path, struct fuse_file_info *)
{
  return f4js_rpc(OP_OPEN, path);
}

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

int f4js_read (const char *path,
               char *buf,
               size_t len,
               off_t offset,
               struct fuse_file_info *)
{
  f4js_cmd.u.rw.offset = offset;
  f4js_cmd.u.rw.len = len;
  f4js_cmd.u.rw.dstBuf = buf;
  return f4js_rpc(OP_READ, path);
}

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

int f4js_write (const char *path,
                const char *buf,
                size_t len,
                off_t offset,
                struct fuse_file_info *)
{
  f4js_cmd.u.rw.offset = offset;
  f4js_cmd.u.rw.len = len;
  f4js_cmd.u.rw.srcBuf = buf;
  return f4js_rpc(OP_WRITE, path);
}

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

int f4js_create (const char *path,
                 mode_t mode,
                 struct fuse_file_info *)
{
  return f4js_rpc(OP_CREATE, path);
}

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

int f4js_utimens (const char *,
                  const struct timespec tv[2])
{
  return 0; // stub out for now to make "touch" command succeed
}

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

int f4js_unlink (const char *path)
{
  return f4js_rpc(OP_UNLINK, path);
}

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

int f4js_rename (const char *src, const char *dst)
{
  f4js_cmd.u.rename.dst = dst;
  return f4js_rpc(OP_RENAME, src);
}

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

int f4js_mkdir (const char *path, mode_t mode)
{
  // TODO: pass 'mode'
  return f4js_rpc(OP_MKDIR, path);
}

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

int f4js_rmdir (const char *path)
{
  return f4js_rpc(OP_RMDIR, path);
}

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

void* f4js_init(struct fuse_conn_info *conn)
{
  // We currently always return NULL
  return (void*)f4js_rpc(OP_INIT, "");
}

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

void f4js_destroy (void *data)
{
  // We currently ignore the data pointer, which init() always sets to NULL
  f4js_rpc(OP_DESTROY, "");
}

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

void *fuse_thread(void *)
{
  struct fuse_operations ops = { 0 };
  ops.getattr = f4js_getattr;
  ops.readdir = f4js_readdir;
  ops.open = f4js_open;
  ops.read = f4js_read;
  ops.write = f4js_write;
  ops.create = f4js_create;
  ops.utimens = f4js_utimens;
  ops.unlink = f4js_unlink;
  ops.rename = f4js_rename;
  ops.mkdir = f4js_mkdir;
  ops.rmdir = f4js_rmdir;
  ops.init = f4js_init;
  ops.destroy = f4js_destroy;
  char *argv[] = { (char*)"dummy", (char*)"-s", (char*)"-d", (char*)f4js.root.c_str() };
  fuse_main(4, argv, &ops, NULL);
  return NULL;
}

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

Handle<Value> GetAttrCompletion(const Arguments& args)
{
  HandleScope scope;
  if (args.Length() >= 1 && args[0]->IsNumber()) {
    Local<Number> retval = Local<Number>::Cast(args[0]);
    f4js_cmd.retval = (int)retval->Value();
    if (f4js_cmd.retval == 0 && args.Length() >= 2 && args[1]->IsObject()) {
      memset(f4js_cmd.u.getattr.stbuf, 0, sizeof(*f4js_cmd.u.getattr.stbuf));
      Handle<Object> stat = Handle<Object>::Cast(args[1]);

      Local<Value> prop = stat->Get(String::NewSymbol("st_size"));
      if (!prop->IsUndefined() && prop->IsNumber()) {
        Local<Number> num = Local<Number>::Cast(prop);
        f4js_cmd.u.getattr.stbuf->st_size = (off_t)num->Value();
      }

      prop = stat->Get(String::NewSymbol("st_mode"));
      if (!prop->IsUndefined() && prop->IsNumber()) {
        Local<Number> num = Local<Number>::Cast(prop);
        f4js_cmd.u.getattr.stbuf->st_mode = (mode_t)num->Value();
      }
    }
  }
  sem_post(&f4js.sem);
  return scope.Close(Undefined());
}

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

Handle<Value> ReadDirCompletion(const Arguments& args)
{
  HandleScope scope;
  if (args.Length() >= 1 && args[0]->IsNumber()) {
    Local<Number> retval = Local<Number>::Cast(args[0]);
    f4js_cmd.retval = (int)retval->Value();
    if (f4js_cmd.retval == 0 && args.Length() >= 2 && args[1]->IsArray()) {
      Handle<Array> ar = Handle<Array>::Cast(args[1]);
      for (uint32_t i = 0; i < ar->Length(); i++) {
        Local<Value> el = ar->Get(i);
        if (!el->IsUndefined() && el->IsString()) {
          Local<String> name = Local<String>::Cast(el);
          String::AsciiValue av(name);
          struct stat st;
          memset(&st, 0, sizeof(st)); // structure not used. Zero everything.
          if (f4js_cmd.u.readdir.filler(f4js_cmd.u.readdir.buf, *av, &st, 0))
            break;
        }
      }
    }
  }
  sem_post(&f4js.sem);
  return scope.Close(Undefined());
}

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

Handle<Value> GenericCompletion(const Arguments& args)
{
  HandleScope scope;
  bool exiting = (f4js_cmd.op == OP_DESTROY);

  if (args.Length() >= 1 && args[0]->IsNumber()) {
    Local<Number> retval = Local<Number>::Cast(args[0]);
    f4js_cmd.retval = (int)retval->Value();
  }
  sem_post(&f4js.sem);

  if (exiting) {
    pthread_join(f4js.fuse_thread, NULL);
    uv_unref((uv_handle_t*) &f4js.async);
  }
  return scope.Close(Undefined());
}

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

Handle<Value> ReadCompletion(const Arguments& args)
{
  HandleScope scope;
  if (args.Length() >= 1 && args[0]->IsNumber()) {
    Local<Number> retval = Local<Number>::Cast(args[0]);
    f4js_cmd.retval = (int)retval->Value();
    if (f4js_cmd.retval >= 0) {
      char *buffer_data = node::Buffer::Data(f4js.nodeBuffer);
      if ((size_t)f4js_cmd.retval > f4js_cmd.u.rw.len) {
        f4js_cmd.retval = f4js_cmd.u.rw.len;
      }
      memcpy(f4js_cmd.u.rw.dstBuf, buffer_data, f4js_cmd.retval);
    }
  }
  f4js.nodeBuffer.Dispose();
  sem_post(&f4js.sem);
  return scope.Close(Undefined());
}

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

Handle<Value> WriteCompletion(const Arguments& args)
{
  HandleScope scope;
  if (args.Length() >= 1 && args[0]->IsNumber()) {
    Local<Number> retval = Local<Number>::Cast(args[0]);
    f4js_cmd.retval = (int)retval->Value();
  }
  f4js.nodeBuffer.Dispose();
  sem_post(&f4js.sem);
  return scope.Close(Undefined());
}

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

// Called from the main thread.
static void DispatchOp(uv_async_t* handle, int status)
{
  HandleScope scope;
  std::string symName(fuseop_names[f4js_cmd.op]);
  Local<FunctionTemplate> tpl = FunctionTemplate::New(GenericCompletion); // default
  f4js_cmd.retval = -EPERM;
  int argc = 0;
  Handle<Value> argv[5];
  Local<String> path = String::New(f4js_cmd.in_path);
  argv[argc++] = path;
  node::Buffer* buffer = NULL; // used for read/write operations

  switch (f4js_cmd.op) {

  case OP_INIT:
  case OP_DESTROY:
    f4js_cmd.retval = 0; // Will be used as the return value of OP_INIT.
    --argc;              // Ugly. Remove the first argument (path) because not needed.
    break;

  case OP_GETATTR:
    tpl = FunctionTemplate::New(GetAttrCompletion);
    break;

  case OP_READDIR:
    tpl = FunctionTemplate::New(ReadDirCompletion);
    break;

  case OP_RENAME:
    argv[argc++] = String::New(f4js_cmd.u.rename.dst);
    break;

  case OP_READ:
    tpl = FunctionTemplate::New(ReadCompletion);
    buffer = node::Buffer::New(f4js_cmd.u.rw.len);
    break;

  case OP_WRITE:
    tpl = FunctionTemplate::New(WriteCompletion);
    buffer = node::Buffer::New((char*)f4js_cmd.u.rw.srcBuf, f4js_cmd.u.rw.len);
    break;

  default:
    break;
  }

  // Additional args for read/write operations
  if (buffer) {
    // FIXME: 64-bit off_t cannot always fit in a JS number
    argv[argc++] = Number::New((double)f4js_cmd.u.rw.offset);
    argv[argc++] = Number::New((double)f4js_cmd.u.rw.len);
    f4js.nodeBuffer = Persistent<Object>::New(buffer->handle_);
    argv[argc++] = f4js.nodeBuffer;
  }

  Local<Function> handler = Local<Function>::Cast(f4js.handlers->Get(String::NewSymbol(symName.c_str())));
  if (handler->IsUndefined()) {
    sem_post(&f4js.sem);
    return;
  }

  Local<Function> cb = tpl->GetFunction();
  std::string cbName = symName + "Completion";
  cb->SetName(String::NewSymbol(cbName.c_str()));
  argv[argc++] = cb;
  handler->Call(Context::GetCurrent()->Global(), argc, argv);
}

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

Handle<Value> Start(const Arguments& args)
{
  HandleScope scope;
  if (args.Length() < 2) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  if (!args[0]->IsString() || !args[1]->IsObject()) {
    ThrowException(Exception::TypeError(String::New("Wrong argument types")));
    return scope.Close(Undefined());
  }

  String::AsciiValue av(args[0]);
  char *root = *av;
  if (root == NULL) {
    ThrowException(Exception::TypeError(String::New("Path is incorrect")));
    return scope.Close(Undefined());
  }
  f4js.root = root;
  f4js.handlers = Persistent<Object>::New(Local<Object>::Cast(args[1]));

  sem_init(&f4js.sem, 0, 0);
  uv_async_init(uv_default_loop(), &f4js.async, DispatchOp);

  pthread_attr_t attr;
  pthread_attr_init(&attr);
  pthread_create(&f4js.fuse_thread, &attr, fuse_thread, NULL);
  return scope.Close(String::New("dummy"));
}

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

void init(Handle<Object> target)
{
  target->Set(String::NewSymbol("start"), FunctionTemplate::New(Start)->GetFunction());
}

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

NODE_MODULE(fuse4js, init)
<|endoftext|>


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

#include <modules/cimg/cimgutils.h>
#include <inviwo/core/datastructures/image/layerramprecision.h>
#include <inviwo/core/util/filesystem.h>
#include <algorithm>

#include <warn/push>
#include <warn/ignore/switch-enum>
#include <warn/ignore/conversion>
#if (_MSC_VER)
# pragma warning(disable: 4146)
# pragma warning(disable: 4197)
# pragma warning(disable: 4297)
# pragma warning(disable: 4267)
# pragma warning(disable: 4293)
#endif

#include <warn/ignore/all>
#include <modules/cimg/ext/cimg/CImg.h>
#include <warn/pop>

// Added in Cimg.h below struct type<float>...
/*#include <limits>
#include <half/half.hpp>

    template<> struct type < half_float::half > {
        static const char* string() { static const char *const s = "half"; return s; }
        static bool is_float() { return true; }
        static bool is_inf(const half_float::half val) {
#ifdef isinf
            return (bool)isinf(val);
#else
            return !is_nan(val) && (val<cimg::type<half_float::half>::min() || val>cimg::type<half_float::half>::max());
#endif
        }
        static bool is_nan(const half_float::half val) {
#ifdef isnan
            return (bool)isnan(val);
#else
            return !(val == val);
#endif
        }
        static half_float::half min() { return std::numeric_limits<half_float::half>::min(); }
        static half_float::half max() { return std::numeric_limits<half_float::half>::max(); }
        static half_float::half inf() { return (half_float::half)cimg::type<double>::inf(); }
        static half_float::half nan() { return (half_float::half)cimg::type<double>::nan(); }
        static half_float::half cut(const double val) { return val<(double)min() ? min() : val>(double)max() ? max() : (half_float::half)val; }
        static const char* format() { return "%.16g"; }
        static double format(const half_float::half val) { return (double)val; }
    };
*/

using namespace cimg_library;

namespace inviwo {

std::unordered_map<std::string, DataFormatEnums::Id> extToBaseTypeMap_ = {
          { "png", DataFormatEnums::UINT8 }
        , { "jpg", DataFormatEnums::UINT8 }
        , { "jpeg", DataFormatEnums::UINT8 }
        , { "bmp", DataFormatEnums::UINT8 }
        , { "exr", DataFormatEnums::FLOAT32 }
        , { "hdr", DataFormatEnums::FLOAT32 }
};

////////////////////// Templates ///////////////////////////////////////////////////

// Single channel images
template <typename T>
struct CImgToIvwConvert {
    static void* convert(void* dst, CImg<T>* img) {
        //Inviwo store pixels interleaved (RGBRGBRGB), CImg stores pixels in a planer format (RRRRGGGGBBBB).
        //Permute from planer to interleaved format, does we need to specify cxyz as input instead of xyzc
        if (img->spectrum() > 1){
            img->permute_axes("cxyz");
        }

        if (!dst) {
            T* dstAlloc = new T[img->size()];
            dst = static_cast<void*>(dstAlloc);
        }
        const void* src = static_cast<const void*>(img->data());

        std::memcpy(dst, src, img->size()*sizeof(T));

        return dst;
    }
};

// Single channel images
template <typename T>
struct LayerToCImg {
    static CImg<T>* convert(const LayerRAM* inputLayerRAM, bool permute = true) {
        //Single channel means we can do xyzc, as no permutation is needed
        CImg<T>* img = new CImg<T>(static_cast<const T*>(inputLayerRAM->getData()),
            inputLayerRAM->getDimensions().x, inputLayerRAM->getDimensions().y, 1, 1, false);

        return img;
    }
};

// Multiple channel images
template <typename T, template <typename, glm::precision> class G>
struct LayerToCImg<G<T, glm::defaultp>> {
    static CImg<T>* convert(const LayerRAM* inputLayerRAM, bool permute = true) {
        const DataFormatBase* dataFormat = inputLayerRAM->getDataFormat();
        const G<T, glm::defaultp>* typedDataPtr = static_cast<const G<T, glm::defaultp>*>(inputLayerRAM->getData());

        //Inviwo store pixels interleaved (RGBRGBRGB), CImg stores pixels in a planer format (RRRRGGGGBBBB).
        //Permute from interleaved to planer format, does we need to specify yzcx as input instead of cxyz
        CImg<T>* img = new CImg<T>(glm::value_ptr(*typedDataPtr),
            dataFormat->getComponents(), inputLayerRAM->getDimensions().x, inputLayerRAM->getDimensions().y, 1, false);

        if (permute)
            img->permute_axes("yzcx");

        return img;
    }
};

struct CImgNormalizedLayerDispatcher {
    using type = std::vector<unsigned char>*;
    template <typename T>
    std::vector<unsigned char>* dispatch(const LayerRAM* inputLayer) {
        CImg<typename T::primitive>* img = LayerToCImg<typename T::type>::convert(inputLayer, false);

        CImg<unsigned char> normalizedImg = img->get_normalize(0, 255);

        normalizedImg.mirror('z');

        std::vector<unsigned char>* data =
            new std::vector<unsigned char>(&normalizedImg[0], &normalizedImg[normalizedImg.size()]);

        delete img;

        return data;
    }
};

struct CImgLoadLayerDispatcher {
    using type = void*;
    template <typename T>
    void* dispatch(void* dst, const char* filePath, uvec2& dimensions, DataFormatEnums::Id& formatId, const DataFormatBase* dataFormat, bool rescaleToDim) {
        CImg<typename T::primitive> img(filePath);

        size_t components = static_cast<size_t>(img.spectrum());

        if (rescaleToDim) {
            img.resize(dimensions.x, dimensions.y);
        }
        else{
            dimensions = uvec2(img.width(), img.height());
        }

        const DataFormatBase* loadedDataFormat = DataFormatBase::get(dataFormat->getNumericType(), components, sizeof(typename T::primitive)*8);
        if (loadedDataFormat)
            formatId = loadedDataFormat->getId();
        else
            throw Exception("CImgLoadLayerDispatcher, could not find proper data type");

        //Image is up-side-down
        img.mirror('y');

        return CImgToIvwConvert<typename T::primitive>::convert(dst, &img);
    }
};

struct CImgSaveLayerDispatcher {
    using type = void;
    template <typename T>
    void dispatch(const char* filePath, const LayerRAM* inputLayer) {
        CImg<typename T::primitive>* img = LayerToCImg<typename T::type>::convert(inputLayer);

        //Should normalize based on output format i.e. PNG/JPG is 0-255, HDR different.
        const DataFormatBase* outFormat = DataFLOAT32::get();
        std::string fileExtension = filesystem::getFileExtension(filePath);
        if (extToBaseTypeMap_.find(fileExtension) != extToBaseTypeMap_.end()) {
            outFormat = DataFormatBase::get(extToBaseTypeMap_[fileExtension]);
        }

        //Image is up-side-down
        img->mirror('y');

        img->normalize(static_cast<typename T::primitive>(outFormat->getMin()), static_cast<typename T::primitive>(outFormat->getMax()));
        img->save(filePath);
        delete img;
    }
};

struct CImgRescaleLayerDispatcher {
    using type = void*;
    template <typename T>
    void* dispatch(const LayerRAM* inputLayerRAM, uvec2 dst_dim) {
        CImg<typename T::primitive>* img = LayerToCImg<typename T::type>::convert(inputLayerRAM);

        img->resize(dst_dim.x, dst_dim.y);

        return CImgToIvwConvert<typename T::primitive>::convert(nullptr, img);
    }
};

struct CImgLoadVolumeDispatcher {
    using type = void*;
    template <typename T>
    void* dispatch(void* dst, const char* filePath, size3_t& dimensions, DataFormatEnums::Id& formatId, const DataFormatBase* dataFormat) {
        CImg<typename T::primitive> img(filePath);

        size_t components = static_cast<size_t>(img.spectrum());
        dimensions = size3_t(img.width(), img.height(), img.depth());

        const DataFormatBase* loadedDataFormat = DataFormatBase::get(dataFormat->getNumericType(), components, sizeof(typename T::primitive) * 8);
        if (loadedDataFormat)
            formatId = loadedDataFormat->getId();
        else
            throw Exception("CImgLoadVolumeDispatcher, could not find proper data type");

        //Image is up-side-down
        img.mirror('y');

        return CImgToIvwConvert<typename T::primitive>::convert(dst, &img);
    }
};

////////////////////// CImgUtils ///////////////////////////////////////////////////

void* CImgUtils::loadLayerData(void* dst, const std::string& filePath, uvec2& dimensions,
    DataFormatEnums::Id& formatId, bool rescaleToDim){
    std::string fileExtension = filesystem::getFileExtension(filePath);
    if (extToBaseTypeMap_.find(fileExtension) != extToBaseTypeMap_.end()) {
        formatId = extToBaseTypeMap_[fileExtension];
    }
    else{
        formatId = DataFormatEnums::FLOAT32;
    }
    const DataFormatBase* dataFormat = DataFormatBase::get(formatId);

    CImgLoadLayerDispatcher disp;
    return dataFormat->dispatch(disp, dst, filePath.c_str(), dimensions, formatId, dataFormat, rescaleToDim);
}

void* CImgUtils::loadVolumeData(void* dst, const std::string& filePath, size3_t& dimensions,
    DataFormatEnums::Id& formatId){
    std::string fileExtension = filesystem::getFileExtension(filePath);
    if (extToBaseTypeMap_.find(fileExtension) != extToBaseTypeMap_.end()) {
        formatId = extToBaseTypeMap_[fileExtension];
    }
    else{
        formatId = DataFormatEnums::FLOAT32;
    }
    const DataFormatBase* dataFormat = DataFormatBase::get(formatId);

    CImgLoadVolumeDispatcher disp;
    return dataFormat->dispatch(disp, dst, filePath.c_str(), dimensions, formatId, dataFormat);
}

void CImgUtils::saveLayer(const std::string& filePath, const Layer* inputLayer) {
    CImgSaveLayerDispatcher disp;
    const LayerRAM* inputLayerRam = inputLayer->getRepresentation<LayerRAM>();
    inputLayer->getDataFormat()->dispatch(disp, filePath.c_str(), inputLayerRam);
}

std::vector<unsigned char>* CImgUtils::saveLayerToBuffer(std::string& fileType, const Layer* inputLayer) {
    CImgNormalizedLayerDispatcher disp;
    const LayerRAM* inputLayerRam = inputLayer->getRepresentation<LayerRAM>();
    // Can only produce raw output
    fileType = "raw";
    return inputLayer->getDataFormat()->dispatch(disp, inputLayerRam);
}

void* CImgUtils::rescaleLayer(const Layer* inputLayer, uvec2 dst_dim) {
    const LayerRAM* layerRam = inputLayer->getRepresentation<LayerRAM>();
    return rescaleLayerRAM(layerRam, dst_dim);
}

void* CImgUtils::rescaleLayerRAM(const LayerRAM* srcLayerRam, uvec2 dst_dim) {
    CImgRescaleLayerDispatcher disp;
    return srcLayerRam->getDataFormat()->dispatch(disp, srcLayerRam, dst_dim);
}

}  // namespace

#include <warn/pop>

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

#include <modules/cimg/cimgutils.h>
#include <inviwo/core/datastructures/image/layerramprecision.h>
#include <inviwo/core/util/filesystem.h>
#include <algorithm>

#include <warn/push>
#include <warn/ignore/all>
#include <modules/cimg/ext/cimg/CImg.h>
#include <warn/pop>

#include <warn/push>
#include <warn/ignore/switch-enum>
#include <warn/ignore/conversion>
#if (_MSC_VER)
# pragma warning(disable: 4146)
# pragma warning(disable: 4197)
# pragma warning(disable: 4297)
# pragma warning(disable: 4267)
# pragma warning(disable: 4293)
#endif

// Added in Cimg.h below struct type<float>...
/*#include <limits>
#include <half/half.hpp>

    template<> struct type < half_float::half > {
        static const char* string() { static const char *const s = "half"; return s; }
        static bool is_float() { return true; }
        static bool is_inf(const half_float::half val) {
#ifdef isinf
            return (bool)isinf(val);
#else
            return !is_nan(val) && (val<cimg::type<half_float::half>::min() || val>cimg::type<half_float::half>::max());
#endif
        }
        static bool is_nan(const half_float::half val) {
#ifdef isnan
            return (bool)isnan(val);
#else
            return !(val == val);
#endif
        }
        static half_float::half min() { return std::numeric_limits<half_float::half>::min(); }
        static half_float::half max() { return std::numeric_limits<half_float::half>::max(); }
        static half_float::half inf() { return (half_float::half)cimg::type<double>::inf(); }
        static half_float::half nan() { return (half_float::half)cimg::type<double>::nan(); }
        static half_float::half cut(const double val) { return val<(double)min() ? min() : val>(double)max() ? max() : (half_float::half)val; }
        static const char* format() { return "%.16g"; }
        static double format(const half_float::half val) { return (double)val; }
    };
*/

using namespace cimg_library;

namespace inviwo {

std::unordered_map<std::string, DataFormatEnums::Id> extToBaseTypeMap_ = {
          { "png", DataFormatEnums::UINT8 }
        , { "jpg", DataFormatEnums::UINT8 }
        , { "jpeg", DataFormatEnums::UINT8 }
        , { "bmp", DataFormatEnums::UINT8 }
        , { "exr", DataFormatEnums::FLOAT32 }
        , { "hdr", DataFormatEnums::FLOAT32 }
};

////////////////////// Templates ///////////////////////////////////////////////////

// Single channel images
template <typename T>
struct CImgToIvwConvert {
    static void* convert(void* dst, CImg<T>* img) {
        //Inviwo store pixels interleaved (RGBRGBRGB), CImg stores pixels in a planer format (RRRRGGGGBBBB).
        //Permute from planer to interleaved format, does we need to specify cxyz as input instead of xyzc
        if (img->spectrum() > 1){
            img->permute_axes("cxyz");
        }

        if (!dst) {
            T* dstAlloc = new T[img->size()];
            dst = static_cast<void*>(dstAlloc);
        }
        const void* src = static_cast<const void*>(img->data());

        std::memcpy(dst, src, img->size()*sizeof(T));

        return dst;
    }
};

// Single channel images
template <typename T>
struct LayerToCImg {
    static CImg<T>* convert(const LayerRAM* inputLayerRAM, bool permute = true) {
        //Single channel means we can do xyzc, as no permutation is needed
        CImg<T>* img = new CImg<T>(static_cast<const T*>(inputLayerRAM->getData()),
            inputLayerRAM->getDimensions().x, inputLayerRAM->getDimensions().y, 1, 1, false);

        return img;
    }
};

// Multiple channel images
template <typename T, template <typename, glm::precision> class G>
struct LayerToCImg<G<T, glm::defaultp>> {
    static CImg<T>* convert(const LayerRAM* inputLayerRAM, bool permute = true) {
        const DataFormatBase* dataFormat = inputLayerRAM->getDataFormat();
        const G<T, glm::defaultp>* typedDataPtr = static_cast<const G<T, glm::defaultp>*>(inputLayerRAM->getData());

        //Inviwo store pixels interleaved (RGBRGBRGB), CImg stores pixels in a planer format (RRRRGGGGBBBB).
        //Permute from interleaved to planer format, does we need to specify yzcx as input instead of cxyz
        CImg<T>* img = new CImg<T>(glm::value_ptr(*typedDataPtr),
            dataFormat->getComponents(), inputLayerRAM->getDimensions().x, inputLayerRAM->getDimensions().y, 1, false);

        if (permute)
            img->permute_axes("yzcx");

        return img;
    }
};

struct CImgNormalizedLayerDispatcher {
    using type = std::vector<unsigned char>*;
    template <typename T>
    std::vector<unsigned char>* dispatch(const LayerRAM* inputLayer) {
        CImg<typename T::primitive>* img = LayerToCImg<typename T::type>::convert(inputLayer, false);

        CImg<unsigned char> normalizedImg = img->get_normalize(0, 255);

        normalizedImg.mirror('z');

        std::vector<unsigned char>* data =
            new std::vector<unsigned char>(&normalizedImg[0], &normalizedImg[normalizedImg.size()]);

        delete img;

        return data;
    }
};

struct CImgLoadLayerDispatcher {
    using type = void*;
    template <typename T>
    void* dispatch(void* dst, const char* filePath, uvec2& dimensions, DataFormatEnums::Id& formatId, const DataFormatBase* dataFormat, bool rescaleToDim) {
        CImg<typename T::primitive> img(filePath);

        size_t components = static_cast<size_t>(img.spectrum());

        if (rescaleToDim) {
            img.resize(dimensions.x, dimensions.y);
        }
        else{
            dimensions = uvec2(img.width(), img.height());
        }

        const DataFormatBase* loadedDataFormat = DataFormatBase::get(dataFormat->getNumericType(), components, sizeof(typename T::primitive)*8);
        if (loadedDataFormat)
            formatId = loadedDataFormat->getId();
        else
            throw Exception("CImgLoadLayerDispatcher, could not find proper data type");

        //Image is up-side-down
        img.mirror('y');

        return CImgToIvwConvert<typename T::primitive>::convert(dst, &img);
    }
};

struct CImgSaveLayerDispatcher {
    using type = void;
    template <typename T>
    void dispatch(const char* filePath, const LayerRAM* inputLayer) {
        CImg<typename T::primitive>* img = LayerToCImg<typename T::type>::convert(inputLayer);

        //Should normalize based on output format i.e. PNG/JPG is 0-255, HDR different.
        const DataFormatBase* outFormat = DataFLOAT32::get();
        std::string fileExtension = filesystem::getFileExtension(filePath);
        if (extToBaseTypeMap_.find(fileExtension) != extToBaseTypeMap_.end()) {
            outFormat = DataFormatBase::get(extToBaseTypeMap_[fileExtension]);
        }

        //Image is up-side-down
        img->mirror('y');

        img->normalize(static_cast<typename T::primitive>(outFormat->getMin()), static_cast<typename T::primitive>(outFormat->getMax()));
        img->save(filePath);
        delete img;
    }
};

struct CImgRescaleLayerDispatcher {
    using type = void*;
    template <typename T>
    void* dispatch(const LayerRAM* inputLayerRAM, uvec2 dst_dim) {
        CImg<typename T::primitive>* img = LayerToCImg<typename T::type>::convert(inputLayerRAM);

        img->resize(dst_dim.x, dst_dim.y);

        return CImgToIvwConvert<typename T::primitive>::convert(nullptr, img);
    }
};

struct CImgLoadVolumeDispatcher {
    using type = void*;
    template <typename T>
    void* dispatch(void* dst, const char* filePath, size3_t& dimensions, DataFormatEnums::Id& formatId, const DataFormatBase* dataFormat) {
        CImg<typename T::primitive> img(filePath);

        size_t components = static_cast<size_t>(img.spectrum());
        dimensions = size3_t(img.width(), img.height(), img.depth());

        const DataFormatBase* loadedDataFormat = DataFormatBase::get(dataFormat->getNumericType(), components, sizeof(typename T::primitive) * 8);
        if (loadedDataFormat)
            formatId = loadedDataFormat->getId();
        else
            throw Exception("CImgLoadVolumeDispatcher, could not find proper data type");

        //Image is up-side-down
        img.mirror('y');

        return CImgToIvwConvert<typename T::primitive>::convert(dst, &img);
    }
};

////////////////////// CImgUtils ///////////////////////////////////////////////////

void* CImgUtils::loadLayerData(void* dst, const std::string& filePath, uvec2& dimensions,
    DataFormatEnums::Id& formatId, bool rescaleToDim){
    std::string fileExtension = filesystem::getFileExtension(filePath);
    if (extToBaseTypeMap_.find(fileExtension) != extToBaseTypeMap_.end()) {
        formatId = extToBaseTypeMap_[fileExtension];
    }
    else{
        formatId = DataFormatEnums::FLOAT32;
    }
    const DataFormatBase* dataFormat = DataFormatBase::get(formatId);

    CImgLoadLayerDispatcher disp;
    return dataFormat->dispatch(disp, dst, filePath.c_str(), dimensions, formatId, dataFormat, rescaleToDim);
}

void* CImgUtils::loadVolumeData(void* dst, const std::string& filePath, size3_t& dimensions,
    DataFormatEnums::Id& formatId){
    std::string fileExtension = filesystem::getFileExtension(filePath);
    if (extToBaseTypeMap_.find(fileExtension) != extToBaseTypeMap_.end()) {
        formatId = extToBaseTypeMap_[fileExtension];
    }
    else{
        formatId = DataFormatEnums::FLOAT32;
    }
    const DataFormatBase* dataFormat = DataFormatBase::get(formatId);

    CImgLoadVolumeDispatcher disp;
    return dataFormat->dispatch(disp, dst, filePath.c_str(), dimensions, formatId, dataFormat);
}

void CImgUtils::saveLayer(const std::string& filePath, const Layer* inputLayer) {
    CImgSaveLayerDispatcher disp;
    const LayerRAM* inputLayerRam = inputLayer->getRepresentation<LayerRAM>();
    inputLayer->getDataFormat()->dispatch(disp, filePath.c_str(), inputLayerRam);
}

std::vector<unsigned char>* CImgUtils::saveLayerToBuffer(std::string& fileType, const Layer* inputLayer) {
    CImgNormalizedLayerDispatcher disp;
    const LayerRAM* inputLayerRam = inputLayer->getRepresentation<LayerRAM>();
    // Can only produce raw output
    fileType = "raw";
    return inputLayer->getDataFormat()->dispatch(disp, inputLayerRam);
}

void* CImgUtils::rescaleLayer(const Layer* inputLayer, uvec2 dst_dim) {
    const LayerRAM* layerRam = inputLayer->getRepresentation<LayerRAM>();
    return rescaleLayerRAM(layerRam, dst_dim);
}

void* CImgUtils::rescaleLayerRAM(const LayerRAM* srcLayerRam, uvec2 dst_dim) {
    CImgRescaleLayerDispatcher disp;
    return srcLayerRam->getDataFormat()->dispatch(disp, srcLayerRam, dst_dim);
}

}  // namespace

#include <warn/pop>

<|endoftext|>


<commit_before>#include "context.h"

#include <assert.h>
#include <fcntl.h>
#include <iostream>
#include <string>
#include <fstream>
#include <termios.h>
#include <linux/input.h>

#include "glm/gtc/matrix_transform.hpp"
#include "platform.h"
#include "util/geom.h"

// Main global variables
//-------------------------------
#define check() assert(glGetError() == 0)
EGLDisplay display;
EGLSurface surface;
EGLContext context;

static glm::ivec4 viewport;
static glm::mat4 orthoMatrix;

#define MOUSE_ID "mouse0"
static int mouse_fd = -1;
typedef struct {
    float   x,y;
    float   velX,velY;
    int     button;
} Mouse;
static Mouse mouse;
static bool bRender;
static unsigned char keyPressed;

// Mouse stuff
//--------------------------------
std::string searchForDevice(const std::string& _device) {
    std::ifstream file;
    std::string buffer;
    std::string address = "NONE";

    file.open("/proc/bus/input/devices");

    if (!file.is_open())
      return "NOT FOUND";

    while (!file.eof()) {
      getline(file, buffer);
      std::size_t found = buffer.find(_device);
      if(found!=std::string::npos){
        std::string tmp = buffer.substr(found+_device.size()+1);
        std::size_t foundBegining = tmp.find("event");
        if(foundBegining!=std::string::npos){
            address = "/dev/input/"+tmp.substr(foundBegining);
            address.erase(address.size()-1,1);
        }
        break;
      }
    }

    file.close();
    return address;
}

void closeMouse(){
    if (mouse_fd > 0)
        close(mouse_fd);
    mouse_fd = -1;
}

int initMouse(){
    closeMouse();

    mouse.x = viewport.z*0.5;
    mouse.y = viewport.w*0.5;
    std::string mouseAddress = searchForDevice(MOUSE_ID);
    std::cout << "Mouse [" << mouseAddress << "]"<< std::endl;
    mouse_fd = open(mouseAddress.c_str(), O_RDONLY | O_NONBLOCK);

    return mouse_fd;
}

bool readMouseEvent(struct input_event *mousee){
    int bytes;
    if (mouse_fd > 0) {
        bytes = read(mouse_fd, mousee, sizeof(struct input_event));
        if (bytes == -1)
            return false;
        else if (bytes == sizeof(struct input_event))
            return true;
    }
    return false;
}

bool updateMouse() {
    if (mouse_fd < 0) {
        return false;
    }

    struct input_event mousee;
    while ( readMouseEvent(&mousee) ) {

        mouse.velX=0;
        mouse.velY=0;

        float x,y = 0.0f;
        int button = 0;

        switch(mousee.type) {
            // Update Mouse Event
            case EV_KEY:
                switch (mousee.code) {
                    case BTN_LEFT:
                        if (mousee.value == 1){
                            button = 1;
                        }
                        break;
                    case BTN_RIGHT:
                        if(mousee.value == 1){
                            button = 2;
                        }
                        break;
                    case BTN_MIDDLE:
                        if(mousee.value == 1){
                            button = 3;
                        }
                        break;
                    default:
                        button = 0;
                        break;
                }
                if (button != mouse.button) {
                    mouse.button = button;
                    if(mouse.button == 0){
                        onMouseRelease(mouse.x,mouse.y);
                    } else {
                        onMouseClick(mouse.x,mouse.y,mouse.button);
                    }
                }
                break;
            case EV_REL:
                switch (mousee.code) {
                    case REL_X:
                        mouse.velX = mousee.value;
                        break;
                    case REL_Y:
                        mousee.value = mousee.value * -1;
                        mouse.velY = mousee.value;
                        break;
                    // case REL_WHEEL:
                    //     if (mousee.value > 0)
                    //         std::cout << "Mouse wheel Forward" << std::endl;
                    //     else if(mousee.value < 0)
                    //         std::cout << "Mouse wheel Backward" << std::endl;
                    //     break;
                    default:
                        break;
                }
                mouse.x+=mouse.velX;
                mouse.y+=mouse.velY;

                // Clamp values
                if (mouse.x < 0) mouse.x=0;
                if (mouse.y < 0) mouse.y=0;
                if (mouse.x > viewport.z) mouse.x = viewport.z;
                if (mouse.y > viewport.w) mouse.y = viewport.w;

                if (mouse.button != 0) {
                    onMouseDrag(mouse.x,mouse.y,mouse.button);
                } else {
                    onMouseMove(mouse.x,mouse.y);
                }
                break;
            case EV_ABS:
                switch (mousee.code) {
                    case ABS_X:
                        x = ((float)mousee.value/4095.0f)*viewport.z;
                        mouse.velX = x - mouse.x;
                        mouse.x = x;
                        break;
                    case ABS_Y:
                        y = (1.0-((float)mousee.value/4095.0f))*viewport.w;
                        mouse.velY = y - mouse.y;
                        mouse.y = y;
                        break;
                    default:
                        break;
                }
                if (mouse.button != 0) {
                    onMouseDrag(mouse.x,mouse.y,mouse.button);
                } else {
                    onMouseMove(mouse.x,mouse.y);
                }
                break;
            default:
                break;
        }
    }
    return true;
}

// OpenGL ES
//--------------------------------

//==============================================================================
//  Creation of EGL context (lines 241-341) from:
//
//      https://github.com/raspberrypi/firmware/blob/master/opt/vc/src/hello_pi/hello_triangle2/triangle2.c#L100
//
/*
Copyright (c) 2012, Broadcom Europe Ltd
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.
    * Neither the name of the copyright holder nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.
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.
*/
//==============================================================================
void initGL(int argc, char **argv){

    // Start OpenGL ES
    bcm_host_init();

    // Clear application state
    int32_t success = 0;
    EGLBoolean result;
    EGLint num_config;

    static EGL_DISPMANX_WINDOW_T nativeviewport;

    DISPMANX_ELEMENT_HANDLE_T dispman_element;
    DISPMANX_DISPLAY_HANDLE_T dispman_display;
    DISPMANX_UPDATE_HANDLE_T dispman_update;
    VC_RECT_T dst_rect;
    VC_RECT_T src_rect;

    uint32_t screen_width;
    uint32_t screen_height;

    static const EGLint attribute_list[] = {
        EGL_RED_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_ALPHA_SIZE, 8,
        EGL_SAMPLE_BUFFERS, 1,
        EGL_SAMPLES, 4,
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_DEPTH_SIZE, 16,
        EGL_NONE
    };

    static const EGLint context_attributes[] = {
        EGL_CONTEXT_CLIENT_VERSION, 2,
        EGL_NONE
    };

    EGLConfig config;

    // get an EGL display connection
    display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    assert(display!=EGL_NO_DISPLAY);
    check();

    // initialize the EGL display connection
    result = eglInitialize(display, NULL, NULL);
    assert(EGL_FALSE != result);
    check();

    // get an appropriate EGL frame buffer configuration
    result = eglChooseConfig(display, attribute_list, &config, 1, &num_config);
    assert(EGL_FALSE != result);
    check();

    // get an appropriate EGL frame buffer configuration
    result = eglBindAPI(EGL_OPENGL_ES_API);
    assert(EGL_FALSE != result);
    check();

    // create an EGL rendering context
    context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes);
    assert(context!=EGL_NO_CONTEXT);
    check();

    // create an EGL viewport surface
    success = graphics_get_display_size(0 /* LCD */, &screen_width, &screen_height);
    assert( success >= 0 );

    //  Initially the viewport is for all the screen
    viewport.x = 0;
    viewport.y = 0;
    viewport.z = screen_width;
    viewport.w = screen_height;

    dst_rect.x = viewport.x;
    dst_rect.y = viewport.y;
    dst_rect.width = viewport.z;
    dst_rect.height = viewport.w;

    src_rect.x = 0;
    src_rect.y = 0;
    src_rect.width = viewport.z << 16;
    src_rect.height = viewport.w << 16;

    dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
    dispman_update = vc_dispmanx_update_start( 0 );

    dispman_element = vc_dispmanx_element_add( dispman_update, dispman_display,
                                       0/*layer*/, &dst_rect, 0/*src*/,
                                       &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, (DISPMANX_TRANSFORM_T)0/*transform*/);

    nativeviewport.element = dispman_element;
    nativeviewport.width = viewport.z;
    nativeviewport.height = viewport.w;
    vc_dispmanx_update_submit_sync( dispman_update );
    check();

    surface = eglCreateWindowSurface( display, config, &nativeviewport, NULL );
    assert(surface != EGL_NO_SURFACE);
    check();

    // connect the context to the surface
    result = eglMakeCurrent(display, surface, surface, context);
    assert(EGL_FALSE != result);
    check();

    // Set background color and clear buffers
    // glClearColor(0.15f, 0.25f, 0.35f, 1.0f);
    // glClear( GL_COLOR_BUFFER_BIT );

    setWindowSize(viewport.z,viewport.w);
    mouse.x = viewport.z*0.5;
    mouse.y = viewport.w*0.5;
    check();

    initMouse();
    ///printf("OpenGL Initialize at %i,%i,%i,%i\n",viewport.x,viewport.y,viewport.z,viewport.w);
}

void renderGL(){
    eglSwapBuffers(display, surface);
}

void closeGL(){
    closeMouse();
    eglSwapBuffers(display, surface);

    // Release OpenGL resources
    eglMakeCurrent( display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
    eglDestroySurface( display, surface );
    eglDestroyContext( display, context );
    eglTerminate( display );
}

int getKey() {
    int character;
    struct termios orig_term_attr;
    struct termios new_term_attr;

    /* set the terminal to raw mode */
    tcgetattr(fileno(stdin), &orig_term_attr);
    memcpy(&new_term_attr, &orig_term_attr, sizeof(struct termios));
    new_term_attr.c_lflag &= ~(ECHO|ICANON);
    new_term_attr.c_cc[VTIME] = 0;
    new_term_attr.c_cc[VMIN] = 0;
    tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);

    /* read a character from the stdin stream without blocking */
    /*   returns EOF (-1) if no character is available */
    character = fgetc(stdin);

    /* restore the original terminal attributes */
    tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);

    return character;
}

void updateGL() {
    updateMouse();

    int key = getKey();
    if ( key != -1 && key != keyPressed ){
        keyPressed = key;
        onKeyPress(key);
    }
}

void setWindowSize(int _width, int _height) {
    viewport.z = _width;
    viewport.w = _height;
    glViewport((float)viewport.x, (float)viewport.y, (float)viewport.z, (float)viewport.w);
    orthoMatrix = glm::ortho((float)viewport.x, (float)viewport.z, (float)viewport.y, (float)viewport.w);

    onViewportResize(viewport.z, viewport.w);
}

int getWindowWidth(){
    return viewport.z;
}

int getWindowHeight(){
    return viewport.w;
}

glm::vec2 getWindowSize() {
    return glm::vec2(viewport.w,viewport.w);
}

glm::mat4 getOrthoMatrix(){
    return orthoMatrix;
}

float getMouseX(){
    return mouse.x;
}

float getMouseY(){
    return mouse.y;
}

glm::vec2 getMousePosition() {
    return glm::vec2(mouse.x,mouse.y);
}

float getMouseVelX(){
    return mouse.velX;
}

float getMouseVelY(){
    return mouse.velY;
}

glm::vec2 getMouseVelocity() {
    return glm::vec2(mouse.velX,mouse.velY);
}

int getMouseButton(){
    return mouse.button;
}

unsigned char getKeyPressed(){
    return keyPressed;
}

void setRenderRequest(bool _render) {
    bRender = _render;
}

bool getRenderRequest() {
    return bRender;
}
<commit_msg>Style cleanup in context.cpp<commit_after>#include "context.h"

#include <assert.h>
#include <fcntl.h>
#include <iostream>
#include <string>
#include <fstream>
#include <termios.h>
#include <linux/input.h>

#include "glm/gtc/matrix_transform.hpp"
#include "platform.h"
#include "util/geom.h"

// Main global variables
//-------------------------------
#define check() assert(glGetError() == 0)
EGLDisplay display;
EGLSurface surface;
EGLContext context;

static glm::ivec4 viewport;
static glm::mat4 orthoMatrix;

#define MOUSE_ID "mouse0"
static int mouse_fd = -1;
typedef struct {
    float   x, y;
    float   velX, velY;
    int     button;
} Mouse;
static Mouse mouse;
static bool bRender;
static unsigned char keyPressed;

// Mouse stuff
//--------------------------------
std::string searchForDevice(const std::string& device) {
    std::ifstream file;
    std::string buffer;
    std::string address = "NONE";

    file.open("/proc/bus/input/devices");

    if (!file.is_open()) {
        return "NOT FOUND";
    }

    while (!file.eof()) {
        getline(file, buffer);
        std::size_t found = buffer.find(device);
        if (found != std::string::npos) {
            std::string tmp = buffer.substr(found + device.size() + 1);
            std::size_t foundBegining = tmp.find("event");
            if (foundBegining != std::string::npos) {
                address = "/dev/input/" + tmp.substr(foundBegining);
                address.erase(address.size() - 1, 1);
            }
            break;
        }
    }

    file.close();
    return address;
}

void closeMouse() {
    if (mouse_fd > 0) {
        close(mouse_fd);
    }
    mouse_fd = -1;
}

int initMouse() {
    closeMouse();

    mouse.x = viewport.z * 0.5;
    mouse.y = viewport.w * 0.5;
    std::string mouseAddress = searchForDevice(MOUSE_ID);
    std::cout << "Mouse [" << mouseAddress << "]" << std::endl;
    mouse_fd = open(mouseAddress.c_str(), O_RDONLY | O_NONBLOCK);

    return mouse_fd;
}

bool readMouseEvent(struct input_event *mousee) {
    int bytes;
    if (mouse_fd > 0) {
        bytes = read(mouse_fd, mousee, sizeof(struct input_event));
        if (bytes == -1) {
            return false;
        } else if (bytes == sizeof(struct input_event)) {
            return true;
        }
    }
    return false;
}

bool updateMouse() {
    if (mouse_fd < 0) {
        return false;
    }

    struct input_event mousee;
    while (readMouseEvent(&mousee)) {

        mouse.velX = 0;
        mouse.velY = 0;

        float x = 0.0f, y = 0.0f;
        int button = 0;

        switch (mousee.type) {
            // Update Mouse Event
            case EV_KEY:
                switch (mousee.code) {
                    case BTN_LEFT:
                        if (mousee.value == 1) {
                            button = 1;
                        }
                        break;
                    case BTN_RIGHT:
                        if (mousee.value == 1) {
                            button = 2;
                        }
                        break;
                    case BTN_MIDDLE:
                        if (mousee.value == 1) {
                            button = 3;
                        }
                        break;
                    default:
                        button = 0;
                        break;
                }
                if (button != mouse.button) {
                    mouse.button = button;
                    if (mouse.button == 0) {
                        onMouseRelease(mouse.x, mouse.y);
                    } else {
                        onMouseClick(mouse.x, mouse.y, mouse.button);
                    }
                }
                break;
            case EV_REL:
                switch (mousee.code) {
                    case REL_X:
                        mouse.velX = mousee.value;
                        break;
                    case REL_Y:
                        mousee.value = mousee.value * -1;
                        mouse.velY = mousee.value;
                        break;
                    // case REL_WHEEL:
                    //     if (mousee.value > 0)
                    //         std::cout << "Mouse wheel Forward" << std::endl;
                    //     else if(mousee.value < 0)
                    //         std::cout << "Mouse wheel Backward" << std::endl;
                    //     break;
                    default:
                        break;
                }
                mouse.x += mouse.velX;
                mouse.y += mouse.velY;

                // Clamp values
                if (mouse.x < 0) { mouse.x = 0; }
                if (mouse.y < 0) { mouse.y = 0; }
                if (mouse.x > viewport.z) { mouse.x = viewport.z; }
                if (mouse.y > viewport.w) { mouse.y = viewport.w; }

                if (mouse.button != 0) {
                    onMouseDrag(mouse.x, mouse.y, mouse.button);
                } else {
                    onMouseMove(mouse.x, mouse.y);
                }
                break;
            case EV_ABS:
                switch (mousee.code) {
                    case ABS_X:
                        x = ((float)mousee.value / 4095.0f) * viewport.z;
                        mouse.velX = x - mouse.x;
                        mouse.x = x;
                        break;
                    case ABS_Y:
                        y = (1.0 - ((float)mousee.value / 4095.0f)) * viewport.w;
                        mouse.velY = y - mouse.y;
                        mouse.y = y;
                        break;
                    default:
                        break;
                }
                if (mouse.button != 0) {
                    onMouseDrag(mouse.x, mouse.y, mouse.button);
                } else {
                    onMouseMove(mouse.x, mouse.y);
                }
                break;
            default:
                break;
        }
    }
    return true;
}

// OpenGL ES
//--------------------------------

//==============================================================================
//  Creation of EGL context (lines 241-341) from:
//
//      https://github.com/raspberrypi/firmware/blob/master/opt/vc/src/hello_pi/hello_triangle2/triangle2.c#L100
//
/*
Copyright (c) 2012, Broadcom Europe Ltd
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.
    * Neither the name of the copyright holder nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.
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.
*/
//==============================================================================
void initGL(int argc, char **argv) {

    // Start OpenGL ES
    bcm_host_init();

    // Clear application state
    int32_t success = 0;
    EGLBoolean result;
    EGLint num_config;

    static EGL_DISPMANX_WINDOW_T nativeviewport;

    DISPMANX_ELEMENT_HANDLE_T dispman_element;
    DISPMANX_DISPLAY_HANDLE_T dispman_display;
    DISPMANX_UPDATE_HANDLE_T dispman_update;
    VC_RECT_T dst_rect;
    VC_RECT_T src_rect;

    uint32_t screen_width;
    uint32_t screen_height;

    static const EGLint attribute_list[] = {
        EGL_RED_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_ALPHA_SIZE, 8,
        EGL_SAMPLE_BUFFERS, 1,
        EGL_SAMPLES, 4,
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_DEPTH_SIZE, 16,
        EGL_NONE
    };

    static const EGLint context_attributes[] = {
        EGL_CONTEXT_CLIENT_VERSION, 2,
        EGL_NONE
    };

    EGLConfig config;

    // get an EGL display connection
    display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    assert(display!=EGL_NO_DISPLAY);
    check();

    // initialize the EGL display connection
    result = eglInitialize(display, NULL, NULL);
    assert(EGL_FALSE != result);
    check();

    // get an appropriate EGL frame buffer configuration
    result = eglChooseConfig(display, attribute_list, &config, 1, &num_config);
    assert(EGL_FALSE != result);
    check();

    // get an appropriate EGL frame buffer configuration
    result = eglBindAPI(EGL_OPENGL_ES_API);
    assert(EGL_FALSE != result);
    check();

    // create an EGL rendering context
    context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes);
    assert(context!=EGL_NO_CONTEXT);
    check();

    // create an EGL viewport surface
    success = graphics_get_display_size(0 /* LCD */, &screen_width, &screen_height);
    assert( success >= 0 );

    //  Initially the viewport is for all the screen
    viewport.x = 0;
    viewport.y = 0;
    viewport.z = screen_width;
    viewport.w = screen_height;

    dst_rect.x = viewport.x;
    dst_rect.y = viewport.y;
    dst_rect.width = viewport.z;
    dst_rect.height = viewport.w;

    src_rect.x = 0;
    src_rect.y = 0;
    src_rect.width = viewport.z << 16;
    src_rect.height = viewport.w << 16;

    dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
    dispman_update = vc_dispmanx_update_start( 0 );

    dispman_element = vc_dispmanx_element_add( dispman_update, dispman_display,
                                       0/*layer*/, &dst_rect, 0/*src*/,
                                       &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, (DISPMANX_TRANSFORM_T)0/*transform*/);

    nativeviewport.element = dispman_element;
    nativeviewport.width = viewport.z;
    nativeviewport.height = viewport.w;
    vc_dispmanx_update_submit_sync( dispman_update );
    check();

    surface = eglCreateWindowSurface( display, config, &nativeviewport, NULL );
    assert(surface != EGL_NO_SURFACE);
    check();

    // connect the context to the surface
    result = eglMakeCurrent(display, surface, surface, context);
    assert(EGL_FALSE != result);
    check();

    // Set background color and clear buffers
    // glClearColor(0.15f, 0.25f, 0.35f, 1.0f);
    // glClear( GL_COLOR_BUFFER_BIT );

    setWindowSize(viewport.z,viewport.w);
    mouse.x = viewport.z*0.5;
    mouse.y = viewport.w*0.5;
    check();

    initMouse();
    ///printf("OpenGL Initialize at %i,%i,%i,%i\n",viewport.x,viewport.y,viewport.z,viewport.w);
}

void renderGL(){
    eglSwapBuffers(display, surface);
}

void closeGL(){
    closeMouse();
    eglSwapBuffers(display, surface);

    // Release OpenGL resources
    eglMakeCurrent( display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
    eglDestroySurface( display, surface );
    eglDestroyContext( display, context );
    eglTerminate( display );
}

int getKey() {
    int character;
    struct termios orig_term_attr;
    struct termios new_term_attr;

    /* set the terminal to raw mode */
    tcgetattr(fileno(stdin), &orig_term_attr);
    memcpy(&new_term_attr, &orig_term_attr, sizeof(struct termios));
    new_term_attr.c_lflag &= ~(ECHO|ICANON);
    new_term_attr.c_cc[VTIME] = 0;
    new_term_attr.c_cc[VMIN] = 0;
    tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);

    /* read a character from the stdin stream without blocking */
    /*   returns EOF (-1) if no character is available */
    character = fgetc(stdin);

    /* restore the original terminal attributes */
    tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);

    return character;
}

void updateGL() {
    updateMouse();

    int key = getKey();
    if ( key != -1 && key != keyPressed ){
        keyPressed = key;
        onKeyPress(key);
    }
}

void setWindowSize(int _width, int _height) {
    viewport.z = _width;
    viewport.w = _height;
    glViewport((float)viewport.x, (float)viewport.y, (float)viewport.z, (float)viewport.w);
    orthoMatrix = glm::ortho((float)viewport.x, (float)viewport.z, (float)viewport.y, (float)viewport.w);

    onViewportResize(viewport.z, viewport.w);
}

int getWindowWidth(){
    return viewport.z;
}

int getWindowHeight(){
    return viewport.w;
}

glm::vec2 getWindowSize() {
    return glm::vec2(viewport.w,viewport.w);
}

glm::mat4 getOrthoMatrix(){
    return orthoMatrix;
}

float getMouseX(){
    return mouse.x;
}

float getMouseY(){
    return mouse.y;
}

glm::vec2 getMousePosition() {
    return glm::vec2(mouse.x,mouse.y);
}

float getMouseVelX(){
    return mouse.velX;
}

float getMouseVelY(){
    return mouse.velY;
}

glm::vec2 getMouseVelocity() {
    return glm::vec2(mouse.velX,mouse.velY);
}

int getMouseButton(){
    return mouse.button;
}

unsigned char getKeyPressed(){
    return keyPressed;
}

void setRenderRequest(bool _render) {
    bRender = _render;
}

bool getRenderRequest() {
    return bRender;
}
<|endoftext|>


<commit_before>/*
//  segmentation.cpp
//
//  Author:     Sophia Lee
//  Created:    2017. 05. 19. 18:24
//  Copyright (c) 2016 Sophia Lee. All rights reserved.
//
//
*/
#include <seshat/unicode/segmentation.h>

#ifndef SESHAT_ICU_BACKEND
#include <seshat/unicode/properties.h>
#else
#include <unicode/ubrk.h>
#include <unicode/uloc.h> // ULOC_US
#include <unicode/ustring.h> // u_strFromUTF32()
#endif // SESHAT_ICU_BACKEND

namespace seshat {
namespace unicode {

template <typename It>
It grapheme_bound(It first, It last)
{
#ifdef SESHAT_ICU_BACKEND
    std::vector<UChar> seq16; // ICU UTF-16 string
    int32_t seq16_len;
    UChar *p_seq16;
    UErrorCode e = U_ZERO_ERROR;

    if (first == last) // String length 0.
        return first;
    if ((first + 1) == last) // Last code point always breaks (GB2).
        return first;

    // Convert UTF-32(Seshat) to UTF-16(ICU).
    const auto seq = std::vector<uint32_t>(first, last);
    seq16.reserve(seq.size() * 2);
    p_seq16 = u_strFromUTF32(seq16.data(), seq16.capacity(), &seq16_len,
        reinterpret_cast<const UChar32*>(seq.data()), seq.size(),
        &e);

    // Iterate to next character.
    UBreakIterator *brk_iter = ubrk_open(UBRK_CHARACTER, ULOC_US,
        p_seq16, seq16_len, &e);
    int32_t pos = ubrk_next(brk_iter);
    ubrk_close(brk_iter);

    // Get offset of last code point of boundary.
    U16_SET_CP_START(p_seq16, 0, --pos); // Move `pos` to begin of code point.
    decltype(pos) offset = 0;
    while (pos > 0) {
        U16_BACK_1(p_seq16, 0, pos);
        ++offset;
    }

    return first + offset;
#else
    // Alias enum class name scope for code readability.
    using Gcb::CN;
    using Gcb::CR;
    using Gcb::EB;
    using Gcb::EBG;
    using Gcb::EM;
    using Gcb::EX;
    using Gcb::GAZ;
    using Gcb::L;
    using Gcb::LF;
    using Gcb::LV;
    using Gcb::LVT;
    using Gcb::PP;
    using Gcb::RI;
    using Gcb::SM;
    using Gcb::T;
    using Gcb::V;
    using Gcb::ZWJ;

    auto boundary = first;
    auto eot = last;

    for (auto it = first; it != eot; ++it) {
        Gcb cur = gcb(*it);
        Gcb next = gcb(*(it + 1));
        // GB1 - break at the sot
        // GB2 - break at the eot
        if ((it + 1) == eot)
            break;
        // GB3 - do not break between a CR and LF
        if (cur == CR && next == LF) {
            ++boundary;
            continue;
        }
        // GB4 - break before controls
        if (cur == CN || cur == CR || cur == LF)
            break;
        // GB5 - break after controls
        // GB6 - do not break Hangul syllable sequences
        if (cur == L &&
            (next == L || next == V || next == LV || next == LVT)) {
            ++boundary;
            continue;
        }
        // GB7 - do not break Hangul syllable sequences
        if ((cur == LV || cur == V) && (next == V || next == T)) {
            ++boundary;
            continue;
        }
        // GB8 - do not break Hangul syllable sequences
        if ((cur == LVT || cur == T) && next == T) {
            ++boundary;
            continue;
        }
        // GB9 - do not break before Extend or ZWJ
        if (next == EX || next == ZWJ) {
            ++boundary;
            continue;
        }
        // GB9a - do not break before SpacingMark
        if (next == SM) {
            ++boundary;
            continue;
        }
        // GB9b - do not break after Prepend
        if (cur == PP) {
            ++boundary;
            continue;
        }
        // GB10 - do not break within emoji modifier sequences
        if (next == EM) {
            if (cur == EB || cur == EBG) {
                ++boundary;
                continue;
            }
            // Seek back until found EB or EBG
            if (cur == EX) {
                for (auto back_it = it - 1; back_it != first; --back_it) {
                    // Continue to seek if EX
                    if (gcb(*back_it) == EX)
                        continue;
                    // If EB or EBG found, the sequence is
                    // Emoji Modifier Sequence
                    if ((gcb(*back_it) == EB) || (gcb(*back_it) == EBG)) {
                        ++boundary;
                        break;
                    } else {
                        break;
                    }
                }
            }
        }
        // GB11 - do not break within emoji zwj sequences
        // Emoji ZWJ Sequence break not works properly since it
        // requires CLDR expanded rule.
        if (cur == ZWJ && (next == GAZ || next == EBG)) {
            ++boundary;
            continue;
        }
        // GB12 - do not break within emoji flag sequences
        // GB13 - do not break within emoji flag sequences
        if (cur == RI && next == RI) {
            ++boundary;
            break;
        }
        // GB999 - otherwise, break everywhere
        break;
    }
    return boundary;
#endif // SESHAT_ICU_BACKEND
}

template
CodePointSequenceIter grapheme_bound<CodePointSequenceIter>(
    CodePointSequenceIter first, CodePointSequenceIter last);

template
CodePointSequenceConstIter grapheme_bound<CodePointSequenceConstIter>(
    CodePointSequenceConstIter first, CodePointSequenceConstIter last);

} // namespace unicode
} // namespace seshat
<commit_msg>Fixed critical syntactic error.<commit_after>/*
//  segmentation.cpp
//
//  Author:     Sophia Lee
//  Created:    2017. 05. 19. 18:24
//  Copyright (c) 2016 Sophia Lee. All rights reserved.
//
//
*/
#include <seshat/unicode/segmentation.h>

#ifndef SESHAT_ICU_BACKEND
#include <seshat/unicode/properties.h>
#else
#include <unicode/ubrk.h>
#include <unicode/uloc.h> // ULOC_US
#include <unicode/ustring.h> // u_strFromUTF32()
#endif // SESHAT_ICU_BACKEND

namespace seshat {
namespace unicode {

template <typename It>
It grapheme_bound(It first, It last)
{
#ifdef SESHAT_ICU_BACKEND
    std::vector<UChar> seq16; // ICU UTF-16 string
    int32_t seq16_len;
    UChar *p_seq16;
    UErrorCode e = U_ZERO_ERROR;

    if (first == last) // String length 0.
        return first;
    if ((first + 1) == last) // Last code point always breaks (GB2).
        return first;

    // Convert UTF-32(Seshat) to UTF-16(ICU).
    const auto seq = std::vector<uint32_t>(first, last);
    seq16.reserve(seq.size() * 2);
    p_seq16 = u_strFromUTF32(seq16.data(), seq16.capacity(), &seq16_len,
        reinterpret_cast<const UChar32*>(seq.data()), seq.size(),
        &e);

    // Iterate to next character.
    UBreakIterator *brk_iter = ubrk_open(UBRK_CHARACTER, ULOC_US,
        p_seq16, seq16_len, &e);
    int32_t pos = ubrk_next(brk_iter);
    ubrk_close(brk_iter);

    // Get offset of last code point of boundary.
    U16_SET_CP_START(p_seq16, 0, --pos); // Move `pos` to begin of code point.
    decltype(pos) offset = 0;
    while (pos > 0) {
        U16_BACK_1(p_seq16, 0, pos);
        ++offset;
    }

    return first + offset;
#else
    // Alias enum class name scope for code readability.
    constexpr Gcb CN = Gcb::CN;
    constexpr Gcb CR = Gcb::CR;
    constexpr Gcb EB = Gcb::EB;
    constexpr Gcb EBG = Gcb::EBG;
    constexpr Gcb EM = Gcb::EM;
    constexpr Gcb EX = Gcb::EX;
    constexpr Gcb GAZ = Gcb::GAZ;
    constexpr Gcb L = Gcb::L;
    constexpr Gcb LF = Gcb::LF;
    constexpr Gcb LV = Gcb::LV;
    constexpr Gcb LVT = Gcb::LVT;
    constexpr Gcb PP = Gcb::PP;
    constexpr Gcb RI = Gcb::RI;
    constexpr Gcb SM = Gcb::SM;
    constexpr Gcb T = Gcb::T;
    constexpr Gcb V = Gcb::V;
    constexpr Gcb ZWJ = Gcb::ZWJ;

    auto boundary = first;
    auto eot = last;

    for (auto it = first; it != eot; ++it) {
        Gcb cur = gcb(*it);
        Gcb next = gcb(*(it + 1));
        // GB1 - break at the sot
        // GB2 - break at the eot
        if ((it + 1) == eot)
            break;
        // GB3 - do not break between a CR and LF
        if (cur == CR && next == LF) {
            ++boundary;
            continue;
        }
        // GB4 - break before controls
        if (cur == CN || cur == CR || cur == LF)
            break;
        // GB5 - break after controls
        // GB6 - do not break Hangul syllable sequences
        if (cur == L &&
            (next == L || next == V || next == LV || next == LVT)) {
            ++boundary;
            continue;
        }
        // GB7 - do not break Hangul syllable sequences
        if ((cur == LV || cur == V) && (next == V || next == T)) {
            ++boundary;
            continue;
        }
        // GB8 - do not break Hangul syllable sequences
        if ((cur == LVT || cur == T) && next == T) {
            ++boundary;
            continue;
        }
        // GB9 - do not break before Extend or ZWJ
        if (next == EX || next == ZWJ) {
            ++boundary;
            continue;
        }
        // GB9a - do not break before SpacingMark
        if (next == SM) {
            ++boundary;
            continue;
        }
        // GB9b - do not break after Prepend
        if (cur == PP) {
            ++boundary;
            continue;
        }
        // GB10 - do not break within emoji modifier sequences
        if (next == EM) {
            if (cur == EB || cur == EBG) {
                ++boundary;
                continue;
            }
            // Seek back until found EB or EBG
            if (cur == EX) {
                for (auto back_it = it - 1; back_it != first; --back_it) {
                    // Continue to seek if EX
                    if (gcb(*back_it) == EX)
                        continue;
                    // If EB or EBG found, the sequence is
                    // Emoji Modifier Sequence
                    if ((gcb(*back_it) == EB) || (gcb(*back_it) == EBG)) {
                        ++boundary;
                        break;
                    } else {
                        break;
                    }
                }
            }
        }
        // GB11 - do not break within emoji zwj sequences
        // Emoji ZWJ Sequence break not works properly since it
        // requires CLDR expanded rule.
        if (cur == ZWJ && (next == GAZ || next == EBG)) {
            ++boundary;
            continue;
        }
        // GB12 - do not break within emoji flag sequences
        // GB13 - do not break within emoji flag sequences
        if (cur == RI && next == RI) {
            ++boundary;
            break;
        }
        // GB999 - otherwise, break everywhere
        break;
    }
    return boundary;
#endif // SESHAT_ICU_BACKEND
}

template
CodePointSequenceIter grapheme_bound<CodePointSequenceIter>(
    CodePointSequenceIter first, CodePointSequenceIter last);

template
CodePointSequenceConstIter grapheme_bound<CodePointSequenceConstIter>(
    CodePointSequenceConstIter first, CodePointSequenceConstIter last);

} // namespace unicode
} // namespace seshat
<|endoftext|>


<commit_before>//  Copyright (C) 2000  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

#define BX_IN_CPU_METHOD 1
#include "bochs.h"

// Nomenclature used to signify argument types
//
// Es = single real
// El = double real
// Ea = 14/28 bytes    98/108b bytes (FRSTOR,FSAVE)???
// Ew = word integer (2 bytes)
// Ed = dword integer (4 bytes) (short int)
// Et = extended real
// Eb = packed BCD
// Eq = quadword integer (8 bytes) (long integer)

  void
BX_CPU_C::ESC0(BxInstruction_t *i)
{
  if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC0 not implemented\n");
#endif
}

  void
BX_CPU_C::ESC1(BxInstruction_t *i)
{
  if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC1 not implemented\n");
#endif
}

  void
BX_CPU_C::ESC2(BxInstruction_t *i)
{
  if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC2 not implemented\n");
#endif
}

  void
BX_CPU_C::ESC3(BxInstruction_t *i)
{
  if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }

//fprintf(stderr, "CS:EIP = %04x:%08x\n",
//  BX_CPU.sregs[BX_SEG_REG_CS].selector.value, BX_CPU.prev_eip);

#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC3 not implemented\n");
#endif
}

  void
BX_CPU_C::ESC4(BxInstruction_t *i)
{
  if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC4 not implemented\n");
#endif
}

  void
BX_CPU_C::ESC5(BxInstruction_t *i)
{
  if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC5 not implemented\n");
#endif
}

  void
BX_CPU_C::ESC6(BxInstruction_t *i)
{
  if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC6 not implemented\n");
#endif
}

  void
BX_CPU_C::ESC7(BxInstruction_t *i)
{
  if ( BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC7 not implemented\n");
#endif
}

  void
BX_CPU_C::FWAIT(BxInstruction_t *i)
{
#if BX_CPU_LEVEL < 3
  // WAIT doesn't generate single steps on 8086.
  // The same goes for prefix instructions, and instructions which
  // modify segment registers. (pg4-16)
  // BX_CPU_THIS_PTR single_step_event = 0;
  bx_panic("WAIT: not implemented for < 386\n");
#else // BX_CPU_LEVEL >= 3

  if ( BX_CPU_THIS_PTR cr0.ts && BX_CPU_THIS_PTR cr0.mp ) {
    exception(BX_NM_EXCEPTION, 0, 0); // no error
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("FWAIT: no FPU\n");
#endif

#endif
}

#if BX_SUPPORT_FPU==0
  // if supporting FPU, this function in glue logic file
  void
BX_CPU_C::fpu_init(void)
{
}
#endif
<commit_msg>- fixed lots of bugs caused by BX_CPU_THIS_PTR.  Methods of BX_CPU_C should   use local references (no this-> required) and non-methods should use   fpu_cpu_ptr since it is set to the correct CPU before calling fpu code.<commit_after>//  Copyright (C) 2000  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

#define BX_IN_CPU_METHOD 1
#include "bochs.h"

// Nomenclature used to signify argument types
//
// Es = single real
// El = double real
// Ea = 14/28 bytes    98/108b bytes (FRSTOR,FSAVE)???
// Ew = word integer (2 bytes)
// Ed = dword integer (4 bytes) (short int)
// Et = extended real
// Eb = packed BCD
// Eq = quadword integer (8 bytes) (long integer)

  void
BX_CPU_C::ESC0(BxInstruction_t *i)
{
  if ( cr0.em || cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC0 not implemented\n");
#endif
}

  void
BX_CPU_C::ESC1(BxInstruction_t *i)
{
  if ( cr0.em || cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC1 not implemented\n");
#endif
}

  void
BX_CPU_C::ESC2(BxInstruction_t *i)
{
  if ( cr0.em || cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC2 not implemented\n");
#endif
}

  void
BX_CPU_C::ESC3(BxInstruction_t *i)
{
  if ( cr0.em || cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }

//fprintf(stderr, "CS:EIP = %04x:%08x\n",
//  BX_CPU.sregs[BX_SEG_REG_CS].selector.value, BX_CPU.prev_eip);

#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC3 not implemented\n");
#endif
}

  void
BX_CPU_C::ESC4(BxInstruction_t *i)
{
  if ( cr0.em || cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC4 not implemented\n");
#endif
}

  void
BX_CPU_C::ESC5(BxInstruction_t *i)
{
  if ( cr0.em || cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC5 not implemented\n");
#endif
}

  void
BX_CPU_C::ESC6(BxInstruction_t *i)
{
  if ( cr0.em || cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC6 not implemented\n");
#endif
}

  void
BX_CPU_C::ESC7(BxInstruction_t *i)
{
  if ( cr0.em || cr0.ts ) {
    exception(BX_NM_EXCEPTION, 0, 0);
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("ESC7 not implemented\n");
#endif
}

  void
BX_CPU_C::FWAIT(BxInstruction_t *i)
{
#if BX_CPU_LEVEL < 3
  // WAIT doesn't generate single steps on 8086.
  // The same goes for prefix instructions, and instructions which
  // modify segment registers. (pg4-16)
  // single_step_event = 0;
  bx_panic("WAIT: not implemented for < 386\n");
#else // BX_CPU_LEVEL >= 3

  if ( cr0.ts && cr0.mp ) {
    exception(BX_NM_EXCEPTION, 0, 0); // no error
    }
#if BX_SUPPORT_FPU
  fpu_execute(i);
#else
  bx_printf("FWAIT: no FPU\n");
#endif

#endif
}

#if BX_SUPPORT_FPU==0
  // if supporting FPU, this function in glue logic file
  void
BX_CPU_C::fpu_init(void)
{
}
#endif
<|endoftext|>