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

VK_LAYER_EXPORT VkResult VKAPI vkLayerExtension1(VkDevice device)
{
    printf("In vkLayerExtension1() call w/ device: %p\n", (void*)device);
    printf("vkLayerExtension1 returning SUCCESS\n");
    return VK_SUCCESS;
}

#define BASIC_LAYER_EXT_ARRAY_SIZE 2

static const VkExtensionProperties basicExts[BASIC_LAYER_EXT_ARRAY_SIZE] = {
    {
        VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES,
        "Basic",
        0x10,
        "Sample layer: Basic ",
//        0,
//        NULL,
    },
    {
        VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES,
        "vkLayerExtension1",
        0x10,
        "Sample layer: Basic",
//        0,
//        NULL,
    }
};

VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties(
                                               uint32_t extensionIndex,
                                               VkExtensionProperties*    pData)
{
    /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
    uint32_t *count;

    if (extensionIndex >= BASIC_LAYER_EXT_ARRAY_SIZE)
        return VK_ERROR_INVALID_VALUE;
    memcpy((VkExtensionProperties *) pData, &basicExts[extensionIndex], sizeof(VkExtensionProperties));

    return VK_SUCCESS;
}

VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionCount(uint32_t* pCount)
{
    *pCount = BASIC_LAYER_EXT_ARRAY_SIZE;
    return VK_SUCCESS;
}

VK_LAYER_EXPORT VkResult VKAPI vkEnumeratePhysicalDevices(
                                            VkInstance instance,
                                            uint32_t* pPhysicalDeviceCount,
                                            VkPhysicalDevice* pPhysicalDevices)
{
    printf("At start of wrapped vkEnumeratePhysicalDevices() call w/ inst: %p\n", (void*)instance);
    VkResult result = instance_dispatch_table(instance)->EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
    printf("Completed wrapped vkEnumeratePhysicalDevices() call w/ count %u\n", *pPhysicalDeviceCount);
    return result;
}

VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
{
    printf("At start of wrapped vkCreateDevice() call w/ gpu: %p\n", (void*)gpu);
    VkResult result = device_dispatch_table(*pDevice)->CreateDevice(gpu, pCreateInfo, pDevice);
    printf("Completed wrapped vkCreateDevice() call w/ pDevice, Device %p: %p\n", (void*)pDevice, (void *) *pDevice);
    return result;
}

/* hook DestroyDevice to remove tableMap entry */
VK_LAYER_EXPORT VkResult VKAPI vkDestroyDevice(VkDevice device)
{
    dispatch_key key = get_dispatch_key(device);
    VkResult res = device_dispatch_table(device)->DestroyDevice(device);
    destroy_device_dispatch_table(key);
    return res;
}

/* hook DestroyInstance to remove tableInstanceMap entry */
VK_LAYER_EXPORT VkResult VKAPI vkDestroyInstance(VkInstance instance)
{
    dispatch_key key = get_dispatch_key(instance);
    VkResult res = instance_dispatch_table(instance)->DestroyInstance(instance);
    destroy_instance_dispatch_table(key);
    return res;
}

VK_LAYER_EXPORT VkResult VKAPI vkGetPhysicalDeviceFormatInfo(VkPhysicalDevice gpu, VkFormat format, VkFormatProperties *pFormatInfo)
{
    printf("At start of wrapped vkGetPhysicalDeviceFormatInfo() call w/ gpu: %p\n", (void*)gpu);
    VkResult result = instance_dispatch_table(gpu)->GetPhysicalDeviceFormatInfo(gpu, format, pFormatInfo);
    printf("Completed wrapped vkGetPhysicalDeviceFormatInfo() call w/ gpu: %p\n", (void*)gpu);
    return result;
}

VK_LAYER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char* pName)
{
    if (device == NULL)
        return NULL;

    /* loader uses this to force layer initialization; device object is wrapped */
    if (!strcmp("vkGetDeviceProcAddr", pName)) {
        initDeviceTable((const VkBaseLayerObject *) device);
        return (void *) vkGetDeviceProcAddr;
    }

    if (!strcmp("vkCreateDevice", pName))
        return (void *) vkCreateDevice;
    if (!strcmp("vkDestroyDevice", pName))
        return (void *) vkDestroyDevice;
    if (!strcmp("vkLayerExtension1", pName))
        return (void *) vkLayerExtension1;
    else
    {
        if (device_dispatch_table(device)->GetDeviceProcAddr == NULL)
            return NULL;
        return device_dispatch_table(device)->GetDeviceProcAddr(device, pName);
    }
}

VK_LAYER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char* pName)
{
    if (instance == NULL)
        return NULL;

    /* loader uses this to force layer initialization; instance object is wrapped */
    if (!strcmp("vkGetInstanceProcAddr", pName)) {
        initInstanceTable((const VkBaseLayerObject *) instance);
        return (void *) vkGetInstanceProcAddr;
    }
    if (!strcmp("vkGetPhysicalDeviceFormatInfo", pName))
        return (void *) vkGetPhysicalDeviceFormatInfo;

    if (!strcmp("vkDestroyInstance", pName))
        return (void *) vkDestroyInstance;
    if (!strcmp("vkEnumeratePhysicalDevices", pName))
        return (void*) vkEnumeratePhysicalDevices;
    if (!strcmp("vkGetGlobalExtensionCount", pName))
        return (void*) vkGetGlobalExtensionCount;
    if (!strcmp("vkGetGlobalExtensionProperties", pName))
        return (void*) vkGetGlobalExtensionProperties;
    else
    {
        if (instance_dispatch_table(instance)->GetInstanceProcAddr == NULL)
            return NULL;
        return instance_dispatch_table(instance)->GetInstanceProcAddr(instance, pName);
    }

}
<commit_msg>loader: Remove CreateDevice from loader's instance<commit_after>/*
 * Vulkan
 *
 * Copyright (C) 2014 LunarG, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "loader_platform.h"
#include "vk_dispatch_table_helper.h"
#include "vkLayer.h"
#include "layers_table.h"
// The following is #included again to catch certain OS-specific functions
// being used:
#include "loader_platform.h"

VK_LAYER_EXPORT VkResult VKAPI vkLayerExtension1(VkDevice device)
{
    printf("In vkLayerExtension1() call w/ device: %p\n", (void*)device);
    printf("vkLayerExtension1 returning SUCCESS\n");
    return VK_SUCCESS;
}

#define BASIC_LAYER_EXT_ARRAY_SIZE 2

static const VkExtensionProperties basicExts[BASIC_LAYER_EXT_ARRAY_SIZE] = {
    {
        VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES,
        "Basic",
        0x10,
        "Sample layer: Basic ",
//        0,
//        NULL,
    },
    {
        VK_STRUCTURE_TYPE_EXTENSION_PROPERTIES,
        "vkLayerExtension1",
        0x10,
        "Sample layer: Basic",
//        0,
//        NULL,
    }
};

VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionProperties(
                                               uint32_t extensionIndex,
                                               VkExtensionProperties*    pData)
{
    /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
    uint32_t *count;

    if (extensionIndex >= BASIC_LAYER_EXT_ARRAY_SIZE)
        return VK_ERROR_INVALID_VALUE;
    memcpy((VkExtensionProperties *) pData, &basicExts[extensionIndex], sizeof(VkExtensionProperties));

    return VK_SUCCESS;
}

VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionCount(uint32_t* pCount)
{
    *pCount = BASIC_LAYER_EXT_ARRAY_SIZE;
    return VK_SUCCESS;
}

VK_LAYER_EXPORT VkResult VKAPI vkEnumeratePhysicalDevices(
                                            VkInstance instance,
                                            uint32_t* pPhysicalDeviceCount,
                                            VkPhysicalDevice* pPhysicalDevices)
{
    printf("At start of wrapped vkEnumeratePhysicalDevices() call w/ inst: %p\n", (void*)instance);
    VkResult result = instance_dispatch_table(instance)->EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
    printf("Completed wrapped vkEnumeratePhysicalDevices() call w/ count %u\n", *pPhysicalDeviceCount);
    return result;
}

VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalDevice gpu, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
{
    printf("At start of wrapped vkCreateDevice() call w/ gpu: %p\n", (void*)gpu);
    VkResult result = device_dispatch_table(*pDevice)->CreateDevice(gpu, pCreateInfo, pDevice);
    printf("Completed wrapped vkCreateDevice() call w/ pDevice, Device %p: %p\n", (void*)pDevice, (void *) *pDevice);
    return result;
}

/* hook DestroyDevice to remove tableMap entry */
VK_LAYER_EXPORT VkResult VKAPI vkDestroyDevice(VkDevice device)
{
    dispatch_key key = get_dispatch_key(device);
    VkResult res = device_dispatch_table(device)->DestroyDevice(device);
    destroy_device_dispatch_table(key);
    return res;
}

/* hook DestroyInstance to remove tableInstanceMap entry */
VK_LAYER_EXPORT VkResult VKAPI vkDestroyInstance(VkInstance instance)
{
    dispatch_key key = get_dispatch_key(instance);
    VkResult res = instance_dispatch_table(instance)->DestroyInstance(instance);
    destroy_instance_dispatch_table(key);
    return res;
}

VK_LAYER_EXPORT VkResult VKAPI vkGetPhysicalDeviceFormatInfo(VkPhysicalDevice gpu, VkFormat format, VkFormatProperties *pFormatInfo)
{
    printf("At start of wrapped vkGetPhysicalDeviceFormatInfo() call w/ gpu: %p\n", (void*)gpu);
    VkResult result = instance_dispatch_table(gpu)->GetPhysicalDeviceFormatInfo(gpu, format, pFormatInfo);
    printf("Completed wrapped vkGetPhysicalDeviceFormatInfo() call w/ gpu: %p\n", (void*)gpu);
    return result;
}

VK_LAYER_EXPORT void * VKAPI vkGetDeviceProcAddr(VkDevice device, const char* pName)
{
    if (device == NULL)
        return NULL;

    /* loader uses this to force layer initialization; device object is wrapped */
    if (!strcmp("vkGetDeviceProcAddr", pName)) {
        initDeviceTable((const VkBaseLayerObject *) device);
        return (void *) vkGetDeviceProcAddr;
    }

    if (!strcmp("vkCreateDevice", pName))
        return (void *) vkCreateDevice;
    if (!strcmp("vkDestroyDevice", pName))
        return (void *) vkDestroyDevice;
    if (!strcmp("vkLayerExtension1", pName))
        return (void *) vkLayerExtension1;
    else
    {
        if (device_dispatch_table(device)->GetDeviceProcAddr == NULL)
            return NULL;
        return device_dispatch_table(device)->GetDeviceProcAddr(device, pName);
    }
}

VK_LAYER_EXPORT void * VKAPI vkGetInstanceProcAddr(VkInstance instance, const char* pName)
{
    if (instance == NULL)
        return NULL;

    /* loader uses this to force layer initialization; instance object is wrapped */
    if (!strcmp("vkGetInstanceProcAddr", pName)) {
        initInstanceTable((const VkBaseLayerObject *) instance);
        return (void *) vkGetInstanceProcAddr;
    }
    if (!strcmp("vkGetPhysicalDeviceFormatInfo", pName))
        return (void *) vkGetPhysicalDeviceFormatInfo;

    if (!strcmp("vkDestroyInstance", pName))
        return (void *) vkDestroyInstance;
    if (!strcmp("vkCreateDevice", pName))
        return (void *) vkCreateDevice;
    if (!strcmp("vkEnumeratePhysicalDevices", pName))
        return (void*) vkEnumeratePhysicalDevices;
    if (!strcmp("vkGetGlobalExtensionCount", pName))
        return (void*) vkGetGlobalExtensionCount;
    if (!strcmp("vkGetGlobalExtensionProperties", pName))
        return (void*) vkGetGlobalExtensionProperties;
    else
    {
        if (instance_dispatch_table(instance)->GetInstanceProcAddr == NULL)
            return NULL;
        return instance_dispatch_table(instance)->GetInstanceProcAddr(instance, pName);
    }

}
<|endoftext|>


<commit_before>/*
 * SessionContentUrls.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <session/SessionContentUrls.hpp>

#include <boost/algorithm/string/predicate.hpp>

#include <core/Error.hpp>
#include <core/Log.hpp>
#include <core/FilePath.hpp>
#include <core/FileSerializer.hpp>
#include <core/Exec.hpp>

#include <core/system/System.hpp>

#include <core/http/Util.hpp>
#include <core/http/Response.hpp>
#include <core/http/Request.hpp>

#include <core/json/JsonRpc.hpp>

extern "C" const char *locale2charset(const char *);

#include <session/SessionModuleContext.hpp>

using namespace core ;

namespace session {
namespace content_urls {

namespace {

FilePath contentUrlPath()
{
   FilePath filePath = module_context::userScratchPath().complete("content_urls");
   Error error = filePath.ensureDirectory();
   if (error)
      LOG_ERROR(error);
   return filePath;
}

std::string buildContentUrl(const std::string& title,
                            const std::string& contentFile)
{
   // calculate and return content url
   std::string url = std::string("content") +
                     "?title=" + http::util::urlEncode(title, true) +
                     "&file=" + http::util::urlEncode(contentFile, true);
   return url;
}

Error contentFileInfo(const std::string& contentUrl,
                      std::string* pTitle,
                      core::FilePath* pFilePath)
{
   // extract and parse query string
   std::string queryString;
   std::string::size_type pos = contentUrl.find('?');
   if (pos != std::string::npos)
   {
      if ((pos+1) < contentUrl.length())
         queryString = contentUrl.substr(pos+1);
      else
         return systemError(ENOENT, ERROR_LOCATION);
   }
   else
   {
      return systemError(ENOENT, ERROR_LOCATION);
   }
   http::Fields fields;
   http::util::parseQueryString(queryString, &fields);

   // get title parameter
   *pTitle = http::util::fieldValue<std::string>(fields, "title", "(Untitled)");

   // get file parameter
   std::string contentFile = http::util::fieldValue(fields, "file");
   if (contentFile.empty())
       return systemError(ENOENT, ERROR_LOCATION);
   *pFilePath = contentUrlPath().complete(contentFile);

   // return success
   return Success();
}

} // anonymous namespace

std::string provision(const std::string& title, const FilePath& filePath)
{
   // calculate content path
   std::string contentFile = core::system::generateUuid(false) +
                             filePath.extension();
   FilePath contentPath = contentUrlPath().complete(contentFile);

   // copy the file
   Error error = filePath.copy(contentPath);
   if (error)
      LOG_ERROR(error);

   // calculate and return content url
   return buildContentUrl(title, contentFile);
}

std::string provision(const std::string& title,
                      const std::string& content,
                      const std::string& extension)
{
   // calculate content path
   std::string contentFile = core::system::generateUuid(false) + extension;
   FilePath contentPath = contentUrlPath().complete(contentFile);

   // write the file
   Error error = writeStringToFile(contentPath, content);
   if (error)
      LOG_ERROR(error);

   // calculate and return content url
   return buildContentUrl(title, contentFile);
}

void handleContentRequest(const http::Request& request, http::Response* pResponse)
{
   // get content file info
   std::string title;
   FilePath contentFilePath;
   Error error = contentFileInfo(request.uri(), &title, &contentFilePath);
   if (error)
   {
      pResponse->setError(error);
      return;
   }

   // set private cache forever headers
   pResponse->setPrivateCacheForeverHeaders();

   // set file
   pResponse->setFile(contentFilePath, request);

   bool isUtf8 = true;
   if (boost::algorithm::starts_with(contentFilePath.mimeContentType(), "text/"))
   {
      // If the content looks like valid UTF-8, assume it is. Otherwise, assume
      // it's the system encoding.
      std::string contents;
      error = core::readStringFromFile(contentFilePath, &contents);
      if (!error)
      {
         for (std::string::iterator pos = contents.begin(); pos != contents.end(); )
         {
            error = string_utils::utf8Advance(pos, 1, contents.end(), &pos);
            if (error)
            {
               isUtf8 = false;
               break;
            }
         }
      }
   }

   // reset content-type with charset
   pResponse->setContentType(contentFilePath.mimeContentType() +
                             std::string("; charset=") +
                             (isUtf8 ? "UTF-8" : ::locale2charset(NULL)));

   // set title header
   pResponse->setHeader("Title", title);
}

Error removeContentUrl(const json::JsonRpcRequest& request,
                       json::JsonRpcResponse* pResponse)
{
   // get content url
   std::string contentUrl;
   Error error = json::readParams(request.params, &contentUrl);
   if (error)
      return error;

   // get content file info
   std::string title;
   FilePath contentFilePath;
   error = contentFileInfo(contentUrl, &title, &contentFilePath);
   if (error)
      return error;

   // remove it
   return contentFilePath.removeIfExists();
}

Error initialize()
{
   using boost::bind;
   using namespace session::module_context;
   ExecBlock initBlock ;
   initBlock.addFunctions()
      (bind(registerUriHandler, "/content", handleContentRequest))
      (bind(registerRpcMethod, "remove_content_url", removeContentUrl));
   return initBlock.execute();
}

} // namespace content_urls
} // namesapce session

<commit_msg>fix for very small content payloads (<= 512) not rendering in file.show<commit_after>/*
 * SessionContentUrls.cpp
 *
 * Copyright (C) 2009-12 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <session/SessionContentUrls.hpp>

#include <boost/algorithm/string/predicate.hpp>

#include <core/Error.hpp>
#include <core/Log.hpp>
#include <core/FilePath.hpp>
#include <core/FileSerializer.hpp>
#include <core/Exec.hpp>

#include <core/system/System.hpp>

#include <core/http/Util.hpp>
#include <core/http/Response.hpp>
#include <core/http/Request.hpp>

#include <core/json/JsonRpc.hpp>

extern "C" const char *locale2charset(const char *);

#include <session/SessionModuleContext.hpp>

using namespace core ;

namespace session {
namespace content_urls {

namespace {

FilePath contentUrlPath()
{
   FilePath filePath = module_context::userScratchPath().complete("content_urls");
   Error error = filePath.ensureDirectory();
   if (error)
      LOG_ERROR(error);
   return filePath;
}

std::string buildContentUrl(const std::string& title,
                            const std::string& contentFile)
{
   // calculate and return content url
   std::string url = std::string("content") +
                     "?title=" + http::util::urlEncode(title, true) +
                     "&file=" + http::util::urlEncode(contentFile, true);
   return url;
}

Error contentFileInfo(const std::string& contentUrl,
                      std::string* pTitle,
                      core::FilePath* pFilePath)
{
   // extract and parse query string
   std::string queryString;
   std::string::size_type pos = contentUrl.find('?');
   if (pos != std::string::npos)
   {
      if ((pos+1) < contentUrl.length())
         queryString = contentUrl.substr(pos+1);
      else
         return systemError(ENOENT, ERROR_LOCATION);
   }
   else
   {
      return systemError(ENOENT, ERROR_LOCATION);
   }
   http::Fields fields;
   http::util::parseQueryString(queryString, &fields);

   // get title parameter
   *pTitle = http::util::fieldValue<std::string>(fields, "title", "(Untitled)");

   // get file parameter
   std::string contentFile = http::util::fieldValue(fields, "file");
   if (contentFile.empty())
       return systemError(ENOENT, ERROR_LOCATION);
   *pFilePath = contentUrlPath().complete(contentFile);

   // return success
   return Success();
}

} // anonymous namespace

std::string provision(const std::string& title, const FilePath& filePath)
{
   // calculate content path
   std::string contentFile = core::system::generateUuid(false) +
                             filePath.extension();
   FilePath contentPath = contentUrlPath().complete(contentFile);

   // copy the file
   Error error = filePath.copy(contentPath);
   if (error)
      LOG_ERROR(error);

   // calculate and return content url
   return buildContentUrl(title, contentFile);
}

std::string provision(const std::string& title,
                      const std::string& content,
                      const std::string& extension)
{
   // calculate content path
   std::string contentFile = core::system::generateUuid(false) + extension;
   FilePath contentPath = contentUrlPath().complete(contentFile);

   // write the file
   Error error = writeStringToFile(contentPath, content);
   if (error)
      LOG_ERROR(error);

   // calculate and return content url
   return buildContentUrl(title, contentFile);
}

void handleContentRequest(const http::Request& request, http::Response* pResponse)
{
   // get content file info
   std::string title;
   FilePath contentFilePath;
   Error error = contentFileInfo(request.uri(), &title, &contentFilePath);
   if (error)
   {
      pResponse->setError(error);
      return;
   }

   // set private cache forever headers
   pResponse->setPrivateCacheForeverHeaders();

   // read file
   std::string contents;
   error = core::readStringFromFile(contentFilePath, &contents);
   if (error)
   {
      pResponse->setError(error);
      return;
   }

   // Ensure we are over the Qt iframe (?) minimum of 513 bytes for our custom
   // network reply handler to work correctly (for this case and apparently
   // this case only if bytesAvailable is less than 512 then Qt never calls
   // readData after the call to bytesAvailable). This is the behavior we used
   // to see in Qt 4.X and for that case we had a special workaround (see
   // https://github.com/rstudio/rstudio/blob/master/src/cpp/desktop/DesktopNetworkReply.cpp#L186-L195)
   //
   // Note that we can't just restore the workaround because the IDE didn't
   // even come up with the workaround in place! (due to RPC calls that
   // were less than 512 bytes). I'm not sure why this case and this case
   // only presents problems -- it may be because it's a request in an
   // iframe? (I tried to find other iframes where we might have less than
   // 512 bytes -- e.g. Plots, Help but couldn't even construct a case
   // where the payload was that small)
   if (contents.length() <= 512)
   {
      std::string fill(512 - contents.length() + 1, ' ');
      contents.append(fill);
   }

   // set contents
   pResponse->setContentType(contentFilePath.mimeContentType());
   pResponse->setBody(contents);

   bool isUtf8 = true;
   if (boost::algorithm::starts_with(contentFilePath.mimeContentType(), "text/"))
   {
      // If the content looks like valid UTF-8, assume it is. Otherwise, assume
      // it's the system encoding.
      std::string contents;
      error = core::readStringFromFile(contentFilePath, &contents);
      if (!error)
      {
         for (std::string::iterator pos = contents.begin(); pos != contents.end(); )
         {
            error = string_utils::utf8Advance(pos, 1, contents.end(), &pos);
            if (error)
            {
               isUtf8 = false;
               break;
            }
         }
      }
   }

   // reset content-type with charset
   pResponse->setContentType(contentFilePath.mimeContentType() +
                             std::string("; charset=") +
                             (isUtf8 ? "UTF-8" : ::locale2charset(NULL)));

   // set title header
   pResponse->setHeader("Title", title);
}

Error removeContentUrl(const json::JsonRpcRequest& request,
                       json::JsonRpcResponse* pResponse)
{
   // get content url
   std::string contentUrl;
   Error error = json::readParams(request.params, &contentUrl);
   if (error)
      return error;

   // get content file info
   std::string title;
   FilePath contentFilePath;
   error = contentFileInfo(contentUrl, &title, &contentFilePath);
   if (error)
      return error;

   // remove it
   return contentFilePath.removeIfExists();
}

Error initialize()
{
   using boost::bind;
   using namespace session::module_context;
   ExecBlock initBlock ;
   initBlock.addFunctions()
      (bind(registerUriHandler, "/content", handleContentRequest))
      (bind(registerRpcMethod, "remove_content_url", removeContentUrl));
   return initBlock.execute();
}

} // namespace content_urls
} // namesapce session

<|endoftext|>


<commit_before>/**
 * pty.js
 * Copyright (c) 2012, Christopher Jeffrey (MIT License)
 *
 * pty.cc:
 *   This file is responsible for starting processes
 *   with pseudo-terminal file descriptors.
 *
 * See:
 *   man pty
 *   man tty_ioctl
 *   man termios
 *   man forkpty
 */

#include <v8.h>
#include <node.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>

/* forkpty */
/* http://www.gnu.org/software/gnulib/manual/html_node/forkpty.html */
#if defined(__GLIBC__) || defined(__CYGWIN__)
#include <pty.h>
#elif defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
#include <util.h>
#elif defined(__FreeBSD__)
#include <libutil.h>
#elif defined(__sun)
#include <stropts.h> /* for I_PUSH */
#else
#include <pty.h>
#endif

#include <termios.h> /* tcgetattr, tty_ioctl */

/* environ for execvpe */
/* node/src/node_child_process.cc */
#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
#else
extern char **environ;
#endif

/* for pty_getproc */
#if defined(__linux__)
#include <stdio.h>
#include <stdint.h>
#elif defined(__APPLE__)
#include <sys/sysctl.h>
#include <libproc.h>
#endif

using namespace std;
using namespace node;
using namespace v8;

static Handle<Value>
PtyFork(const Arguments&);

static Handle<Value>
PtyOpen(const Arguments&);

static Handle<Value>
PtyResize(const Arguments&);

static Handle<Value>
PtyGetProc(const Arguments&);

static int
pty_execvpe(const char *, char **, char **);

static int
pty_nonblock(int);

static char *
pty_getproc(int, char *);

static int
pty_openpty(int *, int *, char *,
            const struct termios *,
            const struct winsize *);

static pid_t
pty_forkpty(int *, char *,
            const struct termios *,
            const struct winsize *);

extern "C" void
init(Handle<Object>);

/**
 * PtyFork
 * pty.fork(file, args, env, cwd, cols, rows)
 */

static Handle<Value>
PtyFork(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 6
      || !args[0]->IsString()
      || !args[1]->IsArray()
      || !args[2]->IsArray()
      || !args[3]->IsString()
      || !args[4]->IsNumber()
      || !args[5]->IsNumber()) {
    return ThrowException(Exception::Error(
      String::New("Usage: pty.fork(file, args, env, cwd, cols, rows)")));
  }

  // node/src/node_child_process.cc

  // file
  String::Utf8Value file(args[0]->ToString());

  // args
  int i = 0;
  Local<Array> argv_ = Local<Array>::Cast(args[1]);
  int argc = argv_->Length();
  int argl = argc + 1 + 1;
  char **argv = new char*[argl];
  argv[0] = strdup(*file);
  argv[argl-1] = NULL;
  for (; i < argc; i++) {
    String::Utf8Value arg(argv_->Get(Integer::New(i))->ToString());
    argv[i+1] = strdup(*arg);
  }

  // env
  i = 0;
  Local<Array> env_ = Local<Array>::Cast(args[2]);
  int envc = env_->Length();
  char **env = new char*[envc+1];
  env[envc] = NULL;
  for (; i < envc; i++) {
    String::Utf8Value pair(env_->Get(Integer::New(i))->ToString());
    env[i] = strdup(*pair);
  }

  // cwd
  String::Utf8Value cwd_(args[3]->ToString());
  char *cwd = strdup(*cwd_);

  // size
  struct winsize winp;
  winp.ws_col = args[4]->IntegerValue();
  winp.ws_row = args[5]->IntegerValue();
  winp.ws_xpixel = 0;
  winp.ws_ypixel = 0;

  // fork the pty
  int master = -1;
  char name[40];
  pid_t pid = pty_forkpty(&master, name, NULL, &winp);

  if (pid) {
    for (i = 0; i < argl; i++) free(argv[i]);
    delete[] argv;
    for (i = 0; i < envc; i++) free(env[i]);
    delete[] env;
    free(cwd);
  }

  switch (pid) {
    case -1:
      return ThrowException(Exception::Error(
        String::New("forkpty(3) failed.")));
    case 0:
      if (strlen(cwd)) chdir(cwd);

      pty_execvpe(argv[0], argv, env);

      perror("execvp(3) failed.");
      _exit(1);
    default:
      if (pty_nonblock(master) == -1) {
        return ThrowException(Exception::Error(
          String::New("Could not set master fd to nonblocking.")));
      }

      Local<Object> obj = Object::New();
      obj->Set(String::New("fd"), Number::New(master));
      obj->Set(String::New("pid"), Number::New(pid));
      obj->Set(String::New("pty"), String::New(name));

      return scope.Close(obj);
  }

  return Undefined();
}

/**
 * PtyOpen
 * pty.open(cols, rows)
 */

static Handle<Value>
PtyOpen(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 2
      || !args[0]->IsNumber()
      || !args[1]->IsNumber()) {
    return ThrowException(Exception::Error(
      String::New("Usage: pty.open(cols, rows)")));
  }

  // size
  struct winsize winp;
  winp.ws_col = args[0]->IntegerValue();
  winp.ws_row = args[1]->IntegerValue();
  winp.ws_xpixel = 0;
  winp.ws_ypixel = 0;

  // pty
  int master, slave;
  char name[40];
  int ret = pty_openpty(&master, &slave, name, NULL, &winp);

  if (ret == -1) {
    return ThrowException(Exception::Error(
      String::New("openpty(3) failed.")));
  }

  if (pty_nonblock(master) == -1) {
    return ThrowException(Exception::Error(
      String::New("Could not set master fd to nonblocking.")));
  }

  if (pty_nonblock(slave) == -1) {
    return ThrowException(Exception::Error(
      String::New("Could not set slave fd to nonblocking.")));
  }

  Local<Object> obj = Object::New();
  obj->Set(String::New("master"), Number::New(master));
  obj->Set(String::New("slave"), Number::New(slave));
  obj->Set(String::New("pty"), String::New(name));

  return scope.Close(obj);
}

/**
 * Resize Functionality
 * pty.resize(fd, cols, rows)
 */

static Handle<Value>
PtyResize(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 3
      || !args[0]->IsNumber()
      || !args[1]->IsNumber()
      || !args[2]->IsNumber()) {
    return ThrowException(Exception::Error(
      String::New("Usage: pty.resize(fd, cols, rows)")));
  }

  int fd = args[0]->IntegerValue();

  struct winsize winp;
  winp.ws_col = args[1]->IntegerValue();
  winp.ws_row = args[2]->IntegerValue();
  winp.ws_xpixel = 0;
  winp.ws_ypixel = 0;

  if (ioctl(fd, TIOCSWINSZ, &winp) == -1) {
    return ThrowException(Exception::Error(
      String::New("ioctl(2) failed.")));
  }

  return Undefined();
}

/**
 * PtyGetProc
 * Foreground Process Name
 * pty.process(fd, tty)
 */

static Handle<Value>
PtyGetProc(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 2
      || !args[0]->IsNumber()
      || !args[1]->IsString()) {
    return ThrowException(Exception::Error(
      String::New("Usage: pty.process(fd, tty)")));
  }

  int fd = args[0]->IntegerValue();

  String::Utf8Value tty_(args[1]->ToString());
  char *tty = strdup(*tty_);
  char *name = pty_getproc(fd, tty);
  free(tty);

  if (name == NULL) {
    return Undefined();
  }

  Local<String> name_ = String::New(name);
  free(name);
  return scope.Close(name_);
}

/**
 * execvpe
 */

// execvpe(3) is not portable.
// http://www.gnu.org/software/gnulib/manual/html_node/execvpe.html
static int
pty_execvpe(const char *file, char **argv, char **envp) {
  char **old = environ;
  environ = envp;
  int ret = execvp(file, argv);
  environ = old;
  return ret;
}

/**
 * Nonblocking FD
 */

static int
pty_nonblock(int fd) {
  int flags = fcntl(fd, F_GETFL, 0);
  if (flags == -1) return -1;
  return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

/**
 * pty_getproc
 * Taken from tmux.
 */

// Taken from: tmux (http://tmux.sourceforge.net/)
// Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
// Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org>
// Copyright (c) 2009 Todd Carson <toc@daybefore.net>
//
// Permission to use, copy, modify, and 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 MIND, 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.

#if defined(__linux__)

static char *
pty_getproc(int fd, char *tty) {
  FILE *f;
  char *path, *buf;
  size_t len;
  int ch;
  pid_t pgrp;
  int r;

  if ((pgrp = tcgetpgrp(fd)) == -1) {
    return NULL;
  }

  r = asprintf(&path, "/proc/%lld/cmdline", (long long)pgrp);
  if (r == -1 || path == NULL) return NULL;

  if ((f = fopen(path, "r")) == NULL) {
    free(path);
    return NULL;
  }

  free(path);

  len = 0;
  buf = NULL;
  while ((ch = fgetc(f)) != EOF) {
    if (ch == '\0') break;
    buf = (char *)realloc(buf, len + 2);
    if (buf == NULL) return NULL;
    buf[len++] = ch;
  }

  if (buf != NULL) {
    buf[len] = '\0';
  }

  fclose(f);
  return buf;
}

#elif defined(__APPLE__)

static char *
pty_getproc(int fd, char *tty) {
  int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 };
  size_t size;
  struct kinfo_proc kp;

  if ((mib[3] = tcgetpgrp(fd)) == -1) {
    return NULL;
  }

  size = sizeof kp;
  if (sysctl(mib, 4, &kp, &size, NULL, 0) == -1) {
    return NULL;
  }

  if (*kp.kp_proc.p_comm == '\0') {
    return NULL;
  }

  return strdup(kp.kp_proc.p_comm);
}

#else

static char *
pty_getproc(int fd, char *tty) {
  return NULL;
}

#endif

/**
 * openpty(3) / forkpty(3)
 */

static int
pty_openpty(int *amaster, int *aslave, char *name,
            const struct termios *termp,
            const struct winsize *winp) {
#if defined(__sun)
  char *slave_name;
  int slave;
  int master = open("/dev/ptmx", O_RDWR | O_NOCTTY);
  if (master == -1) return -1;
  if (amaster) *amaster = master;

  if (grantpt(master) == -1) goto err;
  if (unlockpt(master) == -1) goto err;

  slave_name = ptsname(master);
  if (slave_name == NULL) goto err;
  if (name) strcpy(name, slave_name);

  slave = open(slave_name, O_RDWR | O_NOCTTY);
  if (slave == -1) goto err;
  if (aslave) *aslave = slave;

  ioctl(slave, I_PUSH, "ptem");
  ioctl(slave, I_PUSH, "ldterm");
  ioctl(slave, I_PUSH, "ttcompat");

  if (termp) tcsetattr(slave, TCSAFLUSH, termp);
  if (winp) ioctl(slave, TIOCSWINSZ, winp);

  return 0;

err:
  close(master);
  return -1;
#else
  return openpty(amaster, aslave, name, (termios *)termp, (winsize *)winp);
#endif
}

static pid_t
pty_forkpty(int *amaster, char *name,
            const struct termios *termp,
            const struct winsize *winp) {
#if defined(__sun)
  int master, slave;

  int ret = pty_openpty(&master, &slave, name, termp, winp);
  if (ret == -1) return -1;
  if (amaster) *amaster = master;

  pid_t pid = fork();

  switch (pid) {
    case -1:
      close(master);
      close(slave);
      return -1;
    case 0:
      close(master);

      setsid();

#if defined(TIOCSCTTY)
      // glibc does this
      if (ioctl(slave, TIOCSCTTY, NULL) == -1) _exit(1);
#endif

      dup2(slave, 0);
      dup2(slave, 1);
      dup2(slave, 2);

      if (slave > 2) close(slave);

      return 0;
    default:
      close(slave);
      return pid;
  }

  return -1;
#else
  return forkpty(amaster, name, (termios *)termp, (winsize *)winp);
#endif
}

/**
 * Init
 */

extern "C" void
init(Handle<Object> target) {
  HandleScope scope;
  NODE_SET_METHOD(target, "fork", PtyFork);
  NODE_SET_METHOD(target, "open", PtyOpen);
  NODE_SET_METHOD(target, "resize", PtyResize);
  NODE_SET_METHOD(target, "process", PtyGetProc);
}
<commit_msg>Fix for node v0.9.x<commit_after>/**
 * pty.js
 * Copyright (c) 2012, Christopher Jeffrey (MIT License)
 *
 * pty.cc:
 *   This file is responsible for starting processes
 *   with pseudo-terminal file descriptors.
 *
 * See:
 *   man pty
 *   man tty_ioctl
 *   man termios
 *   man forkpty
 */

#include <v8.h>
#include <node.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>

/* forkpty */
/* http://www.gnu.org/software/gnulib/manual/html_node/forkpty.html */
#if defined(__GLIBC__) || defined(__CYGWIN__)
#include <pty.h>
#elif defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
#include <util.h>
#elif defined(__FreeBSD__)
#include <libutil.h>
#elif defined(__sun)
#include <stropts.h> /* for I_PUSH */
#else
#include <pty.h>
#endif

#include <termios.h> /* tcgetattr, tty_ioctl */

/* environ for execvpe */
/* node/src/node_child_process.cc */
#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
#else
extern char **environ;
#endif

/* for pty_getproc */
#if defined(__linux__)
#include <stdio.h>
#include <stdint.h>
#elif defined(__APPLE__)
#include <sys/sysctl.h>
#include <libproc.h>
#endif

using namespace std;
using namespace node;
using namespace v8;

static Handle<Value>
PtyFork(const Arguments&);

static Handle<Value>
PtyOpen(const Arguments&);

static Handle<Value>
PtyResize(const Arguments&);

static Handle<Value>
PtyGetProc(const Arguments&);

static int
pty_execvpe(const char *, char **, char **);

static int
pty_nonblock(int);

static char *
pty_getproc(int, char *);

static int
pty_openpty(int *, int *, char *,
            const struct termios *,
            const struct winsize *);

static pid_t
pty_forkpty(int *, char *,
            const struct termios *,
            const struct winsize *);

extern "C" void
init(Handle<Object>);

/**
 * PtyFork
 * pty.fork(file, args, env, cwd, cols, rows)
 */

static Handle<Value>
PtyFork(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 6
      || !args[0]->IsString()
      || !args[1]->IsArray()
      || !args[2]->IsArray()
      || !args[3]->IsString()
      || !args[4]->IsNumber()
      || !args[5]->IsNumber()) {
    return ThrowException(Exception::Error(
      String::New("Usage: pty.fork(file, args, env, cwd, cols, rows)")));
  }

  // node/src/node_child_process.cc

  // file
  String::Utf8Value file(args[0]->ToString());

  // args
  int i = 0;
  Local<Array> argv_ = Local<Array>::Cast(args[1]);
  int argc = argv_->Length();
  int argl = argc + 1 + 1;
  char **argv = new char*[argl];
  argv[0] = strdup(*file);
  argv[argl-1] = NULL;
  for (; i < argc; i++) {
    String::Utf8Value arg(argv_->Get(Integer::New(i))->ToString());
    argv[i+1] = strdup(*arg);
  }

  // env
  i = 0;
  Local<Array> env_ = Local<Array>::Cast(args[2]);
  int envc = env_->Length();
  char **env = new char*[envc+1];
  env[envc] = NULL;
  for (; i < envc; i++) {
    String::Utf8Value pair(env_->Get(Integer::New(i))->ToString());
    env[i] = strdup(*pair);
  }

  // cwd
  String::Utf8Value cwd_(args[3]->ToString());
  char *cwd = strdup(*cwd_);

  // size
  struct winsize winp;
  winp.ws_col = args[4]->IntegerValue();
  winp.ws_row = args[5]->IntegerValue();
  winp.ws_xpixel = 0;
  winp.ws_ypixel = 0;

  // fork the pty
  int master = -1;
  char name[40];
  pid_t pid = pty_forkpty(&master, name, NULL, &winp);

  if (pid) {
    for (i = 0; i < argl; i++) free(argv[i]);
    delete[] argv;
    for (i = 0; i < envc; i++) free(env[i]);
    delete[] env;
    free(cwd);
  }

  switch (pid) {
    case -1:
      return ThrowException(Exception::Error(
        String::New("forkpty(3) failed.")));
    case 0:
      if (strlen(cwd)) chdir(cwd);

      pty_execvpe(argv[0], argv, env);

      perror("execvp(3) failed.");
      _exit(1);
    default:
      if (pty_nonblock(master) == -1) {
        return ThrowException(Exception::Error(
          String::New("Could not set master fd to nonblocking.")));
      }

      Local<Object> obj = Object::New();
      obj->Set(String::New("fd"), Number::New(master));
      obj->Set(String::New("pid"), Number::New(pid));
      obj->Set(String::New("pty"), String::New(name));

      return scope.Close(obj);
  }

  return Undefined();
}

/**
 * PtyOpen
 * pty.open(cols, rows)
 */

static Handle<Value>
PtyOpen(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 2
      || !args[0]->IsNumber()
      || !args[1]->IsNumber()) {
    return ThrowException(Exception::Error(
      String::New("Usage: pty.open(cols, rows)")));
  }

  // size
  struct winsize winp;
  winp.ws_col = args[0]->IntegerValue();
  winp.ws_row = args[1]->IntegerValue();
  winp.ws_xpixel = 0;
  winp.ws_ypixel = 0;

  // pty
  int master, slave;
  char name[40];
  int ret = pty_openpty(&master, &slave, name, NULL, &winp);

  if (ret == -1) {
    return ThrowException(Exception::Error(
      String::New("openpty(3) failed.")));
  }

  if (pty_nonblock(master) == -1) {
    return ThrowException(Exception::Error(
      String::New("Could not set master fd to nonblocking.")));
  }

  if (pty_nonblock(slave) == -1) {
    return ThrowException(Exception::Error(
      String::New("Could not set slave fd to nonblocking.")));
  }

  Local<Object> obj = Object::New();
  obj->Set(String::New("master"), Number::New(master));
  obj->Set(String::New("slave"), Number::New(slave));
  obj->Set(String::New("pty"), String::New(name));

  return scope.Close(obj);
}

/**
 * Resize Functionality
 * pty.resize(fd, cols, rows)
 */

static Handle<Value>
PtyResize(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 3
      || !args[0]->IsNumber()
      || !args[1]->IsNumber()
      || !args[2]->IsNumber()) {
    return ThrowException(Exception::Error(
      String::New("Usage: pty.resize(fd, cols, rows)")));
  }

  int fd = args[0]->IntegerValue();

  struct winsize winp;
  winp.ws_col = args[1]->IntegerValue();
  winp.ws_row = args[2]->IntegerValue();
  winp.ws_xpixel = 0;
  winp.ws_ypixel = 0;

  if (ioctl(fd, TIOCSWINSZ, &winp) == -1) {
    return ThrowException(Exception::Error(
      String::New("ioctl(2) failed.")));
  }

  return Undefined();
}

/**
 * PtyGetProc
 * Foreground Process Name
 * pty.process(fd, tty)
 */

static Handle<Value>
PtyGetProc(const Arguments& args) {
  HandleScope scope;

  if (args.Length() != 2
      || !args[0]->IsNumber()
      || !args[1]->IsString()) {
    return ThrowException(Exception::Error(
      String::New("Usage: pty.process(fd, tty)")));
  }

  int fd = args[0]->IntegerValue();

  String::Utf8Value tty_(args[1]->ToString());
  char *tty = strdup(*tty_);
  char *name = pty_getproc(fd, tty);
  free(tty);

  if (name == NULL) {
    return Undefined();
  }

  Local<String> name_ = String::New(name);
  free(name);
  return scope.Close(name_);
}

/**
 * execvpe
 */

// execvpe(3) is not portable.
// http://www.gnu.org/software/gnulib/manual/html_node/execvpe.html
static int
pty_execvpe(const char *file, char **argv, char **envp) {
  char **old = environ;
  environ = envp;
  int ret = execvp(file, argv);
  environ = old;
  return ret;
}

/**
 * Nonblocking FD
 */

static int
pty_nonblock(int fd) {
  int flags = fcntl(fd, F_GETFL, 0);
  if (flags == -1) return -1;
  return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

/**
 * pty_getproc
 * Taken from tmux.
 */

// Taken from: tmux (http://tmux.sourceforge.net/)
// Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
// Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org>
// Copyright (c) 2009 Todd Carson <toc@daybefore.net>
//
// Permission to use, copy, modify, and 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 MIND, 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.

#if defined(__linux__)

static char *
pty_getproc(int fd, char *tty) {
  FILE *f;
  char *path, *buf;
  size_t len;
  int ch;
  pid_t pgrp;
  int r;

  if ((pgrp = tcgetpgrp(fd)) == -1) {
    return NULL;
  }

  r = asprintf(&path, "/proc/%lld/cmdline", (long long)pgrp);
  if (r == -1 || path == NULL) return NULL;

  if ((f = fopen(path, "r")) == NULL) {
    free(path);
    return NULL;
  }

  free(path);

  len = 0;
  buf = NULL;
  while ((ch = fgetc(f)) != EOF) {
    if (ch == '\0') break;
    buf = (char *)realloc(buf, len + 2);
    if (buf == NULL) return NULL;
    buf[len++] = ch;
  }

  if (buf != NULL) {
    buf[len] = '\0';
  }

  fclose(f);
  return buf;
}

#elif defined(__APPLE__)

static char *
pty_getproc(int fd, char *tty) {
  int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 };
  size_t size;
  struct kinfo_proc kp;

  if ((mib[3] = tcgetpgrp(fd)) == -1) {
    return NULL;
  }

  size = sizeof kp;
  if (sysctl(mib, 4, &kp, &size, NULL, 0) == -1) {
    return NULL;
  }

  if (*kp.kp_proc.p_comm == '\0') {
    return NULL;
  }

  return strdup(kp.kp_proc.p_comm);
}

#else

static char *
pty_getproc(int fd, char *tty) {
  return NULL;
}

#endif

/**
 * openpty(3) / forkpty(3)
 */

static int
pty_openpty(int *amaster, int *aslave, char *name,
            const struct termios *termp,
            const struct winsize *winp) {
#if defined(__sun)
  char *slave_name;
  int slave;
  int master = open("/dev/ptmx", O_RDWR | O_NOCTTY);
  if (master == -1) return -1;
  if (amaster) *amaster = master;

  if (grantpt(master) == -1) goto err;
  if (unlockpt(master) == -1) goto err;

  slave_name = ptsname(master);
  if (slave_name == NULL) goto err;
  if (name) strcpy(name, slave_name);

  slave = open(slave_name, O_RDWR | O_NOCTTY);
  if (slave == -1) goto err;
  if (aslave) *aslave = slave;

  ioctl(slave, I_PUSH, "ptem");
  ioctl(slave, I_PUSH, "ldterm");
  ioctl(slave, I_PUSH, "ttcompat");

  if (termp) tcsetattr(slave, TCSAFLUSH, termp);
  if (winp) ioctl(slave, TIOCSWINSZ, winp);

  return 0;

err:
  close(master);
  return -1;
#else
  return openpty(amaster, aslave, name, (termios *)termp, (winsize *)winp);
#endif
}

static pid_t
pty_forkpty(int *amaster, char *name,
            const struct termios *termp,
            const struct winsize *winp) {
#if defined(__sun)
  int master, slave;

  int ret = pty_openpty(&master, &slave, name, termp, winp);
  if (ret == -1) return -1;
  if (amaster) *amaster = master;

  pid_t pid = fork();

  switch (pid) {
    case -1:
      close(master);
      close(slave);
      return -1;
    case 0:
      close(master);

      setsid();

#if defined(TIOCSCTTY)
      // glibc does this
      if (ioctl(slave, TIOCSCTTY, NULL) == -1) _exit(1);
#endif

      dup2(slave, 0);
      dup2(slave, 1);
      dup2(slave, 2);

      if (slave > 2) close(slave);

      return 0;
    default:
      close(slave);
      return pid;
  }

  return -1;
#else
  return forkpty(amaster, name, (termios *)termp, (winsize *)winp);
#endif
}

/**
 * Init
 */

extern "C" void
init(Handle<Object> target) {
  HandleScope scope;
  NODE_SET_METHOD(target, "fork", PtyFork);
  NODE_SET_METHOD(target, "open", PtyOpen);
  NODE_SET_METHOD(target, "resize", PtyResize);
  NODE_SET_METHOD(target, "process", PtyGetProc);
}

NODE_MODULE(pty, init)
<|endoftext|>


<commit_before>#include <glib.h>
#include <nan.h>

#include "debug.h"
#include "function.h"
#include "type.h"
#include "value.h"

using namespace v8;

namespace GNodeJS {

struct Closure {
    GClosure base;
    Persistent<Function> persistent;
    GISignalInfo* info;

    ~Closure() {
        if (info)
            g_base_info_unref(info);
    }

    static void Marshal(GClosure *closure,
                        GValue   *g_return_value,
                        uint argc, const GValue *g_argv,
                        gpointer  invocation_hint,
                        gpointer  marshal_data);

    static void Invalidated(gpointer data, GClosure *closure);
};

void Closure::Marshal(GClosure *base,
                      GValue   *g_return_value,
                      uint argc, const GValue *g_argv,
                      gpointer  invocation_hint,
                      gpointer  marshal_data) {
    Closure *closure = (Closure *) base;
    Isolate *isolate = Isolate::GetCurrent ();

    HandleScope scope(isolate);
    Local<Context> context = Context::New(isolate);
    Context::Scope context_scope(context);
    Nan::TryCatch try_catch;

    Local<Function> func = Local<Function>::New(isolate, closure->persistent);

    // We don't pass the implicit instance as first argument
    uint n_js_args = argc - 1;

    #ifndef __linux__
        Local<Value>* js_args = new Local<Value>[n_js_args];
    #else
        Local<Value> js_args[n_js_args];
    #endif

    for (uint i = 1; i < argc; i++) {
        GIArgument argument;
        memcpy(&argument, &g_argv[i].data[0], sizeof(GIArgument));
        GIArgInfo arg_info;
        GITypeInfo type_info;
        g_callable_info_load_arg(closure->info, i - 1, &arg_info);
        g_arg_info_load_type(&arg_info, &type_info);

        js_args[i - 1] = GIArgumentToV8(&type_info, &argument);
    }

    Local<Object> self = func;
    Local<Value> result = func->CallAsFunction(self, n_js_args, js_args);

    if (!result.IsEmpty()) {
        if (g_return_value) {
            if (G_VALUE_TYPE(g_return_value) == G_TYPE_INVALID)
                g_warning ("Marshal: return value has invalid g_type");
            else if (!V8ToGValue (g_return_value, result))
                g_warning ("Marshal: could not convert return value");
        }
    }
    else {
        auto stackTrace = try_catch.StackTrace();
        if (!stackTrace.IsEmpty())
            printf("%s\n", *Nan::Utf8String(stackTrace.ToLocalChecked()));
        else
            printf("%s\n", *Nan::Utf8String(try_catch.Exception()));
        exit(1);
    }

    #ifndef __linux__
        delete[] js_args;
    #endif
}

void Closure::Invalidated(gpointer data, GClosure *base) {
    Closure *closure = (Closure *) base;
    closure->~Closure();
}

GClosure *MakeClosure(Isolate *isolate, Local<Function> function, GISignalInfo* info) {
    Closure *closure = (Closure *) g_closure_new_simple (sizeof (*closure), NULL);
    closure->persistent.Reset(isolate, function);
    closure->info = info;
    GClosure *gclosure = &closure->base;
    g_closure_set_marshal (gclosure, Closure::Marshal);
    g_closure_add_invalidate_notifier (gclosure, NULL, Closure::Invalidated);
    return gclosure;
}

};
<commit_msg>Revert "closure: remove Nan::Call"<commit_after>#include <glib.h>
#include <nan.h>

#include "debug.h"
#include "function.h"
#include "type.h"
#include "value.h"

using namespace v8;

namespace GNodeJS {

struct Closure {
    GClosure base;
    Persistent<Function> persistent;
    GISignalInfo* info;

    ~Closure() {
        if (info)
            g_base_info_unref(info);
    }

    static void Marshal(GClosure *closure,
                        GValue   *g_return_value,
                        uint argc, const GValue *g_argv,
                        gpointer  invocation_hint,
                        gpointer  marshal_data);

    static void Invalidated(gpointer data, GClosure *closure);
};

void Closure::Marshal(GClosure *base,
                      GValue   *g_return_value,
                      uint argc, const GValue *g_argv,
                      gpointer  invocation_hint,
                      gpointer  marshal_data) {
    Closure *closure = (Closure *) base;
    Isolate *isolate = Isolate::GetCurrent ();

    HandleScope scope(isolate);
    Local<Context> context = Context::New(isolate);
    Context::Scope context_scope(context);
    Nan::TryCatch try_catch;

    Local<Function> func = Local<Function>::New(isolate, closure->persistent);

    // We don't pass the implicit instance as first argument
    uint n_js_args = argc - 1;

    #ifndef __linux__
        Local<Value>* js_args = new Local<Value>[n_js_args];
    #else
        Local<Value> js_args[n_js_args];
    #endif

    for (uint i = 1; i < argc; i++) {
        GIArgument argument;
        memcpy(&argument, &g_argv[i].data[0], sizeof(GIArgument));
        GIArgInfo arg_info;
        GITypeInfo type_info;
        g_callable_info_load_arg(closure->info, i - 1, &arg_info);
        g_arg_info_load_type(&arg_info, &type_info);

        js_args[i - 1] = GIArgumentToV8(&type_info, &argument);
    }

    Local<Object> self = func;
    Local<Value> return_value;

    auto result = Nan::Call(func, self, n_js_args, js_args);

    if (result.ToLocal(&return_value)) {
        if (g_return_value) {
            if (G_VALUE_TYPE(g_return_value) == G_TYPE_INVALID)
                g_warning ("Marshal: return value has invalid g_type");
            else if (!V8ToGValue (g_return_value, return_value))
                g_warning ("Marshal: could not convert return value");
        }
    }
    else {
        auto stackTrace = try_catch.StackTrace();
        if (!stackTrace.IsEmpty())
            printf("%s\n", *Nan::Utf8String(stackTrace.ToLocalChecked()));
        else
            printf("%s\n", *Nan::Utf8String(try_catch.Exception()));
        exit(1);
    }

    #ifndef __linux__
        delete[] js_args;
    #endif
}

void Closure::Invalidated(gpointer data, GClosure *base) {
    Closure *closure = (Closure *) base;
    closure->~Closure();
}

GClosure *MakeClosure(Isolate *isolate, Local<Function> function, GISignalInfo* info) {
    Closure *closure = (Closure *) g_closure_new_simple (sizeof (*closure), NULL);
    closure->persistent.Reset(isolate, function);
    closure->info = info;
    GClosure *gclosure = &closure->base;
    g_closure_set_marshal (gclosure, Closure::Marshal);
    g_closure_add_invalidate_notifier (gclosure, NULL, Closure::Invalidated);
    return gclosure;
}

};
<|endoftext|>


<commit_before>/*	cluster.hh	*/
//C Copyright (C) 2015 Richard Tjörnhammar
//L
//L  This library is free software and is distributed under the terms
//L  and conditions of version 2.1 of the GNU Lesser General Public
//L  Licence (LGPL) with the following additional clause:
//L
//L     `You may also combine or link a "work that uses the Library" to
//L     produce a work containing portions of the Library, and distribute
//L     that work under terms of your choice, provided that you give
//L     prominent notice with each copy of the work that the specified
//L     version of the Library is used in it, and that you include or
//L     provide public access to the complete corresponding
//L     machine-readable source code for the Library including whatever
//L     changes were used in the work. (i.e. If you make changes to the
//L     Library you must distribute those, but you do not need to
//L     distribute source or object code to those portions of the work
//L     not covered by this licence.)'
//L
//L  Note that this clause grants an additional right and does not impose
//L  any additional restriction, and so does not affect compatibility
//L  with the GNU General Public Licence (GPL). If you wish to negotiate
//L  other terms, please contact the maintainer.
//L
//L  You can redistribute it and/or modify the library under the terms of
//L  the GNU Lesser General Public License as published by the Free Software
//L  Foundation; either version 2.1 of the License, or (at your option) any
//L  later version.
//L
//L  This library is distributed in the hope that it will be useful, but
//L  WITHOUT ANY WARRANTY; without even the implied warranty of
//L  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//L  Lesser General Public License for more details.
//L
//L  You should have received a copy of the CCP4 licence and/or GNU
//L  Lesser General Public License along with this library; if not, write
//L  to the CCP4 Secretary, Daresbury Laboratory, Warrington WA4 4AD, UK.
//L  The GNU Lesser General Public can also be obtained by writing to the
//L  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
//L  MA 02111-1307 USA

#include "richtypes.h"
#include "simple.hh"
#include "iofunc.hh"
#include "richfit.hh"

namespace richanalysis {

	class clustering : public simple_ops {
		public:
		//! null constructor
			inline clustering() {} //!< Null constructor

		//! performs k-means clustering on the specified data
			int gsl_kmeans( gmat *, gvec *, gmat *, gvec * );
			int gsl_kmeans( gmat *, gvec *, gmat *, gvec *, ftyp );

		//! performs my own connectivity clustering algorithm
			int connectivity( gmat * , ftyp val );
	};

	class cluster :  public clustering, public tensorIO {
		public:
			cluster() { 	bSet_ = false; rDIM_=DIM; };
			void		alloc_space ( int, int ); // model_N and cent_N
			int		set_matrix( particles );
			int		find_centroids( void );
			std::vector<int>	get_labels( void );
		//
			void		copyC(gmat *C0) {
						if(C0->size1==C_->size1&&C0->size2==C_->size2) { gsl_matrix_memcpy(C0, C_); }
					};
			void		copyM(gmat *M0) {
						if(M0->size1==M_->size1&&M0->size2==M_->size2) { gsl_matrix_memcpy(M0, M_); }
					};
			void		copyv(gvec *v0) {
						if(v0->size ==vc_->size) { gsl_vector_memcpy(v0, vc_); }
					};
			void		copyw(gvec *w0) {
						if(w0->size ==wc_->size) { gsl_vector_memcpy(w0, wc_); }
					};

			void		writev(gvec *v0) {
						if(v0->size ==vc_->size) { gsl_vector_memcpy(vc_, v0); }
					};
			int		get_cDIM(void) { return rDIM_; }; // centroid dimension
			void		set_cDIM(int rDIM) { rDIM_=rDIM; };// centroid dimension
			int		length_C(void){ return C_->size2; };
			int		length_M(void){ return M_->size2; };
			bool		isSet() { return ( bSet_ ); };
		private:
			gmat	*M_; 		// 0 THE ORIGINAL COORDINATES
			gmat	*C_; 		// 1 THE CENTROIDS
			gvec	*vc_;		// 0 UNSORTED LABELS
			gvec	*wc_;		// 1 UNSORTED LABELS
			int	bSet_;
			std::vector<int>	inOrder_;
			std::vector<int>	NperC_;
			int	rDIM_;
	};

	typedef std::pair< cluster, cluster > node;
	typedef std::vector< node > layer;

	class node_analysis : public fitting {
		public:
			node_analysis() { bNode_ = false; bLayer_ = false; };
			node_analysis( node n ) { bNode_ = assign_node( n ); };
			std::vector< int >	find_centroid_relation( void );
			bool			find_index_orders(void);
			std::vector< int >	global_index_order ( void ) { return glob_idx_order_; };
			std::vector< int >	cluster_index_order( void ) { return cidx_; };
			std::pair<int,int>	size(void){ std::pair<int,int> pi;
							pi.first=parents_.first.length_M();
							pi.second=parents_.second.length_M();
							return pi; };
			bool			assign_node( node n );
			bool			allSet()	{ return ( bNode_ && bLayer_ ); };
			bool			haveNode()	{ return ( bNode_); };
			bool			haveLayer()	{ return ( bLayer_ ); };
			layer			get_node_layer( void ){ return children_; };
			~node_analysis(){};
		private:
			node	parents_;
			layer	children_;
			bool bNode_; bool bLayer_;
			std::vector<int>  idx_;
			std::vector<int> iidx_;
			std::vector<int> cidx_;
			std::vector<int> glob_idx_order_;
	};

	class cluster0 : public clustering, public linalg, public tensorIO {
		public:
			cluster0() { 	bSet_[0]=0; bSet_[1]=0; bSet_[2]=0; bSet_[3]=0; bPCset_=0;
					Uc_  = gsl_matrix_calloc( DIM, DIM );	tc_ = gsl_vector_calloc( DIM );
					Axis_ = gsl_vector_calloc( DIM );	Euler_ = gsl_vector_calloc( DIM ); };

			std::vector<int>	get_labels  ( void );
			void			alloc_space ( int, int );
			void			seM ( int, int, ftyp );
			void			sev ( int, ftyp );
			void			seC ( int, int, ftyp );
			void			sew ( int, ftyp );
			int 			set_matrix( particles );
			void			print_all( void ) {
							output_matrix( M_ );
							output_vector(vc_ );
							output_matrix( C_ );
							output_vector(wc_ );
						} ;
			int			perform_clustering( void );
			int			perform_clustering( ftyp );
			int			length_C(void){ return C_->size2; };
			int			length_M(void){ return M_->size2; };
			void	copyC(gmat *C0){ if(C0->size1==C_->size1&&C0->size2==C_->size2) { gsl_matrix_memcpy(C0, C_); } };
			void	copyM(gmat *M0){ if(M0->size1==M_->size1&&M0->size2==M_->size2) { gsl_matrix_memcpy(M0, M_); } };
			void	setM( gmat *M0){ if(M0->size1==M_->size1&&M0->size2==M_->size2) { gsl_matrix_memcpy(M_, M0); } };
			void	copyUc(gmat *U0){ if(U0->size1==Uc_->size1&&U0->size2==Uc_->size2) { gsl_matrix_memcpy(U0, Uc_); } };
			void	copytc(gvec *tc0){ if(tc0->size ==tc_->size) { gsl_vector_memcpy(tc0, tc_); } };
			void	copyv(gvec *v0){ if(v0->size ==vc_->size) { gsl_vector_memcpy(v0, vc_); } };
			void	copyw(gvec *w0){ if(w0->size ==wc_->size) { gsl_vector_memcpy(w0, wc_); } };
			int	NpC(int i){ if(NperC_.size()>0&&i<NperC_.size()){ return NperC_[i]; } };
			bool			isSet(){return bSet_[0]>0&&bSet_[1]>0&&bSet_[2]>0&&bSet_[3]>0;}
			ftyp			find_shape();
		//! Calculates the shape
			ftyp			shape(	gmat *P , gmat *U , gvec *t 	);
			void			print_shape( void ) { output_matrix( Uc_ ); };
			bool			has_shape(void){return (bPCset_==1); };
			particle		normal(void);
			particle		center(void);
			~cluster0() {}
	private:
		gmat	*M_; 		// 0 THE ORIGINAL COORDINATES
		gmat	*C_; 		// 1 THE CENTROIDS
		gvec	*vc_;		// 0 UNSORTED LABELS
		gvec	*wc_;		// 1 UNSORTED LABELS
		int	bSet_[4];
		std::vector<int>	NperC_;
//	shape stuff
		gmat *Uc_;
		gvec *tc_;
		gvec *Euler_;
		gvec *Axis_;
		ftyp angle_;
		int bPCset_;
	};

	class cluster_node0 : public fitting {
		public:
			cluster_node0() { bDirRel_=0; bUtSet_=0; subSet_=0;
					U_  = gsl_matrix_calloc( DIM, DIM );  t_ = gsl_vector_calloc( DIM );
					iU_ = gsl_matrix_calloc( DIM, DIM ); it_ = gsl_vector_calloc( DIM ); sgn_=1; }

			void			assign_sub( cluster0 c1, cluster0 c2 );
			bool			subSet() { return (subSet_==1); };

			std::vector<int>	find_centroid_relation( void );

			std::vector<int>	find_simple_relation( void );

			std::pair< particles,
			std::vector<int> >	apply_fragment_trans( particles, std::vector<int> );

			std::vector<int> 	get_indices(void){ return idx_; };
			std::vector<int> 	global_fragment_order(void);
			int			direction_relation(void){ return bDirRel_;};
			int			have_transform(void){ return bUtSet_; };
			particles 		apply_rot_trans( particles , int );
			particles 		apply_rot_trans( particles );
			particles		assign_particles( void ); // packs subclusters into a particles struct
			void			invert_transform(void);
			void			printUt(void){  output_matrix(U_); output_vector(t_); };
			void			printiUt(void){ output_matrix(iU_);output_vector(it_);};
			ftyp			angle_between(cluster0 c1, cluster0 c2);
			std::pair<ftyp, ftyp >	angle_between(cluster0 c1, cluster0 c2, int i, int j);
		private:
			int subSet_;
			std::pair<richanalysis::cluster0, richanalysis::cluster0 > parents_;
			std::vector<richanalysis::cluster0 > vc1_, vc2_; // subclusters
			int bDirRel_;
			std::vector<int> idx_;		// clusters
			std::vector<int> iidx_;		// clusters
			std::vector<int> cidx_;
			int N_,M_,I_,J_;
			int bUtSet_;
			int sgn_;
			gmat *U_,*iU_;
			gvec *t_,*it_;
	};

}
<commit_msg>f00b4r<commit_after>/*	cluster.hh	*/
//C Copyright (C) 2015 Richard Tjörnhammar
//L
//L  This library is free software and is distributed under the terms
//L  and conditions of version 2.1 of the GNU Lesser General Public
//L  Licence (LGPL) with the following additional clause:
//L
//L     `You may also combine or link a "work that uses the Library" to
//L     produce a work containing portions of the Library, and distribute
//L     that work under terms of your choice, provided that you give
//L     prominent notice with each copy of the work that the specified
//L     version of the Library is used in it, and that you include or
//L     provide public access to the complete corresponding
//L     machine-readable source code for the Library including whatever
//L     changes were used in the work. (i.e. If you make changes to the
//L     Library you must distribute those, but you do not need to
//L     distribute source or object code to those portions of the work
//L     not covered by this licence.)'
//L
//L  Note that this clause grants an additional right and does not impose
//L  any additional restriction, and so does not affect compatibility
//L  with the GNU General Public Licence (GPL). If you wish to negotiate
//L  other terms, please contact the maintainer.
//L
//L  You can redistribute it and/or modify the library under the terms of
//L  the GNU Lesser General Public License as published by the Free Software
//L  Foundation; either version 2.1 of the License, or (at your option) any
//L  later version.
//L
//L  This library is distributed in the hope that it will be useful, but
//L  WITHOUT ANY WARRANTY; without even the implied warranty of
//L  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//L  Lesser General Public License for more details.
//L
//L  You should have received a copy of the CCP4 licence and/or GNU
//L  Lesser General Public License along with this library; if not, write
//L  to the CCP4 Secretary, Daresbury Laboratory, Warrington WA4 4AD, UK.
//L  The GNU Lesser General Public can also be obtained by writing to the
//L  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
//L  MA 02111-1307 USA

#include "richtypes.h"
#include "simple.hh"
#include "iofunc.hh"
#include "richfit.hh"

namespace richanalysis {

	class clustering : public simple_ops {
		public:
		//! null constructor
			inline clustering() {} //!< Null constructor

		//! performs k-means clustering on the specified data
			int gsl_kmeans( gmat *, gvec *, gmat *, gvec * );
			int gsl_kmeans( gmat *, gvec *, gmat *, gvec *, ftyp );

		//! performs my own connectivity clustering algorithm
			int connectivity( gmat * , ftyp val );
	};

	class cluster :  public clustering, public tensorIO {
		public:
			cluster() { 	bSet_ = false; rDIM_=DIM; };
			void		alloc_space ( int, int ); // model_N and cent_N
			int		set_matrix( particles );
			int		find_centroids( void );
			std::vector<int>	get_labels( void );
		//
			void		copyC(gmat *C0) {
						if(C0->size1==C_->size1&&C0->size2==C_->size2) { gsl_matrix_memcpy(C0, C_); }
					};
			void		copyM(gmat *M0) {
						if(M0->size1==M_->size1&&M0->size2==M_->size2) { gsl_matrix_memcpy(M0, M_); }
					};
			void		copyv(gvec *v0) {
						if(v0->size ==vc_->size) { gsl_vector_memcpy(v0, vc_); }
					};
			void		copyw(gvec *w0) {
						if(w0->size ==wc_->size) { gsl_vector_memcpy(w0, wc_); }
					};

			void		writev(gvec *v0) {
						if(v0->size ==vc_->size) { gsl_vector_memcpy(vc_, v0); }
					};
			int		get_cDIM(void) { return rDIM_; }; // centroid dimension
			void		set_cDIM(int rDIM) { rDIM_=rDIM; };// centroid dimension
			int		length_C(void){ return C_->size2; };
			int		length_M(void){ return M_->size2; };
			bool		isSet() { return ( bSet_ ); };
		private:
			gmat	*M_; 		// 0 THE ORIGINAL COORDINATES
			gmat	*C_; 		// 1 THE CENTROIDS
			gvec	*vc_;		// 0 UNSORTED LABELS
			gvec	*wc_;		// 1 UNSORTED LABELS
			int	bSet_;
			std::vector<int>	inOrder_;
			std::vector<int>	NperC_;
			int	rDIM_;
	};

	typedef std::pair< cluster, cluster > node;
	typedef std::vector< node > layer;

	class node_analysis : public fitting {
		public:
			node_analysis() { bNode_ = false; bLayer_ = false; };
			node_analysis( node n ) { bNode_ = assign_node( n ); };
			std::vector< int >	find_centroid_relation( void );
			bool			find_index_orders(void);
			std::vector< int >	global_index_order ( void ) { return glob_idx_order_; };
			std::vector< int >	cluster_index_order( void ) { return cidx_; };
			std::pair<int,int>	size(void){ std::pair<int,int> pi;
							pi.first=parents_.first.length_M();
							pi.second=parents_.second.length_M();
							return pi; };
			bool			assign_node( node n );
			bool			allSet()	{ return ( bNode_ && bLayer_ ); };
			bool			haveNode()	{ return ( bNode_); };
			bool			haveLayer()	{ return ( bLayer_ ); };
			layer			get_node_layer( void ){ return children_; };
			~node_analysis(){};
		private:
			node	parents_;
			layer	children_;
			bool bNode_; bool bLayer_;
			std::vector<int>  idx_;
			std::vector<int> iidx_;
			std::vector<int> cidx_;
			std::vector<int> glob_idx_order_;
	};

	class layer_analysis : public fileIO {
		public:
			layer_analysis(){ bSet_ = false; };
			layer_analysis(layer l){ bSet_ = true; own_=l; };
			void output_layer( std::string );
		private:
			layer	own_;
			bool	bSet_;
	};

	class cluster0 : public clustering, public linalg, public tensorIO {
		public:
			cluster0() { 	bSet_[0]=0; bSet_[1]=0; bSet_[2]=0; bSet_[3]=0; bPCset_=0;
					Uc_  = gsl_matrix_calloc( DIM, DIM );	tc_ = gsl_vector_calloc( DIM );
					Axis_ = gsl_vector_calloc( DIM );	Euler_ = gsl_vector_calloc( DIM ); };

			std::vector<int>	get_labels  ( void );
			void			alloc_space ( int, int );
			void			seM ( int, int, ftyp );
			void			sev ( int, ftyp );
			void			seC ( int, int, ftyp );
			void			sew ( int, ftyp );
			int 			set_matrix( particles );
			void			print_all( void ) {
							output_matrix( M_ );
							output_vector(vc_ );
							output_matrix( C_ );
							output_vector(wc_ );
						} ;
			int			perform_clustering( void );
			int			perform_clustering( ftyp );
			int			length_C(void){ return C_->size2; };
			int			length_M(void){ return M_->size2; };
			void	copyC(gmat *C0){ if(C0->size1==C_->size1&&C0->size2==C_->size2) { gsl_matrix_memcpy(C0, C_); } };
			void	copyM(gmat *M0){ if(M0->size1==M_->size1&&M0->size2==M_->size2) { gsl_matrix_memcpy(M0, M_); } };
			void	setM( gmat *M0){ if(M0->size1==M_->size1&&M0->size2==M_->size2) { gsl_matrix_memcpy(M_, M0); } };
			void	copyUc(gmat *U0){ if(U0->size1==Uc_->size1&&U0->size2==Uc_->size2) { gsl_matrix_memcpy(U0, Uc_); } };
			void	copytc(gvec *tc0){ if(tc0->size ==tc_->size) { gsl_vector_memcpy(tc0, tc_); } };
			void	copyv(gvec *v0){ if(v0->size ==vc_->size) { gsl_vector_memcpy(v0, vc_); } };
			void	copyw(gvec *w0){ if(w0->size ==wc_->size) { gsl_vector_memcpy(w0, wc_); } };
			int	NpC(int i){ if(NperC_.size()>0&&i<NperC_.size()){ return NperC_[i]; } };
			bool			isSet(){return bSet_[0]>0&&bSet_[1]>0&&bSet_[2]>0&&bSet_[3]>0;}
			ftyp			find_shape();
		//! Calculates the shape
			ftyp			shape(	gmat *P , gmat *U , gvec *t 	);
			void			print_shape( void ) { output_matrix( Uc_ ); };
			bool			has_shape(void){return (bPCset_==1); };
			particle		normal(void);
			particle		center(void);
			~cluster0() {}
	private:
		gmat	*M_; 		// 0 THE ORIGINAL COORDINATES
		gmat	*C_; 		// 1 THE CENTROIDS
		gvec	*vc_;		// 0 UNSORTED LABELS
		gvec	*wc_;		// 1 UNSORTED LABELS
		int	bSet_[4];
		std::vector<int>	NperC_;
//	shape stuff
		gmat *Uc_;
		gvec *tc_;
		gvec *Euler_;
		gvec *Axis_;
		ftyp angle_;
		int bPCset_;
	};

	class cluster_node0 : public fitting {
		public:
			cluster_node0() { bDirRel_=0; bUtSet_=0; subSet_=0;
					U_  = gsl_matrix_calloc( DIM, DIM );  t_ = gsl_vector_calloc( DIM );
					iU_ = gsl_matrix_calloc( DIM, DIM ); it_ = gsl_vector_calloc( DIM ); sgn_=1; }

			void			assign_sub( cluster0 c1, cluster0 c2 );
			bool			subSet() { return (subSet_==1); };

			std::vector<int>	find_centroid_relation( void );

			std::vector<int>	find_simple_relation( void );

			std::pair< particles,
			std::vector<int> >	apply_fragment_trans( particles, std::vector<int> );

			std::vector<int> 	get_indices(void){ return idx_; };
			std::vector<int> 	global_fragment_order(void);
			int			direction_relation(void){ return bDirRel_;};
			int			have_transform(void){ return bUtSet_; };
			particles 		apply_rot_trans( particles , int );
			particles 		apply_rot_trans( particles );
			particles		assign_particles( void ); // packs subclusters into a particles struct
			void			invert_transform(void);
			void			printUt(void){  output_matrix(U_); output_vector(t_); };
			void			printiUt(void){ output_matrix(iU_);output_vector(it_);};
			ftyp			angle_between(cluster0 c1, cluster0 c2);
			std::pair<ftyp, ftyp >	angle_between(cluster0 c1, cluster0 c2, int i, int j);
		private:
			int subSet_;
			std::pair<richanalysis::cluster0, richanalysis::cluster0 > parents_;
			std::vector<richanalysis::cluster0 > vc1_, vc2_; // subclusters
			int bDirRel_;
			std::vector<int> idx_;		// clusters
			std::vector<int> iidx_;		// clusters
			std::vector<int> cidx_;
			int N_,M_,I_,J_;
			int bUtSet_;
			int sgn_;
			gmat *U_,*iU_;
			gvec *t_,*it_;
	};

}
<|endoftext|>


<commit_before>#include <algorithm>
#include <cpr/cpr.h>
#include <utils.h>
#include "command.h"
#include "../CmdHandler.h"
#include "../option.h"
#include "../stringparse.h"
#include "../strfmt.h"

/* full name of the command */
CMDNAME("ge");
/* description of the command */
CMDDESCR("look up item prices");
/* command usage synopsis */
CMDUSAGE("$ge [-n AMT] ITEM");

static const char *EXCHANGE_API =
	"https://api.rsbuddy.com/grandExchange?a=guidePrice&i=";

static int64_t extract_price(const char *resp);

/* ge: look up item prices */
int CmdHandler::ge(char *out, struct command *c)
{
	int64_t amt, price;
	cpr::Response resp;
	Json::Value item;
	char buf[MAX_MSG];
	char num[RSN_BUF];
	char *s;

	int opt;
	static struct l_option long_opts[] = {
		{ "amount", REQ_ARG, 'n' },
		{ "help", NO_ARG, 'h' },
		{ 0, 0, 0 }
	};

	if (!m_GEReader.active()) {
		_sprintf(out, MAX_MSG, "%s: GE reader is inactive", c->argv[0]);
		return EXIT_FAILURE;
	}

	opt_init();
	amt = 1;
	while ((opt = l_getopt_long(c->argc, c->argv, "n:", long_opts)) != EOF) {
		switch (opt) {
		case 'h':
			HELPMSG(out, CMDNAME, CMDUSAGE, CMDDESCR);
			return EXIT_SUCCESS;
		case 'n':
			if (!parsenum_mult(l_optarg, &amt)) {
				_sprintf(out, MAX_MSG, "%s: invalid number: %s",
						c->argv[0], l_optarg);
				return EXIT_FAILURE;
			}
			if (amt < 0) {
				_sprintf(out, MAX_MSG, "%s: amount cannot be "
						"negative", c->argv[0]);
				return EXIT_FAILURE;
			}
			break;
		case '?':
			_sprintf(out, MAX_MSG, "%s", l_opterr());
			return EXIT_FAILURE;
		default:
			return EXIT_FAILURE;
		}
	}

	if (l_optind == c->argc) {
		USAGEMSG(out, CMDNAME, CMDUSAGE);
		return EXIT_FAILURE;
	}

	argvcat(buf, c->argc, c->argv, l_optind, 1);
	while ((s = strchr(buf, '_')))
		*s = ' ';

	/* find item in database */
	if ((item = m_GEReader.getItem(buf)).empty()) {
		_sprintf(out, MAX_MSG, "%s: item not found: %s",
				c->argv[0], buf);
		return EXIT_FAILURE;
	}

	/* read ge api and extract data */
	_sprintf(buf, MAX_MSG, "%s%d", EXCHANGE_API, item["id"].asInt());
	resp = cpr::Get(cpr::Url(buf), cpr::Header{{ "Connection", "close" }});
	strcpy(buf, resp.text.c_str());

	if ((price = extract_price(buf)) == -1) {
		_sprintf(out, MAX_MSG, "%s: could not extract price",
				c->argv[0]);
		return EXIT_FAILURE;
	}

	strcpy(out, "[GE] ");
	out = strchr(out, '\0');
	if (amt != 1) {
		_sprintf(buf, RSN_BUF, "%ld", amt);
		fmtnum(out, RSN_BUF, buf);
		strcat(out, "x ");
		out = strchr(out, '\0');
	}
	_sprintf(buf, RSN_BUF, "%ld", amt * price);
	fmtnum(num, RSN_BUF, buf);
	_sprintf(out, MAX_MSG, "%s: %s gp", item["name"].asCString(), num);

	return EXIT_SUCCESS;
}

/* extract_price: return the price of the json data in resp */
static int64_t extract_price(const char *resp)
{
	Json::Reader reader;
	Json::Value item;

	if (reader.parse(resp, item))
		return item["overall"].asInt64();
	else
		return -1;
}
<commit_msg>ge: add --hex option<commit_after>#include <algorithm>
#include <cpr/cpr.h>
#include <utils.h>
#include "command.h"
#include "../CmdHandler.h"
#include "../option.h"
#include "../stringparse.h"
#include "../strfmt.h"

/* full name of the command */
CMDNAME("ge");
/* description of the command */
CMDDESCR("look up item prices");
/* command usage synopsis */
CMDUSAGE("$ge [-n AMT] ITEM");

static const char *EXCHANGE_API =
	"https://api.rsbuddy.com/grandExchange?a=guidePrice&i=";

static int64_t extract_price(const char *resp);

/* ge: look up item prices */
int CmdHandler::ge(char *out, struct command *c)
{
	int64_t amt, price;
	cpr::Response resp;
	Json::Value item;
	char buf[MAX_MSG];
	char num[RSN_BUF];
	char *s;

	int opt, hex;
	static struct l_option long_opts[] = {
		{ "amount", REQ_ARG, 'n' },
		{ "help", NO_ARG, 'h' },
		{ "hex", NO_ARG, 'z' },
		{ 0, 0, 0 }
	};

	if (!m_GEReader.active()) {
		_sprintf(out, MAX_MSG, "%s: GE reader is inactive", c->argv[0]);
		return EXIT_FAILURE;
	}

	opt_init();
	amt = 1;
	hex = 0;
	while ((opt = l_getopt_long(c->argc, c->argv, "n:", long_opts)) != EOF) {
		switch (opt) {
		case 'h':
			HELPMSG(out, CMDNAME, CMDUSAGE, CMDDESCR);
			return EXIT_SUCCESS;
		case 'n':
			if (!parsenum_mult(l_optarg, &amt)) {
				_sprintf(out, MAX_MSG, "%s: invalid number: %s",
						c->argv[0], l_optarg);
				return EXIT_FAILURE;
			}
			if (amt < 0) {
				_sprintf(out, MAX_MSG, "%s: amount cannot be "
						"negative", c->argv[0]);
				return EXIT_FAILURE;
			}
			break;
		case 'z':
			hex = 1;
			break;
		case '?':
			_sprintf(out, MAX_MSG, "%s", l_opterr());
			return EXIT_FAILURE;
		default:
			return EXIT_FAILURE;
		}
	}

	if (l_optind == c->argc) {
		USAGEMSG(out, CMDNAME, CMDUSAGE);
		return EXIT_FAILURE;
	}

	argvcat(buf, c->argc, c->argv, l_optind, 1);
	while ((s = strchr(buf, '_')))
		*s = ' ';

	/* find item in database */
	if ((item = m_GEReader.getItem(buf)).empty()) {
		_sprintf(out, MAX_MSG, "%s: item not found: %s",
				c->argv[0], buf);
		return EXIT_FAILURE;
	}

	/* read ge api and extract data */
	_sprintf(buf, MAX_MSG, "%s%d", EXCHANGE_API, item["id"].asInt());
	resp = cpr::Get(cpr::Url(buf), cpr::Header{{ "Connection", "close" }});
	strcpy(buf, resp.text.c_str());

	if ((price = extract_price(buf)) == -1) {
		_sprintf(out, MAX_MSG, "%s: could not extract price",
				c->argv[0]);
		return EXIT_FAILURE;
	}

	strcpy(out, "[GE] ");
	out = strchr(out, '\0');
	if (amt != 1) {
		if (hex) {
			_sprintf(out, RSN_BUF, "%lX", amt);
		} else {
			_sprintf(buf, RSN_BUF, "%ld", amt);
			fmtnum(out, RSN_BUF, buf);
		}
		strcat(out, "x ");
		out = strchr(out, '\0');
	}
	if (hex) {
		_sprintf(num, RSN_BUF, "0x%lX", (uint64_t)(amt * price));
	} else {
		_sprintf(buf, RSN_BUF, "%ld", amt * price);
		fmtnum(num, RSN_BUF, buf);
	}
	_sprintf(out, MAX_MSG, "%s: %s gp", item["name"].asCString(), num);

	return EXIT_SUCCESS;
}

/* extract_price: return the price of the json data in resp */
static int64_t extract_price(const char *resp)
{
	Json::Reader reader;
	Json::Value item;

	if (reader.parse(resp, item))
		return item["overall"].asInt64();
	else
		return -1;
}
<|endoftext|>


<commit_before>#include "mapnik_projection.hpp"
#include "utils.hpp"

Persistent<FunctionTemplate> Projection::constructor;

void Projection::Initialize(Handle<Object> target) {

    HandleScope scope;

    constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(Projection::New));
    constructor->InstanceTemplate()->SetInternalFieldCount(1);
    constructor->SetClassName(String::NewSymbol("Projection"));

    NODE_SET_PROTOTYPE_METHOD(constructor, "forward", forward);
    NODE_SET_PROTOTYPE_METHOD(constructor, "inverse", inverse);

    target->Set(String::NewSymbol("Projection"),constructor->GetFunction());
}

Projection::Projection(std::string const& name) :
  ObjectWrap(),
  projection_(new mapnik::projection(name)) {}

Projection::~Projection()
{
}

Handle<Value> Projection::New(const Arguments& args)
{
  HandleScope scope;

  if (!(args.Length() > 0 && args[0]->IsString()))
    return ThrowException(Exception::TypeError(
      String::New("please provide a proj4 intialization string")));
  try
  {
      Projection* p = new Projection(TOSTR(args[0]));
      p->Wrap(args.This());
      return args.This();
  }
  catch (const mapnik::proj_init_error & ex )
  {
    return ThrowException(Exception::Error(
      String::New(ex.what())));
  }
}

Handle<Value> Projection::forward(const Arguments& args)
{
  HandleScope scope;
  Projection* p = ObjectWrap::Unwrap<Projection>(args.This());

  if (!args.Length() == 1)
    return ThrowException(Exception::Error(
      String::New("Must provide an array of either [x,y] or [minx,miny,maxx,maxy]")));
  else
  {
      if (!args[0]->IsArray())
          return ThrowException(Exception::Error(
             String::New("Must provide an array of either [x,y] or [minx,miny,maxx,maxy]")));

      Local<Array> a = Local<Array>::Cast(args[0]);
      uint32_t array_length = a->Length();
      if (array_length == 2)
      {
          double x = a->Get(0)->NumberValue();
          double y = a->Get(1)->NumberValue();
          p->projection_->forward(x,y);
          Local<Array> a = Array::New(2);
          a->Set(0, Number::New(x));
          a->Set(1, Number::New(y));
          return scope.Close(a);
      }
      else if (array_length == 4)
      {
          double minx = a->Get(0)->NumberValue();
          double miny = a->Get(1)->NumberValue();
          double maxx = a->Get(2)->NumberValue();
          double maxy = a->Get(3)->NumberValue();
          p->projection_->forward(minx,miny);
          p->projection_->forward(maxx,maxy);
          Local<Array> a = Array::New(4);
          a->Set(0, Number::New(minx));
          a->Set(1, Number::New(miny));
          a->Set(2, Number::New(maxx));
          a->Set(3, Number::New(maxy));
          return scope.Close(a);
      }
      else
          return ThrowException(Exception::Error(
             String::New("Must provide an array of either [x,y] or [minx,miny,maxx,maxy]")));

  }
}

Handle<Value> Projection::inverse(const Arguments& args)
{
  HandleScope scope;
  Projection* p = ObjectWrap::Unwrap<Projection>(args.This());

  if (!args.Length() == 1)
    return ThrowException(Exception::Error(
      String::New("Must provide an array of either [x,y] or [minx,miny,maxx,maxy]")));
  else
  {
      if (!args[0]->IsArray())
          return ThrowException(Exception::Error(
             String::New("Must provide an array of either [x,y] or [minx,miny,maxx,maxy]")));

      Local<Array> a = Local<Array>::Cast(args[0]);
      uint32_t array_length = a->Length();
      if (array_length == 2)
      {
          double x = a->Get(0)->NumberValue();
          double y = a->Get(1)->NumberValue();
          p->projection_->inverse(x,y);
          Local<Array> a = Array::New(2);
          a->Set(0, Number::New(x));
          a->Set(1, Number::New(y));
          return scope.Close(a);
      }
      else if (array_length == 4)
      {
          double minx = a->Get(0)->NumberValue();
          double miny = a->Get(1)->NumberValue();
          double maxx = a->Get(2)->NumberValue();
          double maxy = a->Get(3)->NumberValue();
          p->projection_->inverse(minx,miny);
          p->projection_->inverse(maxx,maxy);
          Local<Array> a = Array::New(4);
          a->Set(0, Number::New(minx));
          a->Set(1, Number::New(miny));
          a->Set(2, Number::New(maxx));
          a->Set(3, Number::New(maxy));
          return scope.Close(a);
      }
      else
          return ThrowException(Exception::Error(
             String::New("Must provide an array of either [x,y] or [minx,miny,maxx,maxy]")));

  }
}

<commit_msg>correct argument checking for mapnik.Projection<commit_after>#include "mapnik_projection.hpp"
#include "utils.hpp"

Persistent<FunctionTemplate> Projection::constructor;

void Projection::Initialize(Handle<Object> target) {

    HandleScope scope;

    constructor = Persistent<FunctionTemplate>::New(FunctionTemplate::New(Projection::New));
    constructor->InstanceTemplate()->SetInternalFieldCount(1);
    constructor->SetClassName(String::NewSymbol("Projection"));

    NODE_SET_PROTOTYPE_METHOD(constructor, "forward", forward);
    NODE_SET_PROTOTYPE_METHOD(constructor, "inverse", inverse);

    target->Set(String::NewSymbol("Projection"),constructor->GetFunction());
}

Projection::Projection(std::string const& name) :
  ObjectWrap(),
  projection_(new mapnik::projection(name)) {}

Projection::~Projection()
{
}

Handle<Value> Projection::New(const Arguments& args)
{
  HandleScope scope;

    if (!args.IsConstructCall())
        return ThrowException(String::New("Cannot call constructor as function, you need to use 'new' keyword"));

  if (!args.Length() > 0 || !args[0]->IsString()) {
      return ThrowException(Exception::TypeError(
        String::New("please provide a proj4 intialization string")));
  }
  try
  {
      Projection* p = new Projection(TOSTR(args[0]));
      p->Wrap(args.This());
      return args.This();
  }
  catch (const mapnik::proj_init_error & ex )
  {
    return ThrowException(Exception::Error(
      String::New(ex.what())));
  }
}

Handle<Value> Projection::forward(const Arguments& args)
{
  HandleScope scope;
  Projection* p = ObjectWrap::Unwrap<Projection>(args.This());

  if (!args.Length() == 1)
    return ThrowException(Exception::Error(
      String::New("Must provide an array of either [x,y] or [minx,miny,maxx,maxy]")));
  else
  {
      if (!args[0]->IsArray())
          return ThrowException(Exception::Error(
             String::New("Must provide an array of either [x,y] or [minx,miny,maxx,maxy]")));

      Local<Array> a = Local<Array>::Cast(args[0]);
      uint32_t array_length = a->Length();
      if (array_length == 2)
      {
          double x = a->Get(0)->NumberValue();
          double y = a->Get(1)->NumberValue();
          p->projection_->forward(x,y);
          Local<Array> a = Array::New(2);
          a->Set(0, Number::New(x));
          a->Set(1, Number::New(y));
          return scope.Close(a);
      }
      else if (array_length == 4)
      {
          double minx = a->Get(0)->NumberValue();
          double miny = a->Get(1)->NumberValue();
          double maxx = a->Get(2)->NumberValue();
          double maxy = a->Get(3)->NumberValue();
          p->projection_->forward(minx,miny);
          p->projection_->forward(maxx,maxy);
          Local<Array> a = Array::New(4);
          a->Set(0, Number::New(minx));
          a->Set(1, Number::New(miny));
          a->Set(2, Number::New(maxx));
          a->Set(3, Number::New(maxy));
          return scope.Close(a);
      }
      else
          return ThrowException(Exception::Error(
             String::New("Must provide an array of either [x,y] or [minx,miny,maxx,maxy]")));

  }
}

Handle<Value> Projection::inverse(const Arguments& args)
{
  HandleScope scope;
  Projection* p = ObjectWrap::Unwrap<Projection>(args.This());

  if (!args.Length() == 1)
    return ThrowException(Exception::Error(
      String::New("Must provide an array of either [x,y] or [minx,miny,maxx,maxy]")));
  else
  {
      if (!args[0]->IsArray())
          return ThrowException(Exception::Error(
             String::New("Must provide an array of either [x,y] or [minx,miny,maxx,maxy]")));

      Local<Array> a = Local<Array>::Cast(args[0]);
      uint32_t array_length = a->Length();
      if (array_length == 2)
      {
          double x = a->Get(0)->NumberValue();
          double y = a->Get(1)->NumberValue();
          p->projection_->inverse(x,y);
          Local<Array> a = Array::New(2);
          a->Set(0, Number::New(x));
          a->Set(1, Number::New(y));
          return scope.Close(a);
      }
      else if (array_length == 4)
      {
          double minx = a->Get(0)->NumberValue();
          double miny = a->Get(1)->NumberValue();
          double maxx = a->Get(2)->NumberValue();
          double maxy = a->Get(3)->NumberValue();
          p->projection_->inverse(minx,miny);
          p->projection_->inverse(maxx,maxy);
          Local<Array> a = Array::New(4);
          a->Set(0, Number::New(minx));
          a->Set(1, Number::New(miny));
          a->Set(2, Number::New(maxx));
          a->Set(3, Number::New(maxy));
          return scope.Close(a);
      }
      else
          return ThrowException(Exception::Error(
             String::New("Must provide an array of either [x,y] or [minx,miny,maxx,maxy]")));

  }
}

<|endoftext|>