<commit_before>/// \file libuobject/main.cc

#include <libport/cstdio>
#include <libport/unistd.h>
#include <cerrno>

#include <iostream>
#include <list>
#include <sstream>

#include <libport/cli.hh>
#include <libport/containers.hh>
#include <libport/package-info.hh>
#include <libport/program-name.hh>
#include <libport/sysexits.hh>

#include <urbi/package-info.hh>
#include <urbi/uexternal.hh>
#include <urbi/umain.hh>
#include <urbi/uobject.hh>
#include <urbi/usyncclient.hh>

using libport::program_name;

namespace urbi
{

  // This part is specific for standalone linux objects
  // LIBURBI 'Module mode'

  UCallbackAction
  dispatcher(const UMessage& msg)
  {
    //check message type
    if (msg.type != MESSAGE_DATA || msg.value->type != DATA_LIST)
    {
      msg.client.printf("Component Error: "
			"unknown message content, type %d\n",
			msg.type);
      return URBI_CONTINUE;
    }

    UList& array = *msg.value->list;

    if (array.size()<2)
    {
      msg.client.printf("Component Error: Invalid number "
			"of arguments in the server message: %lu\n",
			static_cast<unsigned long>(array.size()));
      return URBI_CONTINUE;
    }

    if (array[0].type != DATA_DOUBLE)
    {
      msg.client.printf("Component Error: "
			"unknown server message type %d\n",
			array[0].type);
      return URBI_CONTINUE;
    }

    switch ((USystemExternalMessage)(int)array[0])
    {
      case UEM_ASSIGNVALUE:
      {
        if (array.size() != 3)
        {
          msg.client.printf("Component Error: Invalid number "
                            "of arguments in the server message: %lu"
                            " (expected 3)\n",
                            static_cast<unsigned long>(array.size()));
          return URBI_CONTINUE;
        }
        UVarTable::iterator varmapfind = varmap().find(array[1]);
        if (varmapfind != varmap().end())
          for (std::list<UVar*>::iterator it = varmapfind->second.begin();
               it != varmapfind->second.end();
               ++it)
            (*it)->__update(array[2]);

        UTable::iterator monitormapfind = monitormap().find(array[1]);
        if (monitormapfind != monitormap().end())
          for (std::list<UGenericCallback*>::iterator
                 cbit = monitormapfind->second.begin();
               cbit != monitormapfind->second.end();
               ++cbit)
          {
            // test of return value here
            UList u;
            u.array.push_back(new UValue());
            u[0].storage = (*cbit)->storage;
            (*cbit)->__evalcall(u);
          }
      }
      break;

      case UEM_EVALFUNCTION:
      {
	std::list<UGenericCallback*> tmpfun = functionmap()[array[1]];
	std::list<UGenericCallback*>::iterator tmpfunit = tmpfun.begin();
	array.setOffset(3);
	UValue retval = (*tmpfunit)->__evalcall(array);
	array.setOffset(0);
	if (retval.type == DATA_BINARY)
	{
	  // Send it
	  if (urbi::getDefaultClient ())
          {
             // URBI_SEND_COMMAND does not now how to send binary since it
            // depends on the kernel version.
            getDefaultClient()->startPack();
            (*getDefaultClient()) << " var  " << (std::string) array[2] << "=";
            getDefaultClient()->send(retval);
            (*getDefaultClient()) << ";";
            getDefaultClient()->endPack();
          }
	  // Send void if no client. Would block anyway
	  else
	    URBI_SEND_COMMAND("var " << (std::string) array[2]);
	}
	else // Non-binary value.
	  if (retval.type == DATA_VOID)
	    URBI_SEND_COMMAND("var " << (std::string) array[2]);
	  else
	    URBI_SEND_COMMAND("var " << (std::string) array[2] << "=" << retval);
      }
      break;

      case UEM_EMITEVENT:
      {
        if (eventmap().find(array[1]) != eventmap().end())
        {
          std::list<UGenericCallback*> tmpfun = eventmap()[array[1]];
          for (std::list<UGenericCallback*>::iterator i = tmpfun.begin();
               i != tmpfun.end();
               ++i)
          {
            array.setOffset(2);
            (*i)->__evalcall(array);
            array.setOffset(0);
          }
        }
      }
      break;

      case UEM_ENDEVENT:
      {
        if (eventendmap().find(array[1]) != eventendmap().end())
        {
          std::list<UGenericCallback*> tmpfun = eventendmap()[array[1]];
          for (std::list<UGenericCallback*>::iterator i = tmpfun.begin();
               i != tmpfun.end();
               ++i)
          {
            array.setOffset(2);
            (*i)->__evalcall(array);
            array.setOffset(0);
          }
        }
      }

      case UEM_NEW:
      {
        typedef baseURBIStarter::list_type::iterator iterator;
        iterator i_end = baseURBIStarter::list().end();
        iterator found = i_end;
        for (iterator i = baseURBIStarter::list().begin(); i != i_end; ++i)
          if ((*i)->name == (std::string)array[2])
          {
            if (found != i_end)
              msg.client.printf("Double object definition %s\n",
                                (*i)->name.c_str());
            else
              found = i;
          }

        if (found == i_end)
          msg.client.printf("Unknown object definition %s\n",
                            ((std::string) array[2]).c_str());
        else
          (*found)->copy((std::string) array[1]);

      }
      break;

      case UEM_DELETE:
      {
        typedef baseURBIStarter::list_type::iterator iterator;
        iterator i_end = baseURBIStarter::list().end();
        iterator found = i_end;
        for (iterator i = baseURBIStarter::list().begin();
             i != i_end;
             ++i)
          if ((*i)->name == (std::string)array[1])
          {
            if (found != i_end)
              msg.client.printf("Double object definition %s\n",
                                (*i)->name.c_str());
            else
              found = i;
          }

        if (found == i_end)
          msg.client.printf("Unknown object definition %s\n",
                            ((std::string) array[1]).c_str());
        else
        {
          // remove the object from objectlist or terminate
          // the component if there is nothing left
          if (baseURBIStarter::list().size() == 1)
            exit(0);
          else
            // delete the object
            delete *found;
        }
      }
      break;

      default:
        msg.client.printf("Component Error: "
                          "unknown server message type number %d\n",
                          (int)array[0]);
        return URBI_CONTINUE;
    }
    // Send a terminating ';' since code send by the UObject API uses '|'.
    URBI_SEND_COMMAND("");
    return URBI_CONTINUE;
  }

  UCallbackAction
  debug(const UMessage& msg)
  {
    std::stringstream mesg;
    mesg << msg;
    msg.client.printf("DEBUG: got a message: %s\n",  mesg.str().c_str());
    return URBI_CONTINUE;
  }

  UCallbackAction
  static endProgram(const UMessage& msg)
  {
    std::stringstream mesg;
    mesg << msg;
    msg.client.printf("ERROR: got a disconnection message: %s\n",
                      mesg.str().c_str());
    exit(1);
    return URBI_CONTINUE; //stupid gcc
  }

  static
  void
  usage()
  {
    std::cout <<
      "usage:\n" << libport::program_name() << " [OPTION]...\n"
      "\n"
      "Options:\n"
      "  -b, --buffer SIZE     input buffer size"
		 << " [" << UAbstractClient::URBI_BUFLEN << "]\n"
      "  -h, --help            display this message and exit\n"
      "  -H, --host ADDR       server host name   [localhost]\n"
      "      --server          put remote in server mode\n"
      "  -p, --port PORT       tcp port URBI will listen to"
		 << " [" << UAbstractClient::URBI_PORT << "]\n"
      "  -r, --port-file FILE  file containing the port to listen to\n"
      "  -v, --version         print version information and exit\n"
      "  -d, --disconnect      exit program if disconnected(defaults)\n"
      "  -s, --stay-alive      do not exit program if disconnected\n"
		 << libport::exit (EX_OK);
  }

  static
  void
  version()
  {
    std::cout << urbi::package_info() << std::endl
              << libport::exit (EX_OK);
  }

  static int
  initialize(const std::string& host, int port, size_t buflen,
	     bool exitOnDisconnect, bool server)
  {
    std::cerr << program_name()
	      << ": " << urbi::package_info() << std::endl
	      << program_name()
	      << ": Remote Component Running on "
	      << host << " " << port << std::endl;

    new USyncClient(host, port, buflen, server);

    if (exitOnDisconnect)
    {
      if (!getDefaultClient() || getDefaultClient()->error())
	std::cerr << "ERROR: failed to connect, exiting..." << std::endl
		  << libport::exit(1);
      getDefaultClient()->setClientErrorCallback(callback (&endProgram));
    }
   if (!getDefaultClient() || getDefaultClient()->error())
      return 1;

#ifdef LIBURBIDEBUG
    getDefaultClient()->setWildcardCallback(callback (&debug));
#else
    getDefaultClient()->setErrorCallback(callback (&debug));
#endif

    getDefaultClient()->setCallback(&dispatcher,
				    externalModuleTag.c_str());

    // Wait for client to be connected if in server mode
    while (getDefaultClient ()
           && !getDefaultClient()->error ()
           && !getDefaultClient()->init ())
      usleep(20000);

    // Waiting for connectionID
    while (getDefaultClient ()
           && getDefaultClient ()->connectionID () == "")
      usleep (5000);

    dummyUObject = new UObject (0);
    for (baseURBIStarter::list_type::iterator
           i = baseURBIStarter::list().begin(),
           i_end = baseURBIStarter::list().end();
	 i != i_end;
	 ++i)
      (*i)->init((*i)->name);
    // Send a ';' since UObject likely sent a serie of piped commands.
    URBI_SEND_COMMAND("");
    return 0;
  }

  namespace
  {
    static
    void
    argument_with_option(const char* longopt,
                         char shortopt,
                         const std::string& val)
    {
      std::cerr
        << program_name()
        << ": warning: arguments without options are deprecated"
        << std::endl
        << "use `-" << shortopt << ' ' << val << '\''
        << " or `--" << longopt << ' ' << val << "' instead"
        << std::endl
        << "Try `" << program_name() << " --help' for more information."
        << std::endl;
    }

  }

  int
  main(const libport::cli_args_type& args, bool block, bool)
  {
    std::string host = "localhost";
    bool exitOnDisconnect = true;
    int port = UAbstractClient::URBI_PORT;
    bool server = false;
    size_t buflen = UAbstractClient::URBI_BUFLEN;

    // The number of the next (non-option) argument.
    unsigned argp = 1;
    for (unsigned i = 1; i < args.size(); ++i)
    {
      const std::string& arg = args[i];
      if (arg == "--buffer" || arg == "-b")
	buflen = libport::convert_argument<size_t>(args, i++);
      else if (arg == "--disconnect" || arg == "-d")
	exitOnDisconnect = true;
      else if (arg == "--stay-alive" || arg == "-s")
	exitOnDisconnect = false;
      else if (arg == "--help" || arg == "-h")
	usage();
      else if (arg == "--host" || arg == "-H")
	host = libport::convert_argument<std::string>(args, i++);
      else if (arg == "--port" || arg == "-p")
	port = libport::convert_argument<unsigned>(args, i++);
      else if (arg == "--port-file" || arg == "-r")
	port =
          (libport::file_contents_get<int>
           (libport::convert_argument<const char*>(args, i++)));
      else if (arg == "--server")
	server = true;
      else if (arg == "--version" || arg == "-v")
	version();
      else if (arg[0] == '-')
	libport::invalid_option(arg);
      else
	// A genuine argument.
	switch (argp++)
	{
	  case 1:
            argument_with_option("host", 'H', args[i]);
	    host = args[i];
	    break;
	  case 2:
            argument_with_option("port", 'p', args[i]);
	    port = libport::convert_argument<unsigned> ("port", args[i].c_str());
	    break;
	  default:
	    std::cerr << "unexpected argument: " << arg << std::endl
		      << libport::exit(EX_USAGE);
	}
    }

   initialize(host, port, buflen, exitOnDisconnect, server);

   if (block)
     while (true)
       usleep(30000000);
    return 0;
  }

}
<commit_msg>Add a missing break.<commit_after>/// \file libuobject/main.cc

#include <libport/cstdio>
#include <libport/unistd.h>
#include <cerrno>

#include <iostream>
#include <list>
#include <sstream>

#include <libport/cli.hh>
#include <libport/containers.hh>
#include <libport/package-info.hh>
#include <libport/program-name.hh>
#include <libport/sysexits.hh>

#include <urbi/package-info.hh>
#include <urbi/uexternal.hh>
#include <urbi/umain.hh>
#include <urbi/uobject.hh>
#include <urbi/usyncclient.hh>

using libport::program_name;

namespace urbi
{

  // This part is specific for standalone linux objects
  // LIBURBI 'Module mode'

  UCallbackAction
  dispatcher(const UMessage& msg)
  {
    //check message type
    if (msg.type != MESSAGE_DATA || msg.value->type != DATA_LIST)
    {
      msg.client.printf("Component Error: "
			"unknown message content, type %d\n",
			msg.type);
      return URBI_CONTINUE;
    }

    UList& array = *msg.value->list;

    if (array.size()<2)
    {
      msg.client.printf("Component Error: Invalid number "
			"of arguments in the server message: %lu\n",
			static_cast<unsigned long>(array.size()));
      return URBI_CONTINUE;
    }

    if (array[0].type != DATA_DOUBLE)
    {
      msg.client.printf("Component Error: "
			"unknown server message type %d\n",
			array[0].type);
      return URBI_CONTINUE;
    }

    switch ((USystemExternalMessage)(int)array[0])
    {
      case UEM_ASSIGNVALUE:
      {
        if (array.size() != 3)
        {
          msg.client.printf("Component Error: Invalid number "
                            "of arguments in the server message: %lu"
                            " (expected 3)\n",
                            static_cast<unsigned long>(array.size()));
          return URBI_CONTINUE;
        }
        UVarTable::iterator varmapfind = varmap().find(array[1]);
        if (varmapfind != varmap().end())
          for (std::list<UVar*>::iterator it = varmapfind->second.begin();
               it != varmapfind->second.end();
               ++it)
            (*it)->__update(array[2]);

        UTable::iterator monitormapfind = monitormap().find(array[1]);
        if (monitormapfind != monitormap().end())
          for (std::list<UGenericCallback*>::iterator
                 cbit = monitormapfind->second.begin();
               cbit != monitormapfind->second.end();
               ++cbit)
          {
            // test of return value here
            UList u;
            u.array.push_back(new UValue());
            u[0].storage = (*cbit)->storage;
            (*cbit)->__evalcall(u);
          }
      }
      break;

      case UEM_EVALFUNCTION:
      {
	std::list<UGenericCallback*> tmpfun = functionmap()[array[1]];
	std::list<UGenericCallback*>::iterator tmpfunit = tmpfun.begin();
	array.setOffset(3);
	UValue retval = (*tmpfunit)->__evalcall(array);
	array.setOffset(0);
	if (retval.type == DATA_BINARY)
	{
	  // Send it
	  if (urbi::getDefaultClient ())
          {
             // URBI_SEND_COMMAND does not now how to send binary since it
            // depends on the kernel version.
            getDefaultClient()->startPack();
            (*getDefaultClient()) << " var  " << (std::string) array[2] << "=";
            getDefaultClient()->send(retval);
            (*getDefaultClient()) << ";";
            getDefaultClient()->endPack();
          }
	  // Send void if no client. Would block anyway
	  else
	    URBI_SEND_COMMAND("var " << (std::string) array[2]);
	}
	else // Non-binary value.
	  if (retval.type == DATA_VOID)
	    URBI_SEND_COMMAND("var " << (std::string) array[2]);
	  else
	    URBI_SEND_COMMAND("var " << (std::string) array[2] << "=" << retval);
      }
      break;

      case UEM_EMITEVENT:
      {
        if (eventmap().find(array[1]) != eventmap().end())
        {
          std::list<UGenericCallback*> tmpfun = eventmap()[array[1]];
          for (std::list<UGenericCallback*>::iterator i = tmpfun.begin();
               i != tmpfun.end();
               ++i)
          {
            array.setOffset(2);
            (*i)->__evalcall(array);
            array.setOffset(0);
          }
        }
      }
      break;

      case UEM_ENDEVENT:
      {
        if (eventendmap().find(array[1]) != eventendmap().end())
        {
          std::list<UGenericCallback*> tmpfun = eventendmap()[array[1]];
          for (std::list<UGenericCallback*>::iterator i = tmpfun.begin();
               i != tmpfun.end();
               ++i)
          {
            array.setOffset(2);
            (*i)->__evalcall(array);
            array.setOffset(0);
          }
        }
      }
      break;

      case UEM_NEW:
      {
        typedef baseURBIStarter::list_type::iterator iterator;
        iterator i_end = baseURBIStarter::list().end();
        iterator found = i_end;
        for (iterator i = baseURBIStarter::list().begin(); i != i_end; ++i)
          if ((*i)->name == (std::string)array[2])
          {
            if (found != i_end)
              msg.client.printf("Double object definition %s\n",
                                (*i)->name.c_str());
            else
              found = i;
          }

        if (found == i_end)
          msg.client.printf("Unknown object definition %s\n",
                            ((std::string) array[2]).c_str());
        else
          (*found)->copy((std::string) array[1]);

      }
      break;

      case UEM_DELETE:
      {
        typedef baseURBIStarter::list_type::iterator iterator;
        iterator i_end = baseURBIStarter::list().end();
        iterator found = i_end;
        for (iterator i = baseURBIStarter::list().begin();
             i != i_end;
             ++i)
          if ((*i)->name == (std::string)array[1])
          {
            if (found != i_end)
              msg.client.printf("Double object definition %s\n",
                                (*i)->name.c_str());
            else
              found = i;
          }

        if (found == i_end)
          msg.client.printf("Unknown object definition %s\n",
                            ((std::string) array[1]).c_str());
        else
        {
          // remove the object from objectlist or terminate
          // the component if there is nothing left
          if (baseURBIStarter::list().size() == 1)
            exit(0);
          else
            // delete the object
            delete *found;
        }
      }
      break;

      default:
        msg.client.printf("Component Error: "
                          "unknown server message type number %d\n",
                          (int)array[0]);
        return URBI_CONTINUE;
    }
    // Send a terminating ';' since code send by the UObject API uses '|'.
    URBI_SEND_COMMAND("");
    return URBI_CONTINUE;
  }

  UCallbackAction
  debug(const UMessage& msg)
  {
    std::stringstream mesg;
    mesg << msg;
    msg.client.printf("DEBUG: got a message: %s\n",  mesg.str().c_str());
    return URBI_CONTINUE;
  }

  UCallbackAction
  static endProgram(const UMessage& msg)
  {
    std::stringstream mesg;
    mesg << msg;
    msg.client.printf("ERROR: got a disconnection message: %s\n",
                      mesg.str().c_str());
    exit(1);
    return URBI_CONTINUE; //stupid gcc
  }

  static
  void
  usage()
  {
    std::cout <<
      "usage:\n" << libport::program_name() << " [OPTION]...\n"
      "\n"
      "Options:\n"
      "  -b, --buffer SIZE     input buffer size"
		 << " [" << UAbstractClient::URBI_BUFLEN << "]\n"
      "  -h, --help            display this message and exit\n"
      "  -H, --host ADDR       server host name   [localhost]\n"
      "      --server          put remote in server mode\n"
      "  -p, --port PORT       tcp port URBI will listen to"
		 << " [" << UAbstractClient::URBI_PORT << "]\n"
      "  -r, --port-file FILE  file containing the port to listen to\n"
      "  -v, --version         print version information and exit\n"
      "  -d, --disconnect      exit program if disconnected(defaults)\n"
      "  -s, --stay-alive      do not exit program if disconnected\n"
		 << libport::exit (EX_OK);
  }

  static
  void
  version()
  {
    std::cout << urbi::package_info() << std::endl
              << libport::exit (EX_OK);
  }

  static int
  initialize(const std::string& host, int port, size_t buflen,
	     bool exitOnDisconnect, bool server)
  {
    std::cerr << program_name()
	      << ": " << urbi::package_info() << std::endl
	      << program_name()
	      << ": Remote Component Running on "
	      << host << " " << port << std::endl;

    new USyncClient(host, port, buflen, server);

    if (exitOnDisconnect)
    {
      if (!getDefaultClient() || getDefaultClient()->error())
	std::cerr << "ERROR: failed to connect, exiting..." << std::endl
		  << libport::exit(1);
      getDefaultClient()->setClientErrorCallback(callback (&endProgram));
    }
   if (!getDefaultClient() || getDefaultClient()->error())
      return 1;

#ifdef LIBURBIDEBUG
    getDefaultClient()->setWildcardCallback(callback (&debug));
#else
    getDefaultClient()->setErrorCallback(callback (&debug));
#endif

    getDefaultClient()->setCallback(&dispatcher,
				    externalModuleTag.c_str());

    // Wait for client to be connected if in server mode
    while (getDefaultClient ()
           && !getDefaultClient()->error ()
           && !getDefaultClient()->init ())
      usleep(20000);

    // Waiting for connectionID
    while (getDefaultClient ()
           && getDefaultClient ()->connectionID () == "")
      usleep (5000);

    dummyUObject = new UObject (0);
    for (baseURBIStarter::list_type::iterator
           i = baseURBIStarter::list().begin(),
           i_end = baseURBIStarter::list().end();
	 i != i_end;
	 ++i)
      (*i)->init((*i)->name);
    // Send a ';' since UObject likely sent a serie of piped commands.
    URBI_SEND_COMMAND("");
    return 0;
  }

  namespace
  {
    static
    void
    argument_with_option(const char* longopt,
                         char shortopt,
                         const std::string& val)
    {
      std::cerr
        << program_name()
        << ": warning: arguments without options are deprecated"
        << std::endl
        << "use `-" << shortopt << ' ' << val << '\''
        << " or `--" << longopt << ' ' << val << "' instead"
        << std::endl
        << "Try `" << program_name() << " --help' for more information."
        << std::endl;
    }

  }

  int
  main(const libport::cli_args_type& args, bool block, bool)
  {
    std::string host = "localhost";
    bool exitOnDisconnect = true;
    int port = UAbstractClient::URBI_PORT;
    bool server = false;
    size_t buflen = UAbstractClient::URBI_BUFLEN;

    // The number of the next (non-option) argument.
    unsigned argp = 1;
    for (unsigned i = 1; i < args.size(); ++i)
    {
      const std::string& arg = args[i];
      if (arg == "--buffer" || arg == "-b")
	buflen = libport::convert_argument<size_t>(args, i++);
      else if (arg == "--disconnect" || arg == "-d")
	exitOnDisconnect = true;
      else if (arg == "--stay-alive" || arg == "-s")
	exitOnDisconnect = false;
      else if (arg == "--help" || arg == "-h")
	usage();
      else if (arg == "--host" || arg == "-H")
	host = libport::convert_argument<std::string>(args, i++);
      else if (arg == "--port" || arg == "-p")
	port = libport::convert_argument<unsigned>(args, i++);
      else if (arg == "--port-file" || arg == "-r")
	port =
          (libport::file_contents_get<int>
           (libport::convert_argument<const char*>(args, i++)));
      else if (arg == "--server")
	server = true;
      else if (arg == "--version" || arg == "-v")
	version();
      else if (arg[0] == '-')
	libport::invalid_option(arg);
      else
	// A genuine argument.
	switch (argp++)
	{
	  case 1:
            argument_with_option("host", 'H', args[i]);
	    host = args[i];
	    break;
	  case 2:
            argument_with_option("port", 'p', args[i]);
	    port = libport::convert_argument<unsigned> ("port", args[i].c_str());
	    break;
	  default:
	    std::cerr << "unexpected argument: " << arg << std::endl
		      << libport::exit(EX_USAGE);
	}
    }

   initialize(host, port, buflen, exitOnDisconnect, server);

   if (block)
     while (true)
       usleep(30000000);
    return 0;
  }

}
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int N, S, T;

int main () {
  cin >> N >> S >> T;
  if (S > T) {
    cout << -1 << endl;
    return 0;
  }
  int s = S;
  int cnt = 0;
  while (s <= T) {
    if (s == T) {
      cout << cnt << endl;
      return 0;
    }
    s = (s << 1);
  }
  cout << -1 << endl;
}
<commit_msg>submit B.cpp to 'B - Camphor Tree' (kupc2017) [C++14 (GCC 5.4.1)]<commit_after>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int N, S, T;

int main () {
  cin >> N >> S >> T;
  if (S > T) {
    cout << -1 << endl;
    return 0;
  }
  int s = S;
  int cnt = 0;
  while (s <= T) {
    if (s == T) {
      cout << cnt << endl;
      return 0;
    }
    s = (s << 1);
    cnt++;
  }
  cout << -1 << endl;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int A;
string S;
vector<int> V;

int calc(string str) {
  assert(str.size() <= 7);
  int tmp = 1;
  int ans = 0;
  for (auto i = 0; i < (int)str.size(); ++i) {
    ans += tmp * (str[i] - 'a' + 1);
    tmp *= A;
  }
  //cerr << ans << endl;
  return ans;
}

string maximal(int h) {
  string ans = "";
  while (h > 0) {
    for (auto i = 26; i >= 1; --i) {
      if (h - i < 0) continue;
      if ((h - i) % A == 0) {
        string t{(char)('a' + i - 1)};
        ans = ans + t;
        h = (h - i)/A;
        break;
      }
    }
    //cerr << ans << " " << h << endl;
  }
  return ans;
}

int main () {
  cin >> A >> S;
  if (S.size() <= 7) {
    cout << maximal(calc(S)) << endl;
    return 0;
  }
  string T = S.substr(0, S.size()-7);
  string U = S.substr(S.size()-7, 7);
  assert(S == T + U);
  string ans = 0;
  int kari = 0;
  cerr << "xxx" << endl;
  for (auto j = 0; j < (int)T.size(); ++j) {
    char x = T[j];
    int now = x - 'a' + 1;
    now -= kari;
    for (auto i = 26; i >= 1; --i) {
      if ((i - now) % A == 0) {
        string t{(char)('a' + i - 1)};
        ans = ans + t;
        kari = (i - now)/A;
        break;
      }
    }
    cerr << ans << endl;
  }
  ans += maximal(calc(U) + kari);
  cout << ans << endl;
}
<commit_msg>tried C.cpp to 'C'<commit_after>#include <iostream>
#include <iomanip> // << fixed << setprecision(xxx)
#include <algorithm> // do { } while ( next_permutation(A, A+xxx) ) ;
#include <vector>
#include <string> // to_string(nnn) // substr(m, n) // stoi(nnn)
#include <complex>
#include <tuple> // get<n>(xxx)
#include <queue>
#include <stack>
#include <map> // if (M.find(key) != M.end()) { }
#include <set> // S.insert(M);
// if (S.find(key) != S.end()) { }
// for (auto it=S.begin(); it != S.end(); it++) { }
// auto it = S.lower_bound(M);
#include <random> // random_device rd; mt19937 mt(rd());
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib> // atoi(xxx)
using namespace std;

#define DEBUG 0 // change 0 -> 1 if we need debug.
// insert #if<tab> by my emacs. #if DEBUG == 1 ... #end

typedef long long ll;

// const int dx[4] = {1, 0, -1, 0};
// const int dy[4] = {0, 1, 0, -1};

// const int C = 1e6+10;
// const ll M = 1000000007;

int A;
string S;
vector<int> V;

int calc(string str) {
  assert(str.size() <= 7);
  int tmp = 1;
  int ans = 0;
  for (auto i = 0; i < (int)str.size(); ++i) {
    ans += tmp * (str[i] - 'a' + 1);
    tmp *= A;
  }
  //cerr << ans << endl;
  return ans;
}

string maximal(int h) {
  string ans = "";
  while (h > 0) {
    for (auto i = 26; i >= 1; --i) {
      if (h - i < 0) continue;
      if ((h - i) % A == 0) {
        string t{(char)('a' + i - 1)};
        ans = ans + t;
        h = (h - i)/A;
        break;
      }
    }
    //cerr << ans << " " << h << endl;
  }
  return ans;
}

int main () {
  cin >> A >> S;
  if (S.size() <= 7) {
    cout << maximal(calc(S)) << endl;
    return 0;
  }
  string T = S.substr(0, S.size()-7);
  string U = S.substr(S.size()-7, 7);
  assert(S == T + U);
  cerr << "OK" << endl;
  string ans = 0;
  int kari = 0;
  for (auto j = 0; j < (int)T.size(); ++j) {
    char x = T[j];
    int now = x - 'a' + 1;
    now -= kari;
    for (auto i = 26; i >= 1; --i) {
      if ((i - now) % A == 0) {
        string t{(char)('a' + i - 1)};
        ans = ans + t;
        kari = (i - now)/A;
        break;
      }
    }
    cerr << ans << endl;
  }
  ans += maximal(calc(U) + kari);
  cout << ans << endl;
}
<|endoftext|>


<commit_before>// ==========================================================================
//                      RABEMA Read Alignment Benchmark
// ==========================================================================
// Copyright (C) 2010 Manuel Holtgrewe, FU Berlin
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// ==========================================================================
// Author: Manuel Holtgrewe <manuel.holtgrewe@fu-berlin.de>
// ==========================================================================
// Read mapper benchmark tool.  This is the top level program that
// parses the command line parameters and then calls the main routine
// from the headers "build_gold_standard.h" and "evaluation.h".  These
// headers contain the code for building the gold standard and
// comparing the read mapper results against the gold standard.  They
// also contain the command line parsing code used here.
//
// Usage: rabema build_standard -o GOLD_STANDARD.gsi GENOME.fasta GOLD.sam
//        rabema compare GENOME.fasta GOLD_STANDARD.gsi READ_MAPPER_OUTPUT.sam
// ==========================================================================

#include "rabema.h"

#include <iostream>

#include "evaluation.h"
#include "build_gold_standard.h"

/* Print global help.  This function is called when the user specifies
   a wrong simulation command.
 */
void printHelpGlobal() {
    std::cerr << "RABEMA - Read Alignment Benchmark" << std::endl
              << "(c) 2010 by Manuel Holtgrewe" << std::endl
              << std::endl
              << "Usage: rabema build_standard -o GOLD_STANDARD.gsi GENOME.fasta GOLD.sam" << std::endl
              << "       rabema compare GENOME.fasta GOLD_STANDARD.gsi READ_MAPPER_OUTPUT.sam" << std::endl
              << std::endl
              << "Call with 'rabema COMMAND --help' to get detailed help." << std::endl;
}

int parseOptions(Options<Global> & options, const int argc, const char * argv[]) {
    if (argc == 1 ||
        (argc >= 2 && CharString(argv[1]) == "--help") ||
        (argc >= 2 && CharString(argv[1]) == "-h")) {
        printHelpGlobal();
        return 0;
    } else if (argc >=2 && CharString(argv[1]) != "build_standard" && CharString(argv[1]) != "compare") {
        printHelpGlobal();
        return 1;
    }

    if (CharString(argv[1]) == "build_standard") {
        options.selectedCommand = COMMAND_BUILD_STANDARD;
    } else if (CharString(argv[1]) == "compare") {
        options.selectedCommand = COMMAND_EVALUATE;
    } else {
        printHelpGlobal();
        return 1;
    }

    return 0;
}

int main(int argc, char const ** argv)
{
    Options<Global> globalOptions;
    int ret = parseOptions(globalOptions, argc, argv);
    if (ret)
        return ret;

    if (globalOptions.selectedCommand == COMMAND_BUILD_STANDARD) {
        CommandLineParser parser;
        setUpCommandLineParser(parser, BuildGoldStandard());
        Options<BuildGoldStandard> options;
        int ret = parseCommandLineAndCheck(options, parser, argc, argv);
        if (options.showHelp)
            return 0;
        if (ret != 0)
            return ret;
        return buildGoldStandard(options);
    } else if (globalOptions.selectedCommand == COMMAND_EVALUATE) {
        CommandLineParser parser;
        setUpCommandLineParser(parser, EvaluateResults());
        Options<EvaluateResults> options;
        int ret = parseCommandLineAndCheck(options, parser, argc, argv);
        if (options.showHelp)
            return 0;
        if (ret != 0)
            return ret;
        return evaluateReadMapperResult(options);
    } else {
        SEQAN_ASSERT_FAIL("Invalid command!");
    }

    return 0;
}
<commit_msg>Removing confusing assertion if no command is given.<commit_after>// ==========================================================================
//                      RABEMA Read Alignment Benchmark
// ==========================================================================
// Copyright (C) 2010 Manuel Holtgrewe, FU Berlin
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// ==========================================================================
// Author: Manuel Holtgrewe <manuel.holtgrewe@fu-berlin.de>
// ==========================================================================
// Read mapper benchmark tool.  This is the top level program that
// parses the command line parameters and then calls the main routine
// from the headers "build_gold_standard.h" and "evaluation.h".  These
// headers contain the code for building the gold standard and
// comparing the read mapper results against the gold standard.  They
// also contain the command line parsing code used here.
//
// Usage: rabema build_standard -o GOLD_STANDARD.gsi GENOME.fasta GOLD.sam
//        rabema compare GENOME.fasta GOLD_STANDARD.gsi READ_MAPPER_OUTPUT.sam
// ==========================================================================

#include "rabema.h"

#include <iostream>

#include "evaluation.h"
#include "build_gold_standard.h"

/* Print global help.  This function is called when the user specifies
   a wrong simulation command.
 */
void printHelpGlobal() {
    std::cerr << "RABEMA - Read Alignment Benchmark" << std::endl
              << "(c) 2010 by Manuel Holtgrewe" << std::endl
              << std::endl
              << "Usage: rabema build_standard -o GOLD_STANDARD.gsi GENOME.fasta GOLD.sam" << std::endl
              << "       rabema compare GENOME.fasta GOLD_STANDARD.gsi READ_MAPPER_OUTPUT.sam" << std::endl
              << std::endl
              << "Call with 'rabema COMMAND --help' to get detailed help." << std::endl;
}

int parseOptions(Options<Global> & options, const int argc, const char * argv[]) {
    if (argc == 1 ||
        (argc >= 2 && CharString(argv[1]) == "--help") ||
        (argc >= 2 && CharString(argv[1]) == "-h")) {
        printHelpGlobal();
        return 0;
    } else if (argc >=2 && CharString(argv[1]) != "build_standard" && CharString(argv[1]) != "compare") {
        printHelpGlobal();
        return 1;
    }

    if (CharString(argv[1]) == "build_standard") {
        options.selectedCommand = COMMAND_BUILD_STANDARD;
    } else if (CharString(argv[1]) == "compare") {
        options.selectedCommand = COMMAND_EVALUATE;
    } else {
        printHelpGlobal();
        return 1;
    }

    return 0;
}

int main(int argc, char const ** argv)
{
    Options<Global> globalOptions;
    int ret = parseOptions(globalOptions, argc, argv);
    if (ret)
        return ret;

    if (globalOptions.selectedCommand == COMMAND_BUILD_STANDARD) {
        CommandLineParser parser;
        setUpCommandLineParser(parser, BuildGoldStandard());
        Options<BuildGoldStandard> options;
        int ret = parseCommandLineAndCheck(options, parser, argc, argv);
        if (options.showHelp)
            return 0;
        if (ret != 0)
            return ret;
        return buildGoldStandard(options);
    } else if (globalOptions.selectedCommand == COMMAND_EVALUATE) {
        CommandLineParser parser;
        setUpCommandLineParser(parser, EvaluateResults());
        Options<EvaluateResults> options;
        int ret = parseCommandLineAndCheck(options, parser, argc, argv);
        if (options.showHelp)
            return 0;
        if (ret != 0)
            return ret;
        return evaluateReadMapperResult(options);
    }

    return 0;
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "AlembicPropertyUtils.h"
#include <sstream>

void createStringPropertyDisplayModifier(std::string modname, std::vector<std::pair<std::string, std::string>>& nameValuePairs)
{
   //Example usage:
   //
   //GET_MAX_INTERFACE()->SelectNode( pNode );
   //std::vector<std::pair<std::string, std::string>> nameValuePairs;
   //nameValuePairs.push_back(std::pair<std::string, std::string>("Prop1", "Prop1Val"));
   //nameValuePairs.push_back(std::pair<std::string, std::string>("Prop2", "Prop2Val"));
   //nameValuePairs.push_back(std::pair<std::string, std::string>("Prop3", "Prop3Val"));
   //nameValuePairs.push_back(std::pair<std::string, std::string>("Prop4", "Prop4Val"));
   //createPropertiesDisplayModifier(std::string("My Properties"), nameValuePairs);

   //the script assumes a single object is selected

   std::stringstream evalStream;
   evalStream<<"propModifier = EmptyModifier()"<<"\n";
   evalStream<<"propModifier.name = \""<<modname<<"\""<<"\n";
   evalStream<<"modCount = $.modifiers.count"<<"\n";
   evalStream<<"addmodifier $ propModifier before:modCount"<<"\n";
   evalStream<<"$.modifiers[\""<<modname<<"\"].enabled = false"<<"\n";

   evalStream<<"propAttribute = attributes propAttribute"<<"\n";
   evalStream<<"("<<"\n";

   evalStream<<"parameters propAttributePRM1 rollout:propAttributeRLT1"<<"\n";
   evalStream<<"("<<"\n";
   for(int i=0; i<nameValuePairs.size(); i++){
      std::string& name = nameValuePairs[i].first;
      std::string& val = nameValuePairs[i].second;
      evalStream<<name<<" type:#string ui:e"<<name<<" default:\""<<val<<"\""<<"\n";
   }
   evalStream<<")"<<"\n";

   evalStream<<"rollout propAttributeRLT1 \""<<modname<<"\""<<"\n";
   evalStream<<"("<<"\n";
   for(int i=0; i<nameValuePairs.size(); i++){
      std::string& name = nameValuePairs[i].first;
      //std::string& val = nameValuePairs[i].second;
      evalStream<<"edittext e"<<name<<" \""<<name<<"\" fieldWidth:140 labelOnTop:true"<<"\n";
   }
   evalStream<<")"<<"\n";
   evalStream<<")"<<"\n";

   evalStream<<"custattributes.add $.modifiers[\""<<modname<<"\"] propAttribute baseobject:false"<<"\n";

   ExecuteMAXScriptScript( EC_UTF8_to_TCHAR((char*)evalStream.str().c_str()) );
}

void createDisplayModifier(std::string modkey, std::string modname, std::vector<AbcProp>& props)
{

   //the script assumes a single object is selected

   std::stringstream evalStream;
   evalStream<<"propModifier = EmptyModifier()"<<"\n";
   evalStream<<"propModifier.name = \""<<modkey<<"\""<<"\n";
   evalStream<<"modCount = $.modifiers.count"<<"\n";
   evalStream<<"addmodifier $ propModifier before:modCount"<<"\n";
   evalStream<<"$.modifiers[\""<<modkey<<"\"].enabled = false"<<"\n";

   evalStream<<"propAttribute = attributes propAttribute"<<"\n";
   evalStream<<"("<<"\n";

   evalStream<<"parameters propAttributePRM1 rollout:propAttributeRLT1"<<"\n";
   evalStream<<"("<<"\n";
   for(int i=0; i<props.size(); i++){
      std::string& name = props[i].name;
      std::string& val = props[i].displayVal;
      bool& bConstant = props[i].bConstant;

      const AbcA::DataType& datatype = props[i].propHeader.getDataType();
      const AbcA::MetaData& metadata = props[i].propHeader.getMetaData();

      if(datatype.getPod() == AbcA::kFloat32POD && datatype.getExtent() == 1){
         evalStream<<name<<" type:#float ui:e"<<name<<" default:"<<val;
      }
      else if(datatype.getPod() == AbcA::kFloat32POD && datatype.getExtent() == 3){
         if(metadata.get("interpretation") == std::string("rgb")){
            evalStream<<name<<" type:#color ui:e"<<name<<" default:(["<<val<<"] as color)";
         }
         else{
            evalStream<<name<<" type:#point3 ui:e"<<name<<" default:(["<<val<<"] as color)";
         }
      }
      else{
         evalStream<<name<<" type:#string ui:e"<<name<<" default:\""<<val<<"\"";
      }
      evalStream<<"\n";
   }
   evalStream<<")"<<"\n";

   evalStream<<"rollout propAttributeRLT1 \""<<modname<<"\""<<"\n";
   evalStream<<"("<<"\n";

   for(int i=0; i<props.size(); i++){
      std::string& name = props[i].name;
      bool& bConstant = props[i].bConstant;

      evalStream<<"edittext e"<<name<<" \" "<<name<<"\" fieldWidth:140 labelOnTop:true";
      if(bConstant) evalStream<<" readOnly:true";

      evalStream<<"\n";
   }

   evalStream<<"on propAttributeRLT1 open do\n";
   evalStream<<"("<<"\n";

   for(int i=0; i<props.size(); i++){
      std::string& name = props[i].name;

      const AbcA::DataType& datatype = props[i].propHeader.getDataType();
      const AbcA::MetaData& metadata = props[i].propHeader.getMetaData();

      evalStream<<"e"<<name<<".text = "<<name<<" as string";
      evalStream<<"\n";
   }

   evalStream<<")"<<"\n";
   evalStream<<")"<<"\n";
   evalStream<<")"<<"\n";

   evalStream<<"custattributes.add $.modifiers[\""<<modkey<<"\"] propAttribute baseobject:false"<<"\n";

   ExecuteMAXScriptScript( EC_UTF8_to_TCHAR((char*)evalStream.str().c_str()) );
}<commit_msg>issue #307 - Support light import<commit_after>#include "stdafx.h"
#include "AlembicPropertyUtils.h"
#include <sstream>

void createStringPropertyDisplayModifier(std::string modname, std::vector<std::pair<std::string, std::string>>& nameValuePairs)
{
   //Example usage:
   //
   //GET_MAX_INTERFACE()->SelectNode( pNode );
   //std::vector<std::pair<std::string, std::string>> nameValuePairs;
   //nameValuePairs.push_back(std::pair<std::string, std::string>("Prop1", "Prop1Val"));
   //nameValuePairs.push_back(std::pair<std::string, std::string>("Prop2", "Prop2Val"));
   //nameValuePairs.push_back(std::pair<std::string, std::string>("Prop3", "Prop3Val"));
   //nameValuePairs.push_back(std::pair<std::string, std::string>("Prop4", "Prop4Val"));
   //createPropertiesDisplayModifier(std::string("My Properties"), nameValuePairs);

   //the script assumes a single object is selected

   std::stringstream evalStream;
   evalStream<<"propModifier = EmptyModifier()"<<"\n";
   evalStream<<"propModifier.name = \""<<modname<<"\""<<"\n";
   evalStream<<"modCount = $.modifiers.count"<<"\n";
   evalStream<<"addmodifier $ propModifier before:modCount"<<"\n";
   evalStream<<"$.modifiers[\""<<modname<<"\"].enabled = false"<<"\n";

   evalStream<<"propAttribute = attributes propAttribute"<<"\n";
   evalStream<<"("<<"\n";

   evalStream<<"parameters propAttributePRM1 rollout:propAttributeRLT1"<<"\n";
   evalStream<<"("<<"\n";
   for(int i=0; i<nameValuePairs.size(); i++){
      std::string& name = nameValuePairs[i].first;
      std::string& val = nameValuePairs[i].second;
      evalStream<<name<<" type:#string ui:e"<<name<<" default:\""<<val<<"\""<<"\n";
   }
   evalStream<<")"<<"\n";

   evalStream<<"rollout propAttributeRLT1 \""<<modname<<"\""<<"\n";
   evalStream<<"("<<"\n";
   for(int i=0; i<nameValuePairs.size(); i++){
      std::string& name = nameValuePairs[i].first;
      //std::string& val = nameValuePairs[i].second;
      evalStream<<"edittext e"<<name<<" \""<<name<<"\" fieldWidth:140 labelOnTop:true"<<"\n";
   }
   evalStream<<")"<<"\n";
   evalStream<<")"<<"\n";

   evalStream<<"custattributes.add $.modifiers[\""<<modname<<"\"] propAttribute baseobject:false"<<"\n";

   ExecuteMAXScriptScript( EC_UTF8_to_TCHAR((char*)evalStream.str().c_str()) );
}

void createDisplayModifier(std::string modkey, std::string modname, std::vector<AbcProp>& props)
{

   //the script assumes a single object is selected

   std::stringstream evalStream;
   evalStream<<"propModifier = EmptyModifier()"<<"\n";
   evalStream<<"propModifier.name = \""<<modkey<<"\""<<"\n";
   evalStream<<"modCount = $.modifiers.count"<<"\n";
   evalStream<<"addmodifier $ propModifier before:modCount"<<"\n";
   evalStream<<"$.modifiers[\""<<modkey<<"\"].enabled = false"<<"\n";

   evalStream<<"propAttribute = attributes propAttribute"<<"\n";
   evalStream<<"("<<"\n";

   evalStream<<"parameters propAttributePRM1 rollout:propAttributeRLT1"<<"\n";
   evalStream<<"("<<"\n";
   for(int i=0; i<props.size(); i++){
      std::string& name = props[i].name;
      std::string& val = props[i].displayVal;
      bool& bConstant = props[i].bConstant;

      const AbcA::DataType& datatype = props[i].propHeader.getDataType();
      const AbcA::MetaData& metadata = props[i].propHeader.getMetaData();

      if(datatype.getPod() == AbcA::kFloat32POD && datatype.getExtent() == 1){
         evalStream<<name<<" type:#float ui:e"<<name<<" default:"<<val;
      }
      else if(datatype.getPod() == AbcA::kFloat32POD && datatype.getExtent() == 3){
         if(metadata.get("interpretation") == std::string("rgb")){
            evalStream<<name<<" type:#color ui:e"<<name<<" default:(["<<val<<"] as color)";
         }
         else{
            evalStream<<name<<" type:#point3 ui:e"<<name<<" ["<<val<<"]";
         }
      }
      else{
         evalStream<<name<<" type:#string ui:e"<<name<<" default:\""<<val<<"\"";
      }
      evalStream<<"\n";
   }
   evalStream<<")"<<"\n";

   evalStream<<"rollout propAttributeRLT1 \""<<modname<<"\""<<"\n";
   evalStream<<"("<<"\n";

   for(int i=0; i<props.size(); i++){
      std::string& name = props[i].name;
      bool& bConstant = props[i].bConstant;

      evalStream<<"edittext e"<<name<<" \" "<<name<<"\" fieldWidth:140 labelOnTop:true";
      if(bConstant) evalStream<<" readOnly:true";

      evalStream<<"\n";
   }

   evalStream<<"on propAttributeRLT1 open do\n";
   evalStream<<"("<<"\n";

   for(int i=0; i<props.size(); i++){
      std::string& name = props[i].name;

      const AbcA::DataType& datatype = props[i].propHeader.getDataType();
      const AbcA::MetaData& metadata = props[i].propHeader.getMetaData();

      evalStream<<"e"<<name<<".text = "<<name<<" as string";
      evalStream<<"\n";
   }

   evalStream<<")"<<"\n";
   evalStream<<")"<<"\n";
   evalStream<<")"<<"\n";

   evalStream<<"custattributes.add $.modifiers[\""<<modkey<<"\"] propAttribute baseobject:false"<<"\n";

   ExecuteMAXScriptScript( EC_UTF8_to_TCHAR((char*)evalStream.str().c_str()) );
}<|endoftext|>


<commit_before>/* Copyright (c) 2008-2019 the MRtrix3 contributors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Covered Software is provided under this License on an "as is"
 * basis, without warranty of any kind, either expressed, implied, or
 * statutory, including, without limitation, warranties that the
 * Covered Software is free of defects, merchantable, fit for a
 * particular purpose or non-infringing.
 * See the Mozilla Public License v. 2.0 for more details.
 *
 * For more details, see http://www.mrtrix.org/.
 */

#include "dwi/gradient.h"
#include "file/nifti_utils.h"

namespace MR
{
  namespace DWI
  {

    using namespace App;
    using namespace Eigen;

    OptionGroup GradImportOptions ()
    {
      OptionGroup group ("DW gradient table import options");

      group
        + Option ("grad",
            "Provide the diffusion-weighted gradient scheme used in the acquisition "
            "in a text file. This should be supplied as a 4xN text file with each line "
            "is in the format [ X Y Z b ], where [ X Y Z ] describe the direction of the "
            "applied gradient, and b gives the b-value in units of s/mm^2. If a diffusion "
            "gradient scheme is present in the input image header, the data provided with "
            "this option will be instead used.")
        +   Argument ("file").type_file_in()

        + Option ("fslgrad",
            "Provide the diffusion-weighted gradient scheme used in the acquisition in FSL "
            "bvecs/bvals format files. If a diffusion gradient scheme is present in the "
            "input image header, the data provided with this option will be instead used.")
        +   Argument ("bvecs").type_file_in()
        +   Argument ("bvals").type_file_in();

      return group;
    }

    OptionGroup GradExportOptions()
    {
      return OptionGroup ("DW gradient table export options")

        + Option ("export_grad_mrtrix", "export the diffusion-weighted gradient table to file in MRtrix format")
        +   Argument ("path").type_file_out()

        + Option ("export_grad_fsl", "export the diffusion-weighted gradient table to files in FSL (bvecs / bvals) format")
        +   Argument ("bvecs_path").type_file_out()
        +   Argument ("bvals_path").type_file_out();
    }

    Eigen::MatrixXd parse_DW_scheme (const Header& header)
    {
      Eigen::MatrixXd G;
      const auto it = header.keyval().find ("dw_scheme");
      if (it != header.keyval().end()) {
        try {
          G = parse_matrix (it->second);
        } catch (Exception& e) {
          throw Exception (e, "malformed DW scheme in image \"" + header.name() + "\"");
        }
      }
      return G;
    }

    Eigen::MatrixXd load_bvecs_bvals (const Header& header, const std::string& bvecs_path, const std::string& bvals_path)
    {
      Eigen::MatrixXd bvals, bvecs;
      try {
        bvals = load_matrix<> (bvals_path);
        bvecs = load_matrix<> (bvecs_path);
      } catch (Exception& e) {
        throw Exception (e, "Unable to import files \"" + bvecs_path + "\" and \"" + bvals_path + "\" as FSL bvecs/bvals pair");
      }

      if (bvals.rows() != 1) {
        if (bvals.cols() == 1)
          bvals.transposeInPlace();  // transpose if file contains column vector
        else
          throw Exception ("bvals file must contain 1 row or column only (file \"" + bvals_path + "\" has " + str(bvals.rows()) + ")");
      }
      if (bvecs.rows() != 3) {
        if (bvecs.cols() == 3)
          bvecs.transposeInPlace();
        else
          throw Exception ("bvecs file must contain exactly 3 rows or columns (file \"" + bvecs_path + "\" has " + str(bvecs.rows()) + ")");
      }

      if (bvals.cols() != bvecs.cols())
        throw Exception ("bvecs and bvals files must have same number of diffusion directions (file \"" + bvecs_path + "\" has " + str(bvecs.cols()) + ", file \"" + bvals_path + "\" has " + str(bvals.cols()) + ")");

      const size_t num_volumes = header.ndim() < 4 ? 1 : header.size(3);
      if (size_t(bvals.cols()) != num_volumes)
        throw Exception ("bvecs and bvals files must have same number of diffusion directions as DW-image (gradients: " + str(bvecs.cols()) + ", image: " + str(num_volumes) + ")");

      // bvecs format actually assumes a LHS coordinate system even if image is
      // stored using RHS - x axis is flipped to make linear 3x3 part of
      // transform have negative determinant:
      vector<size_t> order;
      auto adjusted_transform = File::NIfTI::adjust_transform (header, order);
      if (adjusted_transform.linear().determinant() > 0.0)
        bvecs.row(0) = -bvecs.row(0);

      // account for the fact that bvecs are specified wrt original image axes,
      // which may have been re-ordered and/or inverted by MRtrix to match the
      // expected anatomical frame of reference:
      Eigen::MatrixXd G (bvecs.cols(), 3);
      for (ssize_t n = 0; n < G.rows(); ++n) {
        G(n,order[0]) = header.stride(order[0]) > 0 ? bvecs(0,n) : -bvecs(0,n);
        G(n,order[1]) = header.stride(order[1]) > 0 ? bvecs(1,n) : -bvecs(1,n);
        G(n,order[2]) = header.stride(order[2]) > 0 ? bvecs(2,n) : -bvecs(2,n);
      }

      // rotate gradients into scanner coordinate system:
      Eigen::MatrixXd grad (G.rows(), 4);

      grad.leftCols<3>().transpose() = header.transform().rotation() * G.transpose();
      grad.col(3) = bvals.row(0);

      return grad;
    }

    void save_bvecs_bvals (const Header& header, const std::string& bvecs_path, const std::string& bvals_path)
    {
      const auto grad = parse_DW_scheme (header);

      // rotate vectors from scanner space to image space
      Eigen::MatrixXd G = grad.leftCols<3>() * header.transform().rotation();

      // deal with FSL requiring gradient directions to coincide with data strides
      // also transpose matrices in preparation for file output
      vector<size_t> order;
      auto adjusted_transform = File::NIfTI::adjust_transform (header, order);
      Eigen::MatrixXd bvecs (3, grad.rows());
      Eigen::MatrixXd bvals (1, grad.rows());
      for (ssize_t n = 0; n < G.rows(); ++n) {
        bvecs(0,n) = header.stride(order[0]) > 0 ? G(n,order[0]) : -G(n,order[0]);
        bvecs(1,n) = header.stride(order[1]) > 0 ? G(n,order[1]) : -G(n,order[1]);
        bvecs(2,n) = header.stride(order[2]) > 0 ? G(n,order[2]) : -G(n,order[2]);
        bvals(0,n) = grad(n,3);
      }

      // bvecs format actually assumes a LHS coordinate system even if image is
      // stored using RHS - x axis is flipped to make linear 3x3 part of
      // transform have negative determinant:
      if (adjusted_transform.linear().determinant() > 0.0)
        bvecs.row(0) = -bvecs.row(0);

      save_matrix (bvecs, bvecs_path, KeyValues(), false);
      save_matrix (bvals, bvals_path, KeyValues(), false);
    }

    void clear_DW_scheme (Header& header)
    {
      auto it = header.keyval().find ("dw_scheme");
      if (it != header.keyval().end())
        header.keyval().erase (it);
    }

    Eigen::MatrixXd get_raw_DW_scheme (const Header& header)
    {
      DEBUG ("searching for suitable gradient encoding...");
      using namespace App;
      Eigen::MatrixXd grad;

      // check whether the DW scheme has been provided via the command-line:
      const auto opt_mrtrix = get_options ("grad");
      if (opt_mrtrix.size())
        grad = load_matrix<> (opt_mrtrix[0][0]);

      const auto opt_fsl = get_options ("fslgrad");
      if (opt_fsl.size()) {
        if (opt_mrtrix.size())
          throw Exception ("Diffusion gradient table can be provided using either -grad or -fslgrad option, but NOT both");
        grad = load_bvecs_bvals (header, opt_fsl[0][0], opt_fsl[0][1]);
      }

      // otherwise use the information from the header:
      if (!opt_mrtrix.size() && !opt_fsl.size())
        grad = parse_DW_scheme (header);

      return grad;
    }

    Eigen::MatrixXd get_DW_scheme (const Header& header, bool bvalue_scaling)
    {
      try {
        auto grad = get_raw_DW_scheme (header);
        check_DW_scheme (header, grad);

        if (bvalue_scaling)
          scale_bvalue_by_G_squared (grad, 1.0e-3);

        normalise_grad (grad);
        // write the scheme as interpreted back into the header:
        set_DW_scheme (const_cast<Header&> (header), grad);

        INFO ("found " + str (grad.rows()) + "x" + str (grad.cols()) + " diffusion gradient table");
        return grad;
      }
      catch (Exception& e) {
        throw Exception (e, "error importing diffusion gradient table for image \"" + header.name() + "\"");
      }
    }

    void export_grad_commandline (const Header& header)
    {
      auto check = [](const Header& h) -> const Header& {
        if (h.keyval().find("dw_scheme") == h.keyval().end())
          throw Exception ("no gradient information found within image \"" + h.name() + "\"");
        return h;
      };

      auto opt = get_options ("export_grad_mrtrix");
      if (opt.size())
        save_matrix (parse_DW_scheme (check (header)), opt[0][0]);

      opt = get_options ("export_grad_fsl");
      if (opt.size())
        save_bvecs_bvals (check (header), opt[0][0], opt[0][1]);
    }

  }
}

<commit_msg>DW scheme handling: clear DW scheme from header on error<commit_after>/* Copyright (c) 2008-2019 the MRtrix3 contributors.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Covered Software is provided under this License on an "as is"
 * basis, without warranty of any kind, either expressed, implied, or
 * statutory, including, without limitation, warranties that the
 * Covered Software is free of defects, merchantable, fit for a
 * particular purpose or non-infringing.
 * See the Mozilla Public License v. 2.0 for more details.
 *
 * For more details, see http://www.mrtrix.org/.
 */

#include "dwi/gradient.h"
#include "file/nifti_utils.h"

namespace MR
{
  namespace DWI
  {

    using namespace App;
    using namespace Eigen;

    OptionGroup GradImportOptions ()
    {
      OptionGroup group ("DW gradient table import options");

      group
        + Option ("grad",
            "Provide the diffusion-weighted gradient scheme used in the acquisition "
            "in a text file. This should be supplied as a 4xN text file with each line "
            "is in the format [ X Y Z b ], where [ X Y Z ] describe the direction of the "
            "applied gradient, and b gives the b-value in units of s/mm^2. If a diffusion "
            "gradient scheme is present in the input image header, the data provided with "
            "this option will be instead used.")
        +   Argument ("file").type_file_in()

        + Option ("fslgrad",
            "Provide the diffusion-weighted gradient scheme used in the acquisition in FSL "
            "bvecs/bvals format files. If a diffusion gradient scheme is present in the "
            "input image header, the data provided with this option will be instead used.")
        +   Argument ("bvecs").type_file_in()
        +   Argument ("bvals").type_file_in();

      return group;
    }

    OptionGroup GradExportOptions()
    {
      return OptionGroup ("DW gradient table export options")

        + Option ("export_grad_mrtrix", "export the diffusion-weighted gradient table to file in MRtrix format")
        +   Argument ("path").type_file_out()

        + Option ("export_grad_fsl", "export the diffusion-weighted gradient table to files in FSL (bvecs / bvals) format")
        +   Argument ("bvecs_path").type_file_out()
        +   Argument ("bvals_path").type_file_out();
    }

    Eigen::MatrixXd parse_DW_scheme (const Header& header)
    {
      Eigen::MatrixXd G;
      const auto it = header.keyval().find ("dw_scheme");
      if (it != header.keyval().end()) {
        try {
          G = parse_matrix (it->second);
        } catch (Exception& e) {
          throw Exception (e, "malformed DW scheme in image \"" + header.name() + "\"");
        }
      }
      return G;
    }

    Eigen::MatrixXd load_bvecs_bvals (const Header& header, const std::string& bvecs_path, const std::string& bvals_path)
    {
      Eigen::MatrixXd bvals, bvecs;
      try {
        bvals = load_matrix<> (bvals_path);
        bvecs = load_matrix<> (bvecs_path);
      } catch (Exception& e) {
        throw Exception (e, "Unable to import files \"" + bvecs_path + "\" and \"" + bvals_path + "\" as FSL bvecs/bvals pair");
      }

      if (bvals.rows() != 1) {
        if (bvals.cols() == 1)
          bvals.transposeInPlace();  // transpose if file contains column vector
        else
          throw Exception ("bvals file must contain 1 row or column only (file \"" + bvals_path + "\" has " + str(bvals.rows()) + ")");
      }
      if (bvecs.rows() != 3) {
        if (bvecs.cols() == 3)
          bvecs.transposeInPlace();
        else
          throw Exception ("bvecs file must contain exactly 3 rows or columns (file \"" + bvecs_path + "\" has " + str(bvecs.rows()) + ")");
      }

      if (bvals.cols() != bvecs.cols())
        throw Exception ("bvecs and bvals files must have same number of diffusion directions (file \"" + bvecs_path + "\" has " + str(bvecs.cols()) + ", file \"" + bvals_path + "\" has " + str(bvals.cols()) + ")");

      const size_t num_volumes = header.ndim() < 4 ? 1 : header.size(3);
      if (size_t(bvals.cols()) != num_volumes)
        throw Exception ("bvecs and bvals files must have same number of diffusion directions as DW-image (gradients: " + str(bvecs.cols()) + ", image: " + str(num_volumes) + ")");

      // bvecs format actually assumes a LHS coordinate system even if image is
      // stored using RHS - x axis is flipped to make linear 3x3 part of
      // transform have negative determinant:
      vector<size_t> order;
      auto adjusted_transform = File::NIfTI::adjust_transform (header, order);
      if (adjusted_transform.linear().determinant() > 0.0)
        bvecs.row(0) = -bvecs.row(0);

      // account for the fact that bvecs are specified wrt original image axes,
      // which may have been re-ordered and/or inverted by MRtrix to match the
      // expected anatomical frame of reference:
      Eigen::MatrixXd G (bvecs.cols(), 3);
      for (ssize_t n = 0; n < G.rows(); ++n) {
        G(n,order[0]) = header.stride(order[0]) > 0 ? bvecs(0,n) : -bvecs(0,n);
        G(n,order[1]) = header.stride(order[1]) > 0 ? bvecs(1,n) : -bvecs(1,n);
        G(n,order[2]) = header.stride(order[2]) > 0 ? bvecs(2,n) : -bvecs(2,n);
      }

      // rotate gradients into scanner coordinate system:
      Eigen::MatrixXd grad (G.rows(), 4);

      grad.leftCols<3>().transpose() = header.transform().rotation() * G.transpose();
      grad.col(3) = bvals.row(0);

      return grad;
    }

    void save_bvecs_bvals (const Header& header, const std::string& bvecs_path, const std::string& bvals_path)
    {
      const auto grad = parse_DW_scheme (header);

      // rotate vectors from scanner space to image space
      Eigen::MatrixXd G = grad.leftCols<3>() * header.transform().rotation();

      // deal with FSL requiring gradient directions to coincide with data strides
      // also transpose matrices in preparation for file output
      vector<size_t> order;
      auto adjusted_transform = File::NIfTI::adjust_transform (header, order);
      Eigen::MatrixXd bvecs (3, grad.rows());
      Eigen::MatrixXd bvals (1, grad.rows());
      for (ssize_t n = 0; n < G.rows(); ++n) {
        bvecs(0,n) = header.stride(order[0]) > 0 ? G(n,order[0]) : -G(n,order[0]);
        bvecs(1,n) = header.stride(order[1]) > 0 ? G(n,order[1]) : -G(n,order[1]);
        bvecs(2,n) = header.stride(order[2]) > 0 ? G(n,order[2]) : -G(n,order[2]);
        bvals(0,n) = grad(n,3);
      }

      // bvecs format actually assumes a LHS coordinate system even if image is
      // stored using RHS - x axis is flipped to make linear 3x3 part of
      // transform have negative determinant:
      if (adjusted_transform.linear().determinant() > 0.0)
        bvecs.row(0) = -bvecs.row(0);

      save_matrix (bvecs, bvecs_path, KeyValues(), false);
      save_matrix (bvals, bvals_path, KeyValues(), false);
    }

    void clear_DW_scheme (Header& header)
    {
      auto it = header.keyval().find ("dw_scheme");
      if (it != header.keyval().end())
        header.keyval().erase (it);
    }

    Eigen::MatrixXd get_raw_DW_scheme (const Header& header)
    {
      DEBUG ("searching for suitable gradient encoding...");
      using namespace App;
      Eigen::MatrixXd grad;

      // check whether the DW scheme has been provided via the command-line:
      const auto opt_mrtrix = get_options ("grad");
      if (opt_mrtrix.size())
        grad = load_matrix<> (opt_mrtrix[0][0]);

      const auto opt_fsl = get_options ("fslgrad");
      if (opt_fsl.size()) {
        if (opt_mrtrix.size())
          throw Exception ("Diffusion gradient table can be provided using either -grad or -fslgrad option, but NOT both");
        grad = load_bvecs_bvals (header, opt_fsl[0][0], opt_fsl[0][1]);
      }

      // otherwise use the information from the header:
      if (!opt_mrtrix.size() && !opt_fsl.size())
        grad = parse_DW_scheme (header);

      return grad;
    }

    Eigen::MatrixXd get_DW_scheme (const Header& header, bool bvalue_scaling)
    {
      try {
        auto grad = get_raw_DW_scheme (header);
        check_DW_scheme (header, grad);

        if (bvalue_scaling)
          scale_bvalue_by_G_squared (grad, 1.0e-3);

        normalise_grad (grad);
        // write the scheme as interpreted back into the header:
        set_DW_scheme (const_cast<Header&> (header), grad);

        INFO ("found " + str (grad.rows()) + "x" + str (grad.cols()) + " diffusion gradient table");
        return grad;
      }
      catch (Exception& e) {
        clear_DW_scheme (const_cast<Header&> (header));
        throw Exception (e, "error importing diffusion gradient table for image \"" + header.name() + "\"");
      }
    }

    void export_grad_commandline (const Header& header)
    {
      auto check = [](const Header& h) -> const Header& {
        if (h.keyval().find("dw_scheme") == h.keyval().end())
          throw Exception ("no gradient information found within image \"" + h.name() + "\"");
        return h;
      };

      auto opt = get_options ("export_grad_mrtrix");
      if (opt.size())
        save_matrix (parse_DW_scheme (check (header)), opt[0][0]);

      opt = get_options ("export_grad_fsl");
      if (opt.size())
        save_bvecs_bvals (check (header), opt[0][0], opt[0][1]);
    }

  }
}

<|endoftext|>


<commit_before>#pragma once
#include "xlib.hpp"
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/glx.h>
#include "widget.hpp"
#include "events.hpp"
#include "utf.hpp"
#include <cstring>
#include <stdexcept>

namespace wheel
{
	constexpr char const*const atomnames[] = { "UTF8_STRING", "WM_DELETE_WINDOW", "_NET_WM_NAME", "_NET_WM_STATE", "_NET_WM_STATE_FULLSCREEN" };

	struct application : widget, xlib::display
	{
		eventloop events;
		xlib::atoms<atomnames,5> atom;
		GLXContext ctx = 0;
		Visual *vis = 0;
		point m;

		application(uint8_t depth = 16, uint8_t stencil = 0, uint8_t r = 1, uint8_t g = 1, uint8_t b = 1, uint8_t a = 1) : atom(dpy)
		{
			set(0,0,DisplayWidth(dpy,screen()),DisplayHeight(dpy,screen()));
			int attr[] = { GLX_RGBA, GLX_DOUBLEBUFFER, True,
				GLX_RED_SIZE,r, GLX_GREEN_SIZE,g, GLX_BLUE_SIZE,b, GLX_ALPHA_SIZE,a, GLX_DEPTH_SIZE, depth, GLX_STENCIL_SIZE, stencil, 0 };
			if(XVisualInfo *vi = glXChooseVisual(dpy, screen(), attr))
			{
				vis = vi->visual;
				ctx = glXCreateContext(dpy, vi, 0, True);
			}
			else throw std::runtime_error("glXChooseVisual failed");
			events.add(pollfd{fd(),POLLIN}, [&](pollfd) { nextevent(); });
		}

		~application()
		{
			events.remove(pollfd{fd()});
			if(ctx) { glXMakeCurrent(dpy, 0, 0); glXDestroyContext(dpy, ctx); }
		}

		operator bool() const { return !children.empty(); }

		int width() const { return rect::width(); }
		int height() const { return rect::height(); }
		point pointer() const { return m; }

		void process(int timeout = -1)
		{
			while(qlen()) nextevent();
			events.process(timeout);
		}

		inline void nextevent();
	};

	namespace native
	{
		struct window : widget
		{
			bool active;
			Window wnd;

			operator Window() const { return wnd; }
			application& app() { return *(application*)parent; }

			window(application& app, const char *title, int w = 0, int h = 0)
			{
				XSetWindowAttributes wa;
				wa.border_pixel = 0;
				wa.colormap = XCreateColormap(app, app.root(), app.vis, AllocNone);
				wa.event_mask = KeyPressMask|KeyReleaseMask|PointerMotionMask|ButtonPressMask|ButtonReleaseMask|
					StructureNotifyMask|ExposureMask|FocusChangeMask|VisibilityChangeMask;

				if(!w) w = app.width();
				if(!h) h = app.height();
				wnd = XCreateWindow(app, app.root(), 0,0,w,h, 0, app.depth(), InputOutput, app.vis, CWBorderPixel|CWColormap|CWEventMask, &wa);
				if(!wnd) throw std::runtime_error("Failed to create window");
				set(0,0,w,h);

				XChangeProperty(app, wnd, app.atom["_NET_WM_NAME"], app.atom["UTF8_STRING"], 8, PropModeReplace, (uint8_t*)title, strlen(title));
				XSetWMProtocols(app, wnd, &app.atom["WM_DELETE_WINDOW"], 1);

				parent = &app;
				app.children.push_back(this);
			}

			void show(bool b) { if(b) { makecurrent(); XMapWindow(app(), wnd); } else { glXMakeCurrent(app(),0,0); XUnmapWindow(app(), wnd); } }

			void fullscreen(int b)
			{
				app().sendclient(wnd, app().atom["_NET_WM_STATE"], StructureNotifyMask, b, app().atom["_NET_WM_STATE_FULLSCREEN"]);
			}

			void togglefullscreen() { fullscreen(2); }
			void makecurrent() { glXMakeCurrent(app(), wnd, app().ctx); }
			void draw() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); widget::draw(); flip(); }
			void flip() { glXSwapBuffers(app(), wnd); }
		};
	}

	void application::nextevent()
	{
		XEvent event; XNextEvent(dpy, &event);
		Window wnd = event.xany.window;
		widget *w = 0;
		if(wnd == root()) w = this; else for(widget *c : children) if(((native::window*)c)->wnd == wnd) { w = c; break; }
		if(w) switch(event.type)
		{
			case KeyPress:
			{
				uint8_t k = xlib::key(&event.xkey);
				key::state(k) = 1; w->press(k);
				if(!key::lalt && !key::lcontrol && !key::lmenu && !key::ralt && !key::rcontrol && !key::rmenu) if(' ' <= k && k < key::del)
				{
					char c[16];
					Status stat;
					if(int n = Xutf8LookupString(ic, (XKeyPressedEvent*)&event, c, 16, 0, &stat))
					{
						uint32_t uc;
						utf8to32(c, c + n, &uc);
						w->keycode(uc);
					}
				}
				break;
			}

			case KeyRelease:
			{
				if(XEventsQueued(dpy, QueuedAfterReading))
				{
					XEvent nextEvent;
					XPeekEvent(dpy, &nextEvent);
					if(nextEvent.type == KeyPress && nextEvent.xkey.window == event.xkey.window &&
					   nextEvent.xkey.keycode == event.xkey.keycode && nextEvent.xkey.time - event.xkey.time < 20) break;
				}
				uint8_t k = xlib::key(&event.xkey);
				key::state(k) = 0; w->release(k);
				break;
			}

			case ButtonPress:
				m = point(event.xbutton.x_root, event.xbutton.y_root);
				switch(event.xbutton.button)
				{
					case Button1: key::state(key::lbutton) = 1; w->press(key::lbutton); break;
					case Button2: key::state(key::mbutton) = 1; w->press(key::mbutton); break;
					case Button3: key::state(key::rbutton) = 1; w->press(key::rbutton); break;
					case Button4: w->scroll(-1); break;
					case Button5: w->scroll(+1); break;
				}
				break;

			case ButtonRelease:
				switch(event.xbutton.button)
				{
					case Button1: key::state(key::lbutton) = 0; w->release(key::lbutton); break;
					case Button2: key::state(key::mbutton) = 0; w->release(key::mbutton); break;
					case Button3: key::state(key::rbutton) = 0; w->release(key::rbutton); break;
				}
				break;

			case ConfigureNotify:
				w->set(event.xconfigure.x, event.xconfigure.y, event.xconfigure.width, event.xconfigure.height);
				w->resize();
				break;

			case MotionNotify: m = point(event.xmotion.x_root,event.xmotion.y_root); w->pointermove(); break;
			case ClientMessage: if((Atom)event.xclient.data.l[0] == atom["WM_DELETE_WINDOW"]) w->close(); break;
			case DestroyNotify: w->close(); break;
		}
	}
}
<commit_msg>Fixed Window creation for KDE<commit_after>#pragma once
#include "xlib.hpp"
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/glx.h>
#include "widget.hpp"
#include "events.hpp"
#include "utf.hpp"
#include <cstring>
#include <stdexcept>

namespace wheel
{
	constexpr char const*const atomnames[] = { "UTF8_STRING", "WM_DELETE_WINDOW", "_NET_WM_NAME", "_NET_WM_STATE", "_NET_WM_STATE_FULLSCREEN" };

	struct application : widget, xlib::display
	{
		eventloop events;
		xlib::atoms<atomnames,5> atom;
		GLXContext ctx = 0;
		Visual *vis = 0;
		point m;

		application(uint8_t depth = 16, uint8_t stencil = 0, uint8_t r = 1, uint8_t g = 1, uint8_t b = 1, uint8_t a = 1) : atom(dpy)
		{
			set(0,0,DisplayWidth(dpy,screen()),DisplayHeight(dpy,screen()));
			int attr[] = { GLX_RGBA, GLX_DOUBLEBUFFER, True,
				GLX_RED_SIZE,r, GLX_GREEN_SIZE,g, GLX_BLUE_SIZE,b, GLX_ALPHA_SIZE,a, GLX_DEPTH_SIZE, depth, GLX_STENCIL_SIZE, stencil, 0 };
			if(XVisualInfo *vi = glXChooseVisual(dpy, screen(), attr))
			{
				vis = vi->visual;
				ctx = glXCreateContext(dpy, vi, 0, True);
			}
			else throw std::runtime_error("glXChooseVisual failed");
			events.add(pollfd{fd(),POLLIN}, [&](pollfd) { nextevent(); });
		}

		~application()
		{
			events.remove(pollfd{fd()});
			if(ctx) { glXMakeCurrent(dpy, 0, 0); glXDestroyContext(dpy, ctx); }
		}

		operator bool() const { return !children.empty(); }

		int width() const { return rect::width(); }
		int height() const { return rect::height(); }
		point pointer() const { return m; }

		void process(int timeout = -1)
		{
			while(qlen()) nextevent();
			events.process(timeout);
		}

		inline void nextevent();
	};

	namespace native
	{
		struct window : widget
		{
			bool active;
			Window wnd;

			operator Window() const { return wnd; }
			application& app() { return *(application*)parent; }

			window(application& app, const char *title, int w = 0, int h = 0)
			{
				XSetWindowAttributes wa;
				wa.border_pixel = 0;
				wa.colormap = XCreateColormap(app, app.root(), app.vis, AllocNone);
				wa.event_mask = KeyPressMask|KeyReleaseMask|PointerMotionMask|ButtonPressMask|ButtonReleaseMask|
					StructureNotifyMask|ExposureMask|FocusChangeMask|VisibilityChangeMask;

				if(!w) w = app.width();
				if(!h) h = app.height();
				wnd = XCreateWindow(app, app.root(), 0,0,w,h, 0, app.depth(), InputOutput, app.vis, CWBorderPixel|CWColormap|CWEventMask, &wa);
				if(!wnd) throw std::runtime_error("Failed to create window");
				set(0,0,w,h);

				XChangeProperty(app, wnd, app.atom["_NET_WM_NAME"], app.atom["UTF8_STRING"], 8, PropModeReplace, (uint8_t*)title, strlen(title));
				XSetWMProtocols(app, wnd, &app.atom["WM_DELETE_WINDOW"], 1);

				parent = &app;
				app.children.push_back(this);
			}

			void show(bool b) { if(b) { makecurrent(); XMapWindow(app(), wnd); XFlush(app());} else { glXMakeCurrent(app(),0,0); XUnmapWindow(app(), wnd); } }

			void fullscreen(int b)
			{
				app().sendclient(wnd, app().atom["_NET_WM_STATE"], StructureNotifyMask, b, app().atom["_NET_WM_STATE_FULLSCREEN"]);
			}

			void togglefullscreen() { fullscreen(2); }
			void makecurrent() { glXMakeCurrent(app(), wnd, app().ctx); }
			void draw() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); widget::draw(); flip(); }
			void flip() { glXSwapBuffers(app(), wnd); }
		};
	}

	void application::nextevent()
	{
		XEvent event; XNextEvent(dpy, &event);
		Window wnd = event.xany.window;
		widget *w = 0;
		if(wnd == root()) w = this; else for(widget *c : children) if(((native::window*)c)->wnd == wnd) { w = c; break; }
		if(w) switch(event.type)
		{
			case KeyPress:
			{
				uint8_t k = xlib::key(&event.xkey);
				key::state(k) = 1; w->press(k);
				if(!key::lalt && !key::lcontrol && !key::lmenu && !key::ralt && !key::rcontrol && !key::rmenu) if(' ' <= k && k < key::del)
				{
					char c[16];
					Status stat;
					if(int n = Xutf8LookupString(ic, (XKeyPressedEvent*)&event, c, 16, 0, &stat))
					{
						uint32_t uc;
						utf8to32(c, c + n, &uc);
						w->keycode(uc);
					}
				}
				break;
			}

			case KeyRelease:
			{
				if(XEventsQueued(dpy, QueuedAfterReading))
				{
					XEvent nextEvent;
					XPeekEvent(dpy, &nextEvent);
					if(nextEvent.type == KeyPress && nextEvent.xkey.window == event.xkey.window &&
					   nextEvent.xkey.keycode == event.xkey.keycode && nextEvent.xkey.time - event.xkey.time < 20) break;
				}
				uint8_t k = xlib::key(&event.xkey);
				key::state(k) = 0; w->release(k);
				break;
			}

			case ButtonPress:
				m = point(event.xbutton.x_root, event.xbutton.y_root);
				switch(event.xbutton.button)
				{
					case Button1: key::state(key::lbutton) = 1; w->press(key::lbutton); break;
					case Button2: key::state(key::mbutton) = 1; w->press(key::mbutton); break;
					case Button3: key::state(key::rbutton) = 1; w->press(key::rbutton); break;
					case Button4: w->scroll(-1); break;
					case Button5: w->scroll(+1); break;
				}
				break;

			case ButtonRelease:
				switch(event.xbutton.button)
				{
					case Button1: key::state(key::lbutton) = 0; w->release(key::lbutton); break;
					case Button2: key::state(key::mbutton) = 0; w->release(key::mbutton); break;
					case Button3: key::state(key::rbutton) = 0; w->release(key::rbutton); break;
				}
				break;

			case ConfigureNotify:
				w->set(event.xconfigure.x, event.xconfigure.y, event.xconfigure.width, event.xconfigure.height);
				w->resize();
				break;

			case MotionNotify: m = point(event.xmotion.x_root,event.xmotion.y_root); w->pointermove(); break;
			case ClientMessage: if((Atom)event.xclient.data.l[0] == atom["WM_DELETE_WINDOW"]) w->close(); break;
			case DestroyNotify: w->close(); break;
		}
	}
}
<|endoftext|>


<commit_before>

/* Copyright (c) 2011, Peter Barrett
**
** Permission to use, copy, modify, and/or distribute this software for
** any purpose with or without fee is hereby granted, provided that the
** above copyright notice and this permission notice appear in all copies.
**
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
** SOFTWARE.
*/

#include "Platform.h"
#include "USBAPI.h"
#include <avr/wdt.h>

#if defined(USBCON)
#ifdef CDC_ENABLED

#if (RAMEND < 1000)
#define SERIAL_BUFFER_SIZE 16
#else
#define SERIAL_BUFFER_SIZE 64
#endif

struct ring_buffer
{
	unsigned char buffer[SERIAL_BUFFER_SIZE];
	volatile int head;
	volatile int tail;
};

ring_buffer cdc_rx_buffer = { { 0 }, 0, 0};

typedef struct
{
	u32	dwDTERate;
	u8	bCharFormat;
	u8 	bParityType;
	u8 	bDataBits;
	u8	lineState;
} LineInfo;

static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 };

#define WEAK __attribute__ ((weak))

extern const CDCDescriptor _cdcInterface PROGMEM;
const CDCDescriptor _cdcInterface =
{
	D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1),

	//	CDC communication interface
	D_INTERFACE(CDC_ACM_INTERFACE,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0),
	D_CDCCS(CDC_HEADER,0x10,0x01),								// Header (1.10 bcd)
	D_CDCCS(CDC_CALL_MANAGEMENT,1,1),							// Device handles call management (not)
	D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6),				// SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported
	D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE,CDC_DATA_INTERFACE),	// Communication interface is master, data interface is slave 0
	D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM),USB_ENDPOINT_TYPE_INTERRUPT,0x10,0x40),

	//	CDC data interface
	D_INTERFACE(CDC_DATA_INTERFACE,2,CDC_DATA_INTERFACE_CLASS,0,0),
	D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,0x40,0),
	D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,0x40,0)
};

int WEAK CDC_GetInterface(u8* interfaceNum)
{
	interfaceNum[0] += 2;	// uses 2
	return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface));
}

bool WEAK CDC_Setup(Setup& setup)
{
	u8 r = setup.bRequest;
	u8 requestType = setup.bmRequestType;

	if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType)
	{
		if (CDC_GET_LINE_CODING == r)
		{
			USB_SendControl(0,(void*)&_usbLineInfo,7);
			return true;
		}
	}

	if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType)
	{
		if (CDC_SET_LINE_CODING == r)
		{
			USB_RecvControl((void*)&_usbLineInfo,7);
			return true;
		}

		if (CDC_SET_CONTROL_LINE_STATE == r)
		{
			_usbLineInfo.lineState = setup.wValueL;

			// auto-reset into the bootloader is triggered when the port, already
			// open at 1200 bps, is closed.  this is the signal to start the watchdog
			// with a relatively long period so it can finish housekeeping tasks
			// like servicing endpoints before the sketch ends
			if (1200 == _usbLineInfo.dwDTERate) {
				// We check DTR state to determine if host port is open (bit 0 of lineState).
				// Serial1.print(">"); Serial1.println(_usbLineInfo.lineState, HEX);
				if ((_usbLineInfo.lineState & 0x01) == 0) {
					*(uint16_t *)0x0A00 = 0x7777;
					wdt_enable(WDTO_120MS);
				} else {
					// Most OSs do some intermediate steps when configuring ports and DTR can
					// twiggle more than once before stabilizing.
					// To avoid spurious resets we set the watchdog to 250ms and eventually
					// cancel if DTR goes back high.

					wdt_disable();
					wdt_reset();
					*(uint16_t *)0x0A00 = 0x0;
				}
			}
			return true;
		}
	}
	return false;
}

int _serialPeek = -1;
void Serial_::begin(uint16_t baud_count)
{
}

void Serial_::end(void)
{
}

void Serial_::accept(void)
{
	ring_buffer *buffer = &cdc_rx_buffer;
	int c = USB_Recv(CDC_RX);
	int i = (unsigned int)(buffer->head+1) % SERIAL_BUFFER_SIZE;

	// if we should be storing the received character into the location
	// just before the tail (meaning that the head would advance to the
	// current location of the tail), we're about to overflow the buffer
	// and so we don't write the character or advance the head.
	if (i != buffer->tail) {
		buffer->buffer[buffer->head] = c;
		buffer->head = i;
	}
}

int Serial_::available(void)
{
	ring_buffer *buffer = &cdc_rx_buffer;
	return (unsigned int)(SERIAL_BUFFER_SIZE + buffer->head - buffer->tail) % SERIAL_BUFFER_SIZE;
}

int Serial_::peek(void)
{
	ring_buffer *buffer = &cdc_rx_buffer;
	if (buffer->head == buffer->tail) {
		return -1;
	} else {
		return buffer->buffer[buffer->tail];
	}
}

int Serial_::read(void)
{
	ring_buffer *buffer = &cdc_rx_buffer;
	// if the head isn't ahead of the tail, we don't have any characters
	if (buffer->head == buffer->tail) {
		return -1;
	} else {
		unsigned char c = buffer->buffer[buffer->tail];
		buffer->tail = (unsigned int)(buffer->tail + 1) % SERIAL_BUFFER_SIZE;
		return c;
	}
}

void Serial_::flush(void)
{
	USB_Flush(CDC_TX);
}

size_t Serial_::write(uint8_t c)
{
	/* only try to send bytes if the high-level CDC connection itself
	 is open (not just the pipe) - the OS should set lineState when the port
	 is opened and clear lineState when the port is closed.
	 bytes sent before the user opens the connection or after
	 the connection is closed are lost - just like with a UART. */

	// TODO - ZE - check behavior on different OSes and test what happens if an
	// open connection isn't broken cleanly (cable is yanked out, host dies
	// or locks up, or host virtual serial port hangs)
	if (_usbLineInfo.lineState > 0)	{
		int r = USB_Send(CDC_TX,&c,1);
		if (r > 0) {
			return r;
		} else {
			setWriteError();
			return 0;
		}
	}
	setWriteError();
	return 0;
}

Serial_::operator bool() {
	if (_usbLineInfo.lineState > 0)
		return true;
	return false;
}

Serial_ Serial;

#endif
#endif /* if defined(USBCON) */
<commit_msg>Revert "Revert "added a short delay and comment to boolean operator in CDC""<commit_after>

/* Copyright (c) 2011, Peter Barrett
**
** Permission to use, copy, modify, and/or distribute this software for
** any purpose with or without fee is hereby granted, provided that the
** above copyright notice and this permission notice appear in all copies.
**
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
** SOFTWARE.
*/

#include "Platform.h"
#include "USBAPI.h"
#include <avr/wdt.h>

#if defined(USBCON)
#ifdef CDC_ENABLED

#if (RAMEND < 1000)
#define SERIAL_BUFFER_SIZE 16
#else
#define SERIAL_BUFFER_SIZE 64
#endif

struct ring_buffer
{
	unsigned char buffer[SERIAL_BUFFER_SIZE];
	volatile int head;
	volatile int tail;
};

ring_buffer cdc_rx_buffer = { { 0 }, 0, 0};

typedef struct
{
	u32	dwDTERate;
	u8	bCharFormat;
	u8 	bParityType;
	u8 	bDataBits;
	u8	lineState;
} LineInfo;

static volatile LineInfo _usbLineInfo = { 57600, 0x00, 0x00, 0x00, 0x00 };

#define WEAK __attribute__ ((weak))

extern const CDCDescriptor _cdcInterface PROGMEM;
const CDCDescriptor _cdcInterface =
{
	D_IAD(0,2,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,1),

	//	CDC communication interface
	D_INTERFACE(CDC_ACM_INTERFACE,1,CDC_COMMUNICATION_INTERFACE_CLASS,CDC_ABSTRACT_CONTROL_MODEL,0),
	D_CDCCS(CDC_HEADER,0x10,0x01),								// Header (1.10 bcd)
	D_CDCCS(CDC_CALL_MANAGEMENT,1,1),							// Device handles call management (not)
	D_CDCCS4(CDC_ABSTRACT_CONTROL_MANAGEMENT,6),				// SET_LINE_CODING, GET_LINE_CODING, SET_CONTROL_LINE_STATE supported
	D_CDCCS(CDC_UNION,CDC_ACM_INTERFACE,CDC_DATA_INTERFACE),	// Communication interface is master, data interface is slave 0
	D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_ACM),USB_ENDPOINT_TYPE_INTERRUPT,0x10,0x40),

	//	CDC data interface
	D_INTERFACE(CDC_DATA_INTERFACE,2,CDC_DATA_INTERFACE_CLASS,0,0),
	D_ENDPOINT(USB_ENDPOINT_OUT(CDC_ENDPOINT_OUT),USB_ENDPOINT_TYPE_BULK,0x40,0),
	D_ENDPOINT(USB_ENDPOINT_IN (CDC_ENDPOINT_IN ),USB_ENDPOINT_TYPE_BULK,0x40,0)
};

int WEAK CDC_GetInterface(u8* interfaceNum)
{
	interfaceNum[0] += 2;	// uses 2
	return USB_SendControl(TRANSFER_PGM,&_cdcInterface,sizeof(_cdcInterface));
}

bool WEAK CDC_Setup(Setup& setup)
{
	u8 r = setup.bRequest;
	u8 requestType = setup.bmRequestType;

	if (REQUEST_DEVICETOHOST_CLASS_INTERFACE == requestType)
	{
		if (CDC_GET_LINE_CODING == r)
		{
			USB_SendControl(0,(void*)&_usbLineInfo,7);
			return true;
		}
	}

	if (REQUEST_HOSTTODEVICE_CLASS_INTERFACE == requestType)
	{
		if (CDC_SET_LINE_CODING == r)
		{
			USB_RecvControl((void*)&_usbLineInfo,7);
			return true;
		}

		if (CDC_SET_CONTROL_LINE_STATE == r)
		{
			_usbLineInfo.lineState = setup.wValueL;

			// auto-reset into the bootloader is triggered when the port, already
			// open at 1200 bps, is closed.  this is the signal to start the watchdog
			// with a relatively long period so it can finish housekeeping tasks
			// like servicing endpoints before the sketch ends
			if (1200 == _usbLineInfo.dwDTERate) {
				// We check DTR state to determine if host port is open (bit 0 of lineState).
				// Serial1.print(">"); Serial1.println(_usbLineInfo.lineState, HEX);
				if ((_usbLineInfo.lineState & 0x01) == 0) {
					*(uint16_t *)0x0A00 = 0x7777;
					wdt_enable(WDTO_120MS);
				} else {
					// Most OSs do some intermediate steps when configuring ports and DTR can
					// twiggle more than once before stabilizing.
					// To avoid spurious resets we set the watchdog to 250ms and eventually
					// cancel if DTR goes back high.

					wdt_disable();
					wdt_reset();
					*(uint16_t *)0x0A00 = 0x0;
				}
			}
			return true;
		}
	}
	return false;
}

int _serialPeek = -1;
void Serial_::begin(uint16_t baud_count)
{
}

void Serial_::end(void)
{
}

void Serial_::accept(void)
{
	ring_buffer *buffer = &cdc_rx_buffer;
	int c = USB_Recv(CDC_RX);
	int i = (unsigned int)(buffer->head+1) % SERIAL_BUFFER_SIZE;

	// if we should be storing the received character into the location
	// just before the tail (meaning that the head would advance to the
	// current location of the tail), we're about to overflow the buffer
	// and so we don't write the character or advance the head.
	if (i != buffer->tail) {
		buffer->buffer[buffer->head] = c;
		buffer->head = i;
	}
}

int Serial_::available(void)
{
	ring_buffer *buffer = &cdc_rx_buffer;
	return (unsigned int)(SERIAL_BUFFER_SIZE + buffer->head - buffer->tail) % SERIAL_BUFFER_SIZE;
}

int Serial_::peek(void)
{
	ring_buffer *buffer = &cdc_rx_buffer;
	if (buffer->head == buffer->tail) {
		return -1;
	} else {
		return buffer->buffer[buffer->tail];
	}
}

int Serial_::read(void)
{
	ring_buffer *buffer = &cdc_rx_buffer;
	// if the head isn't ahead of the tail, we don't have any characters
	if (buffer->head == buffer->tail) {
		return -1;
	} else {
		unsigned char c = buffer->buffer[buffer->tail];
		buffer->tail = (unsigned int)(buffer->tail + 1) % SERIAL_BUFFER_SIZE;
		return c;
	}
}

void Serial_::flush(void)
{
	USB_Flush(CDC_TX);
}

size_t Serial_::write(uint8_t c)
{
	/* only try to send bytes if the high-level CDC connection itself
	 is open (not just the pipe) - the OS should set lineState when the port
	 is opened and clear lineState when the port is closed.
	 bytes sent before the user opens the connection or after
	 the connection is closed are lost - just like with a UART. */

	// TODO - ZE - check behavior on different OSes and test what happens if an
	// open connection isn't broken cleanly (cable is yanked out, host dies
	// or locks up, or host virtual serial port hangs)
	if (_usbLineInfo.lineState > 0)	{
		int r = USB_Send(CDC_TX,&c,1);
		if (r > 0) {
			return r;
		} else {
			setWriteError();
			return 0;
		}
	}
	setWriteError();
	return 0;
}

// This operator is a convenient way for a sketch to check whether the
// port has actually been configured and opened by the host (as opposed
// to just being connected to the host).  It can be used, for example, in
// setup() before printing to ensure that an application on the host is
// actually ready to receive and display the data.
// We add a short delay before returning to fix a bug observed by Federico
// where the port is configured (lineState != 0) but not quite opened.
Serial_::operator bool() {
	bool result = false;
	if (_usbLineInfo.lineState > 0)
		result = true;
	delay(10);
	return result;
}

Serial_ Serial;

#endif
#endif /* if defined(USBCON) */
<|endoftext|>