Exemple #1
0
/* Get the font description object defined in swfFont.h */
static pfontDesc swfGetFontDesc(const pGEcontext gc, pswfDesc swfInfo)
{
    int gcfontface = gc->fontface;
    pfontDesc font;
    
    SEXP fontList;
    SEXP fontNames;
    SEXP extPtr;
    int i, listLen;
    
    /* Font list is .pkg.env$.font.list, defined in font.R */
    PROTECT(fontList = Rf_findVar(install(".font.list"), swfInfo->pkgEnv));
    UNPROTECT(1);
    fontNames = GET_NAMES(fontList);
    listLen = Rf_length(fontList);
    for(i = 0; i < listLen; i++)
    {
        if(strcmp(gc->fontfamily, CHAR(STRING_ELT(fontNames, i))) == 0)
        {
            break;
        }
    }
    if(i == listLen) i = 0;
    if(gcfontface < 1 || gcfontface > 5) gcfontface = 1;
    
    extPtr = VECTOR_ELT(VECTOR_ELT(fontList, i), gcfontface - 1);
    font = (pfontDesc) R_ExternalPtrAddr(extPtr);
    
    return font;
}
Exemple #2
0
SEXP R_get_function(char *fname)
{
  SEXP expr, res;
  int error;

  printf("fname: %s\n", fname);

  SEXP robj = Rf_findVar(Rf_install(fname), R_GlobalEnv);
  if (robj == R_UnboundValue)
    return R_NilValue;
  robj = Rf_findFun(Rf_install(fname), R_GlobalEnv);

  printf("VALUE: \n");
  Rf_PrintValue(robj);


  PROTECT(expr = allocVector(LANGSXP, 2));
  SETCAR(expr, install("get"));
  SETCAR(CDR(expr), Rf_mkString(fname));
  res = R_tryEval(expr, R_GlobalEnv, &error);
  //  Rf_PrintValue(res);
  if (error) {
    //    rb_raise(rb_eRException, "R execution exception. %s", expr);
    UNPROTECT(1);
    return NULL;
  }

  UNPROTECT(1);
  return res;
}
Exemple #3
0
SEXP GetVarFromPkgEnv(const char *varName, const char *pkgName)
{
    /* See grDevices/src/devPS getFontDB() */
    SEXP pkgNS, pkgEnv, var;
    PROTECT(pkgNS = R_FindNamespace(ScalarString(mkChar(pkgName))));
    PROTECT(pkgEnv = Rf_findVar(install(".pkg.env"), pkgNS));
    if(TYPEOF(pkgEnv) == PROMSXP) {
        PROTECT(pkgEnv);
        pkgEnv = eval(pkgEnv, pkgNS);
        UNPROTECT(1);
    }
    PROTECT(var = Rf_findVar(install(varName), pkgEnv));
    UNPROTECT(3);
    
    return var;
}
Exemple #4
0
/* Autoload default packages and names from autoloads.h
 *
 * This function behaves in almost every way like
 * R's autoload:
 * function (name, package, reset = FALSE, ...)
 * {
 *     if (!reset && exists(name, envir = .GlobalEnv, inherits = FALSE))
 *        stop("an object with that name already exists")
 *     m <- match.call()
 *     m[[1]] <- as.name("list")
 *     newcall <- eval(m, parent.frame())
 *     newcall <- as.call(c(as.name("autoloader"), newcall))
 *     newcall$reset <- NULL
 *     if (is.na(match(package, .Autoloaded)))
 *        assign(".Autoloaded", c(package, .Autoloaded), env = .AutoloadEnv)
 *     do.call("delayedAssign", list(name, newcall, .GlobalEnv,
 *                                                         .AutoloadEnv))
 *     invisible()
 * }
 *
 * What's missing is the updating of the string vector .Autoloaded with the list
 * of packages, which by my code analysis is useless and only for informational
 * purposes.
 *
 */
void autoloads(void){
    SEXP da, dacall, al, alcall, AutoloadEnv, name, package;
    int i,j, idx=0, errorOccurred, ptct;
    
    /* delayedAssign call*/
    PROTECT(da = Rf_findFun(Rf_install("delayedAssign"), R_GlobalEnv));
    PROTECT(AutoloadEnv = Rf_findVar(Rf_install(".AutoloadEnv"), R_GlobalEnv));
    if (AutoloadEnv == R_NilValue){
        fprintf(stderr,"%s: Cannot find .AutoloadEnv!\n", programName);
        exit(1);
    }
    PROTECT(dacall = allocVector(LANGSXP,5));
    SETCAR(dacall,da);
    /* SETCAR(CDR(dacall),name); */          /* arg1: assigned in loop */
    /* SETCAR(CDR(CDR(dacall)),alcall); */  /* arg2: assigned in loop */
    SETCAR(CDR(CDR(CDR(dacall))),R_GlobalEnv); /* arg3 */
    SETCAR(CDR(CDR(CDR(CDR(dacall)))),AutoloadEnv); /* arg3 */


    /* autoloader call */
    PROTECT(al = Rf_findFun(Rf_install("autoloader"), R_GlobalEnv));
    PROTECT(alcall = allocVector(LANGSXP,3));
    SET_TAG(alcall, R_NilValue); /* just like do_ascall() does */
    SETCAR(alcall,al);
    /* SETCAR(CDR(alcall),name); */          /* arg1: assigned in loop */
    /* SETCAR(CDR(CDR(alcall)),package); */  /* arg2: assigned in loop */

    ptct = 5;
    for(i = 0; i < packc; i++){
        idx += (i != 0)? packobjc[i-1] : 0;
        for (j = 0; j < packobjc[i]; j++){
            /*printf("autload(%s,%s)\n",packobj[idx+j],pack[i]);*/
            
            PROTECT(name = NEW_CHARACTER(1));
            PROTECT(package = NEW_CHARACTER(1));
            SET_STRING_ELT(name, 0, COPY_TO_USER_STRING(packobj[idx+j]));
            SET_STRING_ELT(package, 0, COPY_TO_USER_STRING(pack[i]));
            
            /* Set up autoloader call */
            PROTECT(alcall = allocVector(LANGSXP,3));
            SET_TAG(alcall, R_NilValue); /* just like do_ascall() does */
            SETCAR(alcall,al);
            SETCAR(CDR(alcall),name);
            SETCAR(CDR(CDR(alcall)),package);

            /* Setup delayedAssign call */
            SETCAR(CDR(dacall),name);
            SETCAR(CDR(CDR(dacall)),alcall);
            
            R_tryEval(dacall,R_GlobalEnv,&errorOccurred);
            if (errorOccurred){
                fprintf(stderr,"%s: Error calling delayedAssign!\n", programName);
                exit(1);
            }
            
            ptct += 3;
        }
    }
    UNPROTECT(ptct);
}
Exemple #5
0
/*
 * Get an R **function** object by its name. When not found, an exception is
 * raised. The checking of the length of the identifier is needed to
 * avoid R raising an error.
 */
SEXP get_fun_from_name(char *ident) {
  SEXP obj;

  /* For R not to throw an error, we must check the identifier is
     neither null nor greater than MAXIDSIZE */
  if (!*ident) {
    rb_raise(rb_eRuntimeError, "Attempt to use zero-length variable name");
    return NULL;
  }
  if (strlen(ident) > MAXIDSIZE) {
    rb_raise(rb_eRuntimeError, "symbol print-name too long");
    return NULL;
  }
  
#if R_VERSION < 0x20000
  obj = Rf_findVar(Rf_install(ident), R_GlobalEnv);
#else
  /*
   * For R-2.0.0 and later, it is necessary to use findFun to get
   * functions.  Unfortunately, calling findFun on an undefined name
   * causes a segfault!
   *
   * Solution:
   *
   * 1) Call findVar on the name
   *
   * 2) If something has the name, call findFun
   *
   * 3) Raise an error if either step 1 or 2 fails.
   */
  obj = Rf_findVar(Rf_install(ident), R_GlobalEnv);

  if (obj != R_UnboundValue)
      obj = Rf_findFun(Rf_install(ident), R_GlobalEnv);
#endif
  
  if (obj == R_UnboundValue) {
    rb_raise(rb_eNoMethodError, "R Function \"%s\" not found", ident);
    return NULL;
  }
  return obj;
}
Exemple #6
0
SEXP GetPkgEnv(const char *pkgName)
{
    SEXP pkgNS, pkgEnv;
    PROTECT(pkgNS = R_FindNamespace(ScalarString(mkChar(pkgName))));
    PROTECT(pkgEnv = Rf_findVar(install(".pkg.env"), pkgNS));
    if(TYPEOF(pkgEnv) == PROMSXP) {
        PROTECT(pkgEnv);
        pkgEnv = eval(pkgEnv, pkgNS);
        UNPROTECT(1);
    }
    UNPROTECT(2);
    
    return pkgEnv;
}
Exemple #7
0
SEXP get_fun_from_name(char *ident) {

  SEXP obj;

  if (!*ident) {
    return NULL;
  }

  obj = Rf_findVar(Rf_install(ident), R_GlobalEnv);

/*   if (obj != R_UnboundValue) { */
/*     obj = Rf_findFun(Rf_install(ident), R_GlobalEnv); */
/*   } */

  if (obj == R_UnboundValue)
    rb_raise(rb_eRobjException, "There is no symbol \"%s\".", ident);

  return obj;
}
            void plot::render_from_snapshot() {
                auto xdd = reinterpret_cast<ide_device*>(_device_desc->deviceSpecific);
                xdd->output_and_kill_file_device();

                try {
                    rhost::util::errors_to_exceptions([&] {
                        auto snapshot = Rf_findVar(Rf_install(_snapshot_varname.c_str()), R_GlobalEnv);
                        if (snapshot != R_UnboundValue && snapshot != R_NilValue) {
                            Rf_protect(snapshot);
                            pGEDevDesc ge_dev_desc = Rf_desc2GEDesc(_device_desc);
                            GEplaySnapshot(snapshot, ge_dev_desc);
                            Rf_unprotect(1);
                        } else {
                            Rf_error("Plot snapshot is missing. Plot history may be corrupted. You should restart your session.");
                        }
                    });
                } catch (rhost::util::r_error&) {
                    render_empty();
                }
            }
int execute_tool2(const wchar_t* script_path, IArray* pParameters)
{
  if (pParameters == 0)
    return 0;
  //gp_connect_impl connect;
  //if (!connect.init())
  //  return 1;

  if (pParameters == 0)
    return 0;

  _bstr_t file_path(script_path);
  long nParams = 0;
  pParameters->get_Count(&nParams);
  //CComQIPtr<IGPScriptTool>(pGPTool)->get_FileName(file_path.GetAddress());


  bool ok = true;
  int errorOccurred = 0;

  if (file_path.length() && nParams)
  {
    std::vector< CAdapt<CComPtr<IGPParameter> > > return_params;
    //ipParameters->get_Count(&n);
    SEXP arc_env = Rf_findVar(Rf_install("arc"), R_GlobalEnv);

    {
      std::vector<SEXP> in_params;
      std::vector<std::string> in_params_names;
      std::vector<SEXP> out_params;
      std::vector<std::string> out_params_names;
      tools::protect pt;

      for (int i = 0; i < nParams; i++)
      {
        CComPtr<IUnknown> ipUnk;
        pParameters->get_Element(i, &ipUnk);
        CComQIPtr<IGPParameter> ipParam(ipUnk);
        esriGPParameterDirection eD;
        ipParam->get_Direction(&eD);
        std::pair<SEXP, std::string> p = param2r(ipParam);
        if (eD == esriGPParameterDirectionInput)
        {
          in_params.push_back(pt.add(p.first));
          in_params_names.push_back(p.second);
        }
        else
        {
          out_params.push_back(pt.add(p.first));
          out_params_names.push_back(p.second);
          return_params.push_back(ipParam);
        }
      }

      SEXP p1 = tools::newVal(in_params, pt);
      tools::nameIt(p1, in_params_names);
      SEXP p2 = tools::newVal(out_params, pt);
      tools::nameIt(p2, out_params_names);

      Rf_defineVar(Rf_install(".file"), tools::newVal(file_path, pt), arc_env);
      Rf_defineVar(Rf_install(".in"),  p1, arc_env);
      Rf_defineVar(Rf_install(".out"), p2, arc_env);
    }

    const static wchar_t eval_str[] = L"arc$.ret<-local({"
      L"en<-new.env(hash=TRUE);"
      L"eval(parse(file=arc$.file), envir=en);"
      L"tool_exec<-get('tool_exec',en);"
      L"tool_exec(in_param, out_param)"
      L"},envir=list('in_param'=arc$.in,'out_param'=arc$.out))";

    ok = current_connect->eval_one(eval_str) == 1;
    current_connect->print_out(NULL, -1);

    Rf_defineVar(Rf_install(".file"), R_NilValue, arc_env);
    Rf_defineVar(Rf_install(".in"), R_NilValue, arc_env);
    Rf_defineVar(Rf_install(".out"), R_NilValue, arc_env);
    R_gc();

    //TODO: handle ok
    if (ok)
    {
      /*CComPtr<IGPMessages> ipMsgs;
      if (connect.m_ipGeoProcessor)
        connect.m_ipGeoProcessor->GetReturnMessages(&ipMsgs);
      if (ipMsgs)
      {
        VARIANT_BOOL bErr = VARIANT_FALSE;
        CComQIPtr<IGPMessage>(ipMsgs)->IsError(&bErr);
        if (bErr != VARIANT_FALSE)
          ok = false;
      }*/
      if (!return_params.empty())
      {
        //connect.m_ipGeoProcessor->Is
        SEXP ret = Rf_findVar(Rf_install(".ret"), arc_env);
        tools::vectorGeneric ret_out(ret);
        //tools::vectorGeneric ret_out(ret.get());
        for (size_t i = 0, n = return_params.size(); i < n; i++)
        {
          _bstr_t name;
          return_params[i].m_T->get_Name(name.GetAddress());
          size_t idx = ret_out.idx(std::string(name));
          if (idx != (size_t)-1)
          {
            if (!r2param(ret_out.at(idx), return_params[i].m_T))
            {
              std::wstring msg(L"failed to set output parameter - ");
              msg += name;
              current_connect->print_out(msg.c_str(), 2);
            }
          }
        }
        //TODO list
      }
      Rf_defineVar(Rf_install(".ret"), R_NilValue, arc_env);
    }
  }
  return ok ? 0 : 1;
}
// TODO: split out some of the large blocks into helper functions, to make this easier to read
void RKStructureGetter::getStructureWorker (SEXP val, const QString &name, bool misplaced, RData *storage) {
	RK_TRACE (RBACKEND);

	bool is_function = false;
	bool is_container = false;
	bool is_environment = false;
	unsigned int type = 0;
	unsigned int count;

	RK_DO (qDebug ("fetching '%s': %p, s-type %d", name.toLatin1().data(), val, TYPEOF (val)), RBACKEND, DL_DEBUG);

	PROTECT (val);
	// manually resolve any promises
	SEXP value = resolvePromise (val);
	UNPROTECT (1);		/* val */
	PROTECT (value);

	// first field: get name
	RData *namedata = new RData;
	namedata->datatype = RData::StringVector;
	namedata->length = 1;
	QString *name_dummy = new QString[1];
	name_dummy[0] = name;
	namedata->data = name_dummy;

	// get classes
	SEXP classes_s;

	if (TYPEOF (value) == LANGSXP) {	// if it's a call, we should NEVER send it through eval
		extern SEXP R_data_class (SEXP, Rboolean);
		classes_s = R_data_class (value, (Rboolean) 0);

		value = coerceVector (value, EXPRSXP);	// make sure the object is safe for everything to come
		UNPROTECT (1); /* old value */

		PROTECT (classes_s);
		PROTECT (value);
	} else {
		classes_s = callSimpleFun (class_fun, value, R_BaseEnv);
		PROTECT (classes_s);
	}

	QString *classes = SEXPToStringList (classes_s, &count);
	unsigned int num_classes = count;
	UNPROTECT (1);	/* classes_s */

	// store classes
	RData *classdata = new RData;
	classdata->datatype = RData::StringVector;
	classdata->data = classes;
	classdata->length = num_classes;

	// basic classification
	for (unsigned int i = 0; i < num_classes; ++i) {
#warning: Using is.data.frame() may be more reliable (would need to be called only on List-objects, thus no major performance hit)
		if (classes[i] == "data.frame") type |= RObject::DataFrame;
	}

	if (callSimpleBool (is_matrix_fun, value, R_BaseEnv)) type |= RObject::Matrix;
	if (callSimpleBool (is_array_fun, value, R_BaseEnv)) type |= RObject::Array;
	if (callSimpleBool (is_list_fun, value, R_BaseEnv)) type |= RObject::List;

	if (type != 0) {
		is_container = true;
		type |= RObject::Container;
	} else {
		if (callSimpleBool (is_function_fun, value, R_BaseEnv)) {
			is_function = true;
			type |= RObject::Function;
		} else if (callSimpleBool (is_environment_fun, value, R_BaseEnv)) {
			is_container = true;
			is_environment = true;
			type |= RObject::Environment;
		} else {
			type |= RObject::Variable;
			if (callSimpleBool (is_factor_fun, value, R_BaseEnv)) type |= RObject::Factor;
			else if (callSimpleBool (is_numeric_fun, value, R_BaseEnv)) type |= RObject::Numeric;
			else if (callSimpleBool (is_character_fun, value, R_BaseEnv)) type |= RObject::Character;
			else if (callSimpleBool (is_logical_fun, value, R_BaseEnv)) type |= RObject::Logical;
		}
	}
	if (misplaced) type |= RObject::Misplaced;

	// get meta data, if any
	RData *metadata = new RData;
	metadata->datatype = RData::StringVector;
	if (!Rf_isNull (Rf_getAttrib (value, meta_attrib))) {
		type |= RObject::HasMetaObject;

		SEXP meta_s = callSimpleFun (get_meta_fun, value, R_GlobalEnv);
		PROTECT (meta_s);
		metadata->data = SEXPToStringList (meta_s, &count);
		metadata->length = count;
		UNPROTECT (1);	/* meta_s */
	} else {
		metadata->length = 1;
		QString *meta_dummy = new QString[1];
		meta_dummy[0] = "";
		metadata->data = meta_dummy;
	}

	// store type
	RData *typedata = new RData;
	typedata->datatype = RData::IntVector;
	typedata->length = 1;
	int *type_dummy = new int[1];
	type_dummy[0] = type;
	typedata->data = type_dummy;

	// get dims
	int *dims;
	unsigned int num_dims;
	SEXP dims_s = callSimpleFun (dims_fun, value, R_BaseEnv);
	if (!Rf_isNull (dims_s)) {
		dims = SEXPToIntArray (dims_s, &num_dims);
	} else {
		num_dims = 1;

		unsigned int len = Rf_length (value);
		if ((len < 2) && (!is_function)) {		// suspicious. Maybe some kind of list
			SEXP len_s = callSimpleFun (length_fun, value, R_BaseEnv);
			PROTECT (len_s);
			if (Rf_isNull (len_s)) {
				dims = new int[1];
				dims[0] = len;
			} else {
				dims = SEXPToIntArray (len_s, &num_dims);
			}
			UNPROTECT (1); /* len_s */
		} else {
			dims = new int[1];
			dims[0] = len;
		}
	}

	// store dims
	RData *dimdata = new RData;
	dimdata->datatype = RData::IntVector;
	dimdata->length = num_dims;
	dimdata->data = dims;

	// store everything we have so far
	if (is_container) {
		storage->length = 6;
	} else if (is_function) {
		storage->length = 7;
	} else {
		storage->length = 5;
	}
	storage->datatype = RData::StructureVector;
	RData **res = new RData*[storage->length];
	storage->data = res;
	res[0] = namedata;
	res[1] = typedata;
	res[2] = classdata;
	res[3] = metadata;
	res[4] = dimdata;

	// now add the extra info for containers and functions
	if (is_container) {
		bool do_env = (is_environment && (++envir_depth < 2));
		bool do_cont = is_container && (!is_environment);

		RData *childdata = new RData;
		childdata->datatype = RData::StructureVector;
		childdata->length = 0;
		childdata->data = 0;
		res[5] = childdata;

		// fetch list of child names
		unsigned int childcount;
		SEXP childnames_s;
		if (do_env) {
			childnames_s = R_lsInternal (value, (Rboolean) 1);
		} else if (do_cont) {
			childnames_s = callSimpleFun (names_fun, value, R_BaseEnv);
		} else {
			childnames_s = R_NilValue; // dummy
		}
		PROTECT (childnames_s);
		QString *childnames = SEXPToStringList (childnames_s, &childcount);

		childdata->length = childcount;
		RData **children = new RData*[childcount];
		childdata->data = children;
		childdata->length = childcount;
		for (unsigned int i = 0; i < childcount; ++i) {		// in case there is an error while fetching one of the children, let's pre-initialize everything.
			children[i] = new RData;
			children[i]->data = 0;
			children[i]->length = 0;
			children[i]->datatype = RData::NoData;
		}

		if (do_env) {
			RK_DO (qDebug ("recurse into environment %s", name.toLatin1().data ()), RBACKEND, DL_DEBUG);
			for (unsigned int i = 0; i < childcount; ++i) {
				SEXP current_childname = install(CHAR(STRING_ELT(childnames_s, i)));
				PROTECT (current_childname);
				SEXP child = Rf_findVar (current_childname, value);
				PROTECT (child);

				bool child_misplaced = false;
				if (with_namespace) {
					/* before R 2.4.0, operator "::" would only work on true namespaces, not on package names (operator "::" work, if there is a namespace, and that namespace has the symbol in it)
					TODO remove once we depend on R >= 2.4.0 */
#					ifndef R_2_5
					if (Rf_isNull (namespace_envir)) {
						child_misplaced = true;
					} else {
						SEXP dummy = Rf_findVarInFrame (namespace_envir, current_childname);
						if (Rf_isNull (dummy) || (dummy == R_UnboundValue)) child_misplaced = true;
					}
					/* for R 2.4.0 or greater: operator "::" works if package has no namespace at all, or has a namespace with the symbol in it */
#					else
					if (!Rf_isNull (namespace_envir)) {
						SEXP dummy = Rf_findVarInFrame (namespace_envir, current_childname);
						if (Rf_isNull (dummy) || (dummy == R_UnboundValue)) child_misplaced = true;
					}
#					endif
				}

				getStructureSafe (child, childnames[i], child_misplaced, children[i]);
				UNPROTECT (2); /* childname, child */
			}
		} else if (do_cont) {
			RK_DO (qDebug ("recurse into list %s", name.toLatin1().data ()), RBACKEND, DL_DEBUG);
			// fewer elements than names() can happen, although I doubt it is supposed to happen.
			// see http://sourceforge.net/tracker/?func=detail&aid=3002439&group_id=50231&atid=459007
			bool may_be_special = Rf_length (value) < childcount;
			if (Rf_isList (value) && (!may_be_special)) {		// old style list
				for (unsigned int i = 0; i < childcount; ++i) {
					SEXP child = CAR (value);
					getStructureSafe (child, childnames[i], false, children[i]);
					CDR (value);
				}
			} else if (Rf_isNewList (value) && (!may_be_special)) {				// new style list
				for (unsigned int i = 0; i < childcount; ++i) {
					SEXP child = VECTOR_ELT(value, i);
					getStructureSafe (child, childnames[i], false, children[i]);
				}
			} else {		// probably an S4 object disguised as a list
				SEXP index = Rf_allocVector(INTSXP, 1);
				PROTECT (index);
				for (unsigned int i = 0; i < childcount; ++i) {
					INTEGER (index)[0] = (i + 1);
					SEXP child = callSimpleFun2 (double_brackets_fun, value, index, R_BaseEnv);
					getStructureSafe (child, childnames[i], false, children[i]);
				}
				UNPROTECT (1); /* index */
			}
		}
		UNPROTECT (1);   /* childnames_s */
		delete [] childnames;
	} else if (is_function) {
		RData *funargsdata = new RData;
		funargsdata->datatype = RData::StringVector;
		funargsdata->length = 0;
		funargsdata->data = 0;
		res[5] = funargsdata;

		RData *funargvaluesdata = new RData;
		funargvaluesdata->datatype = RData::StringVector;
		funargvaluesdata->length = 0;
		funargvaluesdata->data = 0;
		res[6] = funargvaluesdata;

// TODO: this is still the major bottleneck, but no idea, how to improve on this
		SEXP formals_s = callSimpleFun (get_formals_fun, value, R_GlobalEnv);
		PROTECT (formals_s);
		// the default values
		funargvaluesdata->data = SEXPToStringList (formals_s, &(funargvaluesdata->length));

		// the argument names
		SEXP names_s = getAttrib (formals_s, R_NamesSymbol);
		PROTECT (names_s);
		funargsdata->data = SEXPToStringList (names_s, &(funargsdata->length));

		UNPROTECT (2); /* names_s, formals_s */
	}

	UNPROTECT (1); /* value */
}
Exemple #11
0
static void nvimcom_list_env()
{
    const char *varName;
    SEXP envVarsSEXP, varSEXP;

    if(tmpdir[0] == 0)
        return;

    if(objbr_auto != 1)
        return;

#ifndef WIN32
    struct timeval begin, middle, end, tdiff1, tdiff2;
    if(verbose > 1)
        gettimeofday(&begin, NULL);
#endif

    memset(obbrbuf2, 0, obbrbufzise);
    char *p = nvimcom_strcat(obbrbuf2, ".GlobalEnv | Libraries\n\n");

    PROTECT(envVarsSEXP = R_lsInternal(R_GlobalEnv, allnames));
    for(int i = 0; i < Rf_length(envVarsSEXP); i++){
        varName = CHAR(STRING_ELT(envVarsSEXP, i));
        PROTECT(varSEXP = Rf_findVar(Rf_install(varName), R_GlobalEnv));
        if (varSEXP != R_UnboundValue) // should never be unbound
        {
            p = nvimcom_browser_line(&varSEXP, varName, "", "   ", p);
        } else {
            REprintf("Unexpected R_UnboundValue returned from R_lsInternal.\n");
        }
        UNPROTECT(1);
    }
    UNPROTECT(1);

#ifndef WIN32
    if(verbose > 1)
        gettimeofday(&middle, NULL);
#endif

    int len1 = strlen(obbrbuf1);
    int len2 = strlen(obbrbuf2);
    if(len1 != len2){
        nvimcom_write_obbr();
    } else {
        for(int i = 0; i < len1; i++){
            if(obbrbuf1[i] != obbrbuf2[i]){
                nvimcom_write_obbr();
                break;
            }
        }
    }
#ifndef WIN32
    if(verbose > 1){
        gettimeofday(&end, NULL);
        timersub(&middle, &begin, &tdiff1);
        timersub(&end, &middle, &tdiff2);
        Rprintf("Time to Update the Object Browser: %ld.%06ld + %ld.%06ld\n",
                (long int)tdiff1.tv_sec, (long int)tdiff1.tv_usec,
                (long int)tdiff2.tv_sec, (long int)tdiff2.tv_usec);
    }
#endif
}
// TODO: split out some of the large blocks into helper functions, to make this easier to read
void RKStructureGetter::getStructureWorker (SEXP val, const QString &name, int add_type_flags, RData *storage, int nesting_depth) {
	RK_TRACE (RBACKEND);

	bool at_toplevel = (toplevel_value == val);
	bool is_function = false;
	bool is_container = false;
	bool is_environment = false;
	bool no_recurse = (nesting_depth >= 2);	// TODO: should be configurable
	unsigned int type = 0;

	RK_DEBUG (RBACKEND, DL_DEBUG, "fetching '%s': %p, s-type %d", name.toLatin1().data(), val, TYPEOF (val));

	SEXP value = val;
	PROTECT_INDEX value_index;
	PROTECT_WITH_INDEX (value, &value_index);
	// manually resolve any promises
	REPROTECT (value = resolvePromise (value), value_index);

	bool is_s4 = Rf_isS4 (value);
	SEXP baseenv = R_BaseEnv;
	if (is_s4) baseenv = R_GlobalEnv;

	// first field: get name
	RData *namedata = new RData;
	namedata->setData (QStringList (name));

	// get classes
	SEXP classes_s;

	if ((TYPEOF (value) == LANGSXP) || (TYPEOF (value) == SYMSXP)) {	// if it's a call, we should NEVER send it through eval
		extern SEXP R_data_class (SEXP, Rboolean);
		classes_s = R_data_class (value, (Rboolean) 0);

		REPROTECT (value = Rf_coerceVector (value, EXPRSXP), value_index);	// make sure the object is safe for everything to come

		PROTECT (classes_s);
	} else {
		classes_s = RKRSupport::callSimpleFun (class_fun, value, baseenv);
		PROTECT (classes_s);
	}

	QStringList classes = RKRSupport::SEXPToStringList (classes_s);
	UNPROTECT (1);	/* classes_s */

	// store classes
	RData *classdata = new RData;
	classdata->setData (classes);

	// basic classification
	for (int i = classes.size () - 1; i >= 0; --i) {
#warning: Using is.data.frame() may be more reliable (would need to be called only on List-objects, thus no major performance hit)
		if (classes[i] == "data.frame") type |= RObject::DataFrame;
	}

	if (RKRSupport::callSimpleBool (is_matrix_fun, value, baseenv)) type |= RObject::Matrix;
	if (RKRSupport::callSimpleBool (is_list_fun, value, baseenv)) type |= RObject::List;

	if (type != 0) {
		is_container = true;
		type |= RObject::Container;
	} else {
		if (RKRSupport::callSimpleBool (is_function_fun, value, baseenv)) {
			is_function = true;
			type |= RObject::Function;
		} else if (RKRSupport::callSimpleBool (is_environment_fun, value, baseenv)) {
			is_container = true;
			type |= RObject::Environment;
			is_environment = true;
		} else {
			type |= RObject::Variable;
			if (RKRSupport::callSimpleBool (is_factor_fun, value, baseenv)) type |= RObject::Factor;
			else if (RKRSupport::callSimpleBool (is_numeric_fun, value, baseenv)) type |= RObject::Numeric;
			else if (RKRSupport::callSimpleBool (is_character_fun, value, baseenv)) type |= RObject::Character;
			else if (RKRSupport::callSimpleBool (is_logical_fun, value, baseenv)) type |= RObject::Logical;

			if (RKRSupport::callSimpleBool (is_array_fun, value, baseenv)) type |= RObject::Array;
		}
	}
	type |= add_type_flags;

	if (is_container) {
		if (no_recurse) {
			type |= RObject::Incomplete;
			RK_DEBUG (RBACKEND, DL_DEBUG, "Depth limit reached. Will not recurse into %s", name.toLatin1().data ());
		}
	}

	// get meta data, if any
	RData *metadata = new RData;
	if (!Rf_isNull (Rf_getAttrib (value, meta_attrib))) {
		SEXP meta_s = RKRSupport::callSimpleFun (get_meta_fun, value, R_GlobalEnv);
		PROTECT (meta_s);
		metadata->setData (RKRSupport::SEXPToStringList (meta_s));
		UNPROTECT (1);	/* meta_s */
	} else {
		metadata->setData (QStringList ());
	}

	// get dims
	RData::IntStorage dims;
	SEXP dims_s = RKRSupport::callSimpleFun (dims_fun, value, baseenv);
	if (!Rf_isNull (dims_s)) {
		dims = RKRSupport::SEXPToIntArray (dims_s);
	} else {
		unsigned int len = Rf_length (value);
		if ((len < 2) && (!is_function)) {		// suspicious. Maybe some kind of list
			SEXP len_s = RKRSupport::callSimpleFun (length_fun, value, baseenv);
			PROTECT (len_s);
			if (Rf_isNull (len_s)) {
				dims.append (len);
			} else {
				dims = RKRSupport::SEXPToIntArray (len_s);
			}
			UNPROTECT (1); /* len_s */
		} else {
			dims.append (len);
		}
	}

	// store dims
	RData *dimdata = new RData;
	dimdata->setData (dims);

	RData *slotsdata = new RData ();
	// does it have slots?
	if (is_s4) {
		type |= RObject::S4Object;
		if (no_recurse) {
			type |= RObject::Incomplete;
			RK_DEBUG (RBACKEND, DL_DEBUG, "Depth limit reached. Will not recurse into slots of %s", name.toLatin1().data ());
		} else {
			RData::RDataStorage dummy (1, 0);
			dummy[0] = new RData ();

			SEXP slots_pseudo_object = RKRSupport::callSimpleFun (rk_get_slots_fun, value, R_GlobalEnv);
			PROTECT (slots_pseudo_object);
			getStructureSafe (slots_pseudo_object, "SLOTS", RObject::PseudoObject, dummy[0], nesting_depth);	// do not increase depth for this pseudo-object
			UNPROTECT (1);

			slotsdata->setData (dummy);
		}
	}

	// store type
	RData *typedata = new RData;
	typedata->setData (RData::IntStorage (1, type));

	// store everything we have so far
	int storage_length = RObject::StorageSizeBasicInfo;
	if (is_container) {
		storage_length = RObject::StorageSizeBasicInfo + 1;
	} else if (is_function) {
		storage_length = RObject::StorageSizeBasicInfo + 2;
	}
	RData::RDataStorage res (storage_length, 0);
	res[RObject::StoragePositionName] = namedata;
	res[RObject::StoragePositionType] = typedata;
	res[RObject::StoragePositionClass] = classdata;
	res[RObject::StoragePositionMeta] = metadata;
	res[RObject::StoragePositionDims] = dimdata;
	res[RObject::StoragePositionSlots] = slotsdata;

	// now add the extra info for containers and functions
	if (is_container) {
		bool do_env = (is_environment && (!no_recurse));
		bool do_cont = is_container && (!is_environment) && (!no_recurse);

		// fetch list of child names
		SEXP childnames_s;
		if (do_env) {
			childnames_s = R_lsInternal (value, (Rboolean) 1);
		} else if (do_cont) {
			childnames_s = RKRSupport::callSimpleFun (names_fun, value, baseenv);
		} else {
			childnames_s = R_NilValue; // dummy
		}
		PROTECT (childnames_s);
		QStringList childnames = RKRSupport::SEXPToStringList (childnames_s);
		int childcount = childnames.size ();
		if (childcount > NAMED_CHILDREN_LIMIT) {
			RK_DEBUG (RBACKEND, DL_WARNING, "object %s has %d named children. Will only retrieve the first %d", name.toLatin1().data (), childcount, NAMED_CHILDREN_LIMIT);
			childcount = NAMED_CHILDREN_LIMIT;
		}

		RData::RDataStorage children (childcount, 0);
		for (int i = 0; i < childcount; ++i) {
			children[i] = new RData ();		// NOTE: RData-ctor pre-initalizes these to empty. Thus, we're safe even if there is an error while fetching one of the children.
		}

		if (do_env) {
			RK_DEBUG (RBACKEND, DL_DEBUG, "recurse into environment %s", name.toLatin1().data ());
			if (!Rf_isEnvironment (value)) {
				// some classes (ReferenceClasses) are identified as envionments by is.environment(), but are not internally ENVSXPs.
				// For these, Rf_findVar would fail.
				REPROTECT (value = RKRSupport::callSimpleFun (as_environment_fun, value, R_GlobalEnv), value_index);
			}
			for (int i = 0; i < childcount; ++i) {
				SEXP current_childname = Rf_install(CHAR(STRING_ELT(childnames_s, i)));		// ??? Why does simply using STRING_ELT(childnames_i, i) crash?
				PROTECT (current_childname);
				SEXP child = Rf_findVar (current_childname, value);
				PROTECT (child);

				bool child_misplaced = false;
				if (at_toplevel && with_namespace && (!RKRBackend::this_pointer->RRuntimeIsVersion (2, 14, 0))) {
					if (!Rf_isNull (namespace_envir)) {
						SEXP dummy = Rf_findVarInFrame (namespace_envir, current_childname);
						if (Rf_isNull (dummy) || (dummy == R_UnboundValue)) child_misplaced = true;
					}
				}

				getStructureSafe (child, childnames[i], child_misplaced ? RObject::Misplaced : 0, children[i], nesting_depth + 1);
				UNPROTECT (2); /* current_childname, child */
			}
		} else if (do_cont) {
			RK_DEBUG (RBACKEND, DL_DEBUG, "recurse into list %s", name.toLatin1().data ());
			// fewer elements than names() can happen, although I doubt it is supposed to happen.
			// see http://sourceforge.net/tracker/?func=detail&aid=3002439&group_id=50231&atid=459007
			bool may_be_special = Rf_length (value) < childcount;
			if (Rf_isList (value) && (!may_be_special)) {		// old style list
				for (int i = 0; i < childcount; ++i) {
					SEXP child = CAR (value);
					getStructureSafe (child, childnames[i], 0, children[i], nesting_depth + 1);
					CDR (value);
				}
			} else if (Rf_isNewList (value) && (!may_be_special)) {				// new style list
				for (int i = 0; i < childcount; ++i) {
					SEXP child = VECTOR_ELT(value, i);
					getStructureSafe (child, childnames[i], 0, children[i], nesting_depth + 1);
				}
			} else {		// probably an S4 object disguised as a list
				SEXP index = Rf_allocVector(INTSXP, 1);
				PROTECT (index);
				for (int i = 0; i < childcount; ++i) {
					INTEGER (index)[0] = (i + 1);
					SEXP child = RKRSupport::callSimpleFun2 (double_brackets_fun, value, index, baseenv);
					getStructureSafe (child, childnames[i], 0, children[i], nesting_depth + 1);
				}
				UNPROTECT (1); /* index */
			}
		}
		UNPROTECT (1);   /* childnames_s */

		RData *childdata = new RData;
		childdata->setData (children);
		res[RObject::StoragePositionChildren] = childdata;

		if (is_environment && at_toplevel && with_namespace) {
			RData *namespacedata = new RData;

			if (no_recurse) {
				type |= RObject::Incomplete;
				RK_DEBUG (RBACKEND, DL_DEBUG, "Depth limit reached. Will not recurse into namespace of %s", name.toLatin1().data ());
			} else {
				RData::RDataStorage dummy (1, 0);
				dummy[0] = new RData ();

				getStructureSafe (namespace_envir, "NAMESPACE", RObject::PseudoObject, dummy[0], nesting_depth+99);	// HACK: By default, do not recurse into the children of the namespace, until dealing with the namespace object itself.

				namespacedata->setData (dummy);
			}

			res.insert (RObject::StoragePositionNamespace, namespacedata);
		}
	} else if (is_function) {
// TODO: getting the formals is still a bit of a bottleneck, but no idea, how to improve on this, any further
		SEXP formals_s;
		if (Rf_isPrimitive (value)) formals_s = FORMALS (RKRSupport::callSimpleFun (args_fun, value, baseenv));	// primitives don't have formals, internally
		else formals_s = FORMALS (value);
		PROTECT (formals_s);

		// get the default values
		QStringList formals = RKRSupport::SEXPToStringList (formals_s);
		// for the most part, the implicit as.character in SEXPToStringList does a good on the formals (and it's the fastest of many options that I have tried).
		// Only for naked strings (as in 'function (a="something")'), we're missing the quotes. So we add quotes, after conversion, as needed:
		SEXP dummy = formals_s;
		const int formals_len = Rf_length (formals_s);
		for (int i = 0; i < formals_len; ++i) {
			if (TYPEOF (CAR (dummy)) == STRSXP) formals[i] = RKRSharedFunctionality::quote (formals[i]);
			dummy = CDR (dummy);
		}
		RData *funargvaluesdata = new RData;
		funargvaluesdata->setData (formals);

		// the argument names
		SEXP names_s = Rf_getAttrib (formals_s, R_NamesSymbol);
		PROTECT (names_s);
		RData *funargsdata = new RData;
		funargsdata->setData (RKRSupport::SEXPToStringList (names_s));

		UNPROTECT (2); /* names_s, formals_s */

		res[RObject::StoragePositionFunArgs] = funargsdata;
		res[RObject::StoragePositionFunValues] = funargvaluesdata;
	}

	UNPROTECT (1); /* value */

	RK_ASSERT (!res.contains (0));
	storage->setData (res);
}