The R Project SVN R

Rev

Rev 44364 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

/*******************************************************************************
 *  RProxy: Connector implementation between application and R language
 *  Copyright (C) 1999--2006 Thomas Baier
 *  Copyright 2006-8 R Development Core Team
 *
 *  R_Proxy_init based on rtest.c,  Copyright (C) 1998--2000
 *                                  R Development Core Team
 *
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, a copy is available at
 *  http://www.r-project.org/Licenses/
 *
 ******************************************************************************/

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

#include <config.h>

#include <Rinternals.h>
#include <Rversion.h>
#include <Rembedded.h>
#include <R_ext/RStartup.h>
#include <R_ext/GraphicsEngine.h>
#include <graphapp.h>

#include "bdx_SEXP.h"
#include "bdx_util.h"
#include "SC_proxy.h"
#include "rproxy.h"
#include "rproxy_impl.h"

# include <R_ext/Parse.h>

#define TRCBUFSIZE 2048

struct _R_Proxy_init_parameters g_R_Proxy_init_parameters = { 0 };

/* calls into the R DLL */
extern char *getRHOME(void);

int R_Proxy_Graphics_Driver (pDevDesc pDD,
                 char* pDisplay,
                 double pWidth,
                 double pHeight,
                 double pPointSize);

extern SC_CharacterDevice* __output_device;

/* trace to DebugView */
int R_Proxy_printf(char const* pFormat,...)
{
  static char __tracebuf[TRCBUFSIZE];

  va_list lArgs;
  va_start(lArgs, pFormat);
  vsnprintf(__tracebuf,TRCBUFSIZE, pFormat, lArgs);
  OutputDebugString(__tracebuf);
  return 0;
}

static void R_Proxy_askok (const char* pMsg)
{
  askok(pMsg);
  return;
}

static int R_Proxy_askyesnocancel (const char* pMsg)
{
  return YES;
}

static int 
R_Proxy_ReadConsole(const char *prompt, char *buf, int len, int addtohistory)
{
  return 0;
}

static void R_Proxy_WriteConsole(const char *buf, int len)
{
  if (__output_device) {
    __output_device->vtbl->write_string (__output_device,buf);
  }
}

static void R_Proxy_CallBack(void)
{
    /* called during i/o, eval, graphics in ProcessEvents */
}

static void R_Proxy_Busy(int which)
{
    /* set a busy cursor ... in which = 1, unset if which = 0 */
}

/* 00-02-18 | baier | parse parameter string and fill parameter structure */
/* 06-06-18 | baier | parse parameter "dm" */
int R_Proxy_parse_parameters (char const* pParameterString,
                  struct _R_Proxy_init_parameters* pParameterStruct)
{
  /*
   * parameter string is of the form name1=value1;name2=value2;...
   *
   * currently recognized parameter names (case-sensitive):
   *
   *   (obsolete) NSIZE ... number of cons cells, (unsigned int) parameter
   *   (obsolete) VSIZE ... size of vector heap, (unsigned int) parameter
   *   dm ...... data mode (unsigned long, see below)
   */
  int lDone = 0;
  char const* lParameterStart = pParameterString;
  int lIndexOfSemicolon = 0;
  char* lTmpBuffer = NULL;
  char* lPosOfSemicolon = NULL;

  RPROXY_TRACE(printf("R_Proxy_parse_parameters(\"%s\")\n",pParameterString));

  while (!lDone) {
    /*
     * dm: data mode?
     * --------------
     *
     *   0 ... default data transfer mode
     *   1 ... read +Inf and -Inf in double representation
     */
    if(strncmp (lParameterStart,"dm=",3) == 0) {
      RPROXY_TRACE(printf("param dm found, parsing\n"));
      lParameterStart += 3;
      
      lPosOfSemicolon = strchr (lParameterStart,';');
      lIndexOfSemicolon = lPosOfSemicolon - lParameterStart;
      
      if (lPosOfSemicolon) {
    lTmpBuffer = malloc (lIndexOfSemicolon + 1); /* to catch NSIZE=; */
    strncpy (lTmpBuffer,lParameterStart,lIndexOfSemicolon);
    *(lTmpBuffer + lIndexOfSemicolon) = 0x0;
    bdx_set_datamode(atol(lTmpBuffer));
    if(pParameterStruct) {
      pParameterStruct->dm = atol (lTmpBuffer);
    }
    free (lTmpBuffer);
    lParameterStart += lIndexOfSemicolon + 1;
      } else {
    bdx_set_datamode(atol(lParameterStart));
    if(pParameterStruct) {
      pParameterStruct->dm = atol(lParameterStart);
    }
    lDone = 1;
      }
    } else if (strncmp (lParameterStart,"REUSER",6) == 0) {
      if(pParameterStruct) {
    pParameterStruct->reuseR = 1;
      }
      lParameterStart = lParameterStart + 6;
      if(*lParameterStart == ';') {
    lParameterStart++;
      }
      RPROXY_TRACE(printf("param REUSER, rest is \"%s\"\n",
              lParameterStart));
    } else {
      lDone = 1;
    }
  }

#if 0
      /* NSIZE? */
      if (strncmp (lParameterStart,"NSIZE=",6) == 0)
    {
      lParameterStart += 6;

      lPosOfSemicolon = strchr (lParameterStart,';');
      lIndexOfSemicolon = lPosOfSemicolon - lParameterStart;

      if (lPosOfSemicolon)
        {
          lTmpBuffer = malloc (lIndexOfSemicolon + 1); /* to catch NSIZE=; */
          strncpy (lTmpBuffer,lParameterStart,lIndexOfSemicolon);
          *(lTmpBuffer + lIndexOfSemicolon) = 0x0;
          pParameterStruct->nsize_valid = 1;
          pParameterStruct->nsize = atoi(lTmpBuffer);
          free (lTmpBuffer);
          lParameterStart += lIndexOfSemicolon + 1;
        }
      else
        {
          pParameterStruct->nsize_valid = 1;
          pParameterStruct->nsize = atoi(lParameterStart);
          lDone = 1;
        }
    }
      else if (strncmp (lParameterStart,"VSIZE=",6) == 0)
    {
      lParameterStart += 6;

      lPosOfSemicolon = strchr (lParameterStart,';');
      lIndexOfSemicolon = lPosOfSemicolon - lParameterStart;

      if (lPosOfSemicolon)
        {
          lTmpBuffer = malloc (lIndexOfSemicolon + 1); /* to catch VSIZE=; */
          strncpy (lTmpBuffer,lParameterStart,lIndexOfSemicolon);
          *(lTmpBuffer + lIndexOfSemicolon) = 0x0;
          pParameterStruct->vsize_valid = 1;
          pParameterStruct->vsize = atoi (lTmpBuffer);
          free (lTmpBuffer);
          lParameterStart += lIndexOfSemicolon + 1;
        }
      else
        {
          pParameterStruct->vsize_valid = 1;
          pParameterStruct->vsize = atoi (lParameterStart);
          lDone = 1;
        }
    }
#endif

  return 0;
}

/* 00-02-18 | baier | R_Proxy_init() now takes parameter string, parse it */
/* 03-06-01 | baier | now we add %R_HOME%\bin to %PATH% */
/* 06-06-18 | baier | parameter parsing enabled in parent function */
int R_Proxy_init (char const* pParameterString)
{
  structRstart rp;
  Rstart Rp = &rp;
  char Rversion[25];
  static char RHome[MAX_PATH];

  snprintf(Rversion, 25, "%s.%s", R_MAJOR, R_MINOR);
  if(strncmp(getDLLVersion(), Rversion, 25) != 0) {
    fprintf(stderr, "Error: R.DLL version does not match\n");
    return SC_PROXY_ERR_UNKNOWN;
  }

  R_DefParams(Rp);

  /* <FIXME> the documented interface is get_R_HOME() */

  /* first, try process-local environment space (CRT) */
  if (getenv("R_HOME")) {
      strcpy(RHome, getenv("R_HOME"));
  } else {
    /* get variable from process-local environment space (Windows API) */
      if (GetEnvironmentVariable ("R_HOME", RHome, sizeof (RHome)) == 0) {
    /* not found, fall back to getRHOME() */
    strcpy(RHome, getRHOME());
      }
    }

  /* now we add %R_HOME%\bin to %PATH% (for dynamically loaded modules there) */
  {
    char buf[2048];
    snprintf(buf, 2048, "PATH=%s\\bin;%s",RHome,getenv("PATH"));
    putenv(buf);
  }

  Rp->rhome = RHome;
  Rp->home = getRUser();
  Rp->CharacterMode = LinkDLL;
  Rp->ReadConsole = R_Proxy_ReadConsole;
  Rp->WriteConsole = R_Proxy_WriteConsole;
  Rp->CallBack = R_Proxy_CallBack;
  Rp->ShowMessage = R_Proxy_askok;
  Rp->YesNoCancel = R_Proxy_askyesnocancel;
  Rp->Busy = R_Proxy_Busy;
  Rp->R_Quiet = 1;
  Rp->RestoreAction = SA_NORESTORE;
  Rp->SaveAction = SA_NOSAVE; /* had 2, with comment 'no save' which is 3 */

  R_SetParams(Rp);
  R_set_command_line_arguments(0, NULL);

  GA_initapp(0, 0);
  readconsolecfg();
  setup_Rmainloop();
  R_ReplDLLinit();

  return SC_PROXY_OK;
}

int R_Proxy_evaluate (char const* pCmd, BDX_Data** pData)
{
    SEXP lSexp;
    int lRc = SC_PROXY_OK, evalError = 0;
    ParseStatus lStatus;
    SEXP lResult;

    lSexp = R_ParseVector(mkString(pCmd), 1, &lStatus, R_NilValue);
    /* This is an EXPRSXP: we assume just one expression */

    switch (lStatus) {
    case PARSE_OK:
    PROTECT(lSexp);
    lResult = R_tryEval(VECTOR_ELT(lSexp, 0), R_GlobalEnv, &evalError);
    UNPROTECT(1);
    if(evalError) lRc = SC_PROXY_ERR_EVALUATE_STOP;
    else lRc = SEXP2BDX(lResult, pData);
    break;
    case PARSE_INCOMPLETE:
    lRc = SC_PROXY_ERR_PARSE_INCOMPLETE;
    break;
    default:
    lRc = SC_PROXY_ERR_PARSE_INVALID;
    break;
    }
    return lRc;
}

int R_Proxy_evaluate_noreturn (char const* pCmd)
{
    SEXP lSexp;
    int lRc = SC_PROXY_OK, evalError = 0;
    ParseStatus lStatus;
    SEXP lResult;

    lSexp = R_ParseVector(mkString(pCmd), 1, &lStatus, R_NilValue);
    /* It would make sense to allow multiple expressions here */
  
    switch (lStatus) {
    case PARSE_OK:
    PROTECT(lSexp);
    lResult = R_tryEval(VECTOR_ELT(lSexp, 0), R_GlobalEnv, &evalError);
    UNPROTECT(1);
    if(evalError) lRc = SC_PROXY_ERR_EVALUATE_STOP;
    else lRc = SC_PROXY_OK;
    break;
    case PARSE_INCOMPLETE:
    lRc = SC_PROXY_ERR_PARSE_INCOMPLETE;
    break;
    default:
    lRc = SC_PROXY_ERR_PARSE_INVALID;
    break;
    }
    return lRc;
}

int R_Proxy_get_symbol (char const* pSymbol, BDX_Data** pData)
{
    SEXP lVar = findVar (install((char*) pSymbol), R_GlobalEnv);

    if (lVar == R_UnboundValue) {
    RPROXY_TRACE(printf(">> %s is an unbound value\n", pSymbol));
    return SC_PROXY_ERR_INVALIDSYMBOL;
    } else if(SEXP2BDX(lVar, pData) == 0)
    return SC_PROXY_OK;
    else
    return SC_PROXY_ERR_UNSUPPORTEDTYPE;
}

/* 04-02-19 | baier | don't PROTECT strings in a vector, new data structs */
/* 04-03-02 | baier | removed traces */
/* 04-10-15 | baier | no more BDX_VECTOR (only BDX_ARRAY) */
/* 05-05-16 | baier | use BDX2SEXP, clean-up */
int R_Proxy_set_symbol (char const* pSymbol, BDX_Data const* pData)
{
  SEXP lSymbol = 0;
  SEXP lData = 0;

  if(BDX2SEXP(pData,&lData) != 0) {
    return SC_PROXY_ERR_UNSUPPORTEDTYPE;
  }
  /*  RPROXY_TRACE(printf("ok BDX2SEXP\n")); */

  /* install a new symbol or get the existing symbol */
  lSymbol = install ((char*) pSymbol);

  /* and set the data to the symbol */
  setVar(lSymbol, lData, R_GlobalEnv);

  return SC_PROXY_OK;
}

int R_Proxy_term (void)
{
  /* end_Rmainloop(); note, this never returns */
  Rf_endEmbeddedR(0);

  return SC_PROXY_OK;
}