#include #include #include "jri.h" #include "globals.h" #include "Rdecl.h" #include "Rcallbacks.h" #include "org_rosuda_JRI_Rengine.h" #include #ifndef Win32 #include #endif #ifdef Win32 #include #else /* from Defn.h (do we still need it? Re_CleanUp is commented out ...) extern Rboolean R_Interactive; */ #endif #if R_VERSION < R_Version(2,6,0) #ifndef checkArity #define checkArity Rf_checkArity #endif #else #define checkArity(X,Y) #endif #ifndef errorcall #define errorcall Rf_errorcall #endif /* this method is used rather for debugging purposes - it finds the correct JNIEnv for the current thread. we still have some threading issues to solve, becuase eenv!=env should never happen (uncontrolled), because concurrency issues arise */ static JavaVM *jvm=0; JNIEnv *checkEnvironment() { JNIEnv *env; jsize l; jint res; if (!jvm) { /* we're hoping that the JVM pointer won't change :P we fetch it just once */ res= JNI_GetCreatedJavaVMs(&jvm, 1, &l); if (res!=0) { fprintf(stderr, "JNI_GetCreatedJavaVMs failed! (%d)\n",(int)res); return 0; } if (l<1) { fprintf(stderr, "JNI_GetCreatedJavaVMs said there's no JVM running!\n"); return 0; } } res = (*jvm)->AttachCurrentThread(jvm, (void*) &env, 0); if (res!=0) { fprintf(stderr, "AttachCurrentThread failed! (%d)\n",(int)res); return 0; } #ifdef JRI_DEBUG if (eenv!=env) fprintf(stderr, "Warning! eenv=%x, but env=%x - different environments encountered!\n", eenv, env); #endif return env; } int Re_ReadConsole(RCCONST char *prompt, unsigned char *buf, int len, int addtohistory) { jstring r,s; jmethodID mid; JNIEnv *lenv=checkEnvironment(); if (!lenv || !engineObj) return -1; jri_checkExceptions(lenv, 1); mid=(*lenv)->GetMethodID(eenv, engineClass, "jriReadConsole", "(Ljava/lang/String;I)Ljava/lang/String;"); #ifdef JRI_DEBUG printf("jriReadconsole mid=%x\n", mid); #endif jri_checkExceptions(lenv, 0); if (!mid) return -1; s=(*lenv)->NewStringUTF(eenv, prompt); r=(jstring) (*lenv)->CallObjectMethod(lenv, engineObj, mid, s, addtohistory); jri_checkExceptions(lenv, 1); (*lenv)->DeleteLocalRef(lenv, s); jri_checkExceptions(lenv, 0); if (r) { const char *c=(*lenv)->GetStringUTFChars(lenv, r, 0); if (!c) return -1; { int l=strlen(c); strncpy((char*)buf, c, (l>len-1)?len-1:l); buf[(l>len-1)?len-1:l]=0; #ifdef JRI_DEBUG printf("Re_ReadConsole succeeded: \"%s\"\n",buf); #endif } (*lenv)->ReleaseStringUTFChars(lenv, r, c); (*lenv)->DeleteLocalRef(lenv, r); return 1; } return -1; } void Re_Busy(int which) { jmethodID mid; JNIEnv *lenv=checkEnvironment(); jri_checkExceptions(lenv, 1); mid=(*lenv)->GetMethodID(lenv, engineClass, "jriBusy", "(I)V"); jri_checkExceptions(lenv, 0); #ifdef JRI_DEBUG printf("jriBusy mid=%x\n", mid); #endif if (!mid) return; (*lenv)->CallVoidMethod(lenv, engineObj, mid, which); jri_checkExceptions(lenv, 1); } void Re_WriteConsoleEx(RCCONST char *buf, int len, int oType) { JNIEnv *lenv=checkEnvironment(); jri_checkExceptions(lenv, 1); { jstring s=(*lenv)->NewStringUTF(lenv, buf); jmethodID mid=(*lenv)->GetMethodID(lenv, engineClass, "jriWriteConsole", "(Ljava/lang/String;I)V"); jri_checkExceptions(lenv, 0); #ifdef JRI_DEBUG printf("jriWriteConsole mid=%x\n", mid); #endif if (!mid) return; (*lenv)->CallVoidMethod(lenv, engineObj, mid, s, oType); jri_checkExceptions(lenv, 1); (*lenv)->DeleteLocalRef(lenv, s); } } /* old-style WriteConsole (for old R versions only) */ void Re_WriteConsole(RCCONST char *buf, int len) { Re_WriteConsoleEx(buf, len, 0); } /* Indicate that input is coming from the console */ void Re_ResetConsole() { } /* Stdio support to ensure the console file buffer is flushed */ void Re_FlushConsole() { JNIEnv *lenv=checkEnvironment(); jri_checkExceptions(lenv, 1); { jmethodID mid=(*lenv)->GetMethodID(lenv, engineClass, "jriFlushConsole", "()V"); jri_checkExceptions(lenv, 0); #ifdef JRI_DEBUG printf("jriFlushConsole mid=%x\n", mid); #endif if (!mid) return; (*lenv)->CallVoidMethod(lenv, engineObj, mid); jri_checkExceptions(lenv, 1); } } /* Reset stdin if the user types EOF on the console. */ void Re_ClearerrConsole() { } int Re_ChooseFile(int new, char *buf, int len) { JNIEnv *lenv=checkEnvironment(); if (lenv && engineObj) { jmethodID mid; jri_checkExceptions(lenv, 1); mid=(*lenv)->GetMethodID(eenv, engineClass, "jriChooseFile", "(I)Ljava/lang/String;"); #ifdef JRI_DEBUG printf("jriChooseFile mid=%x\n", mid); #endif jri_checkExceptions(lenv, 0); if (mid) { jstring r=(jstring) (*lenv)->CallObjectMethod(lenv, engineObj, mid, new); jri_checkExceptions(lenv, 1); if (r) { int slen=0; const char *c=(*lenv)->GetStringUTFChars(lenv, r, 0); if (c) { slen=strlen(c); strncpy(buf, c, (slen>len-1)?len-1:slen); buf[(slen>len-1)?len-1:slen]=0; #ifdef JRI_DEBUG printf("Re_ChooseFile succeeded: \"%s\"\n",buf); #endif } (*lenv)->ReleaseStringUTFChars(lenv, r, c); (*lenv)->DeleteLocalRef(lenv, r); jri_checkExceptions(lenv, 0); return slen; } else return 0; } } /* "native" fallback if there's no such method */ { int namelen; char *bufp; R_ReadConsole("Enter file name: ", (unsigned char *)buf, len, 0); namelen = strlen(buf); bufp = &buf[namelen - 1]; while (bufp >= buf && isspace((int)*bufp)) *bufp-- = '\0'; return strlen(buf); } } void Re_ShowMessage(RCCONST char *buf) { jstring s; jmethodID mid; JNIEnv *lenv=checkEnvironment(); jri_checkExceptions(lenv, 1); s=(*lenv)->NewStringUTF(lenv, buf); mid=(*lenv)->GetMethodID(lenv, engineClass, "jriShowMessage", "(Ljava/lang/String;)V"); jri_checkExceptions(lenv, 0); #ifdef JGR_DEBUG printf("jriShowMessage mid=%x\n", mid); #endif if (mid) (*lenv)->CallVoidMethod(eenv, engineObj, mid, s); jri_checkExceptions(lenv, 0); if (s) (*lenv)->DeleteLocalRef(eenv, s); } void Re_read_history(char *buf) { } void Re_loadhistory(SEXP call, SEXP op, SEXP args, SEXP env) { jmethodID mid; jstring s; JNIEnv *lenv=checkEnvironment(); jri_checkExceptions(lenv, 1); mid=(*lenv)->GetMethodID(lenv, engineClass, "jriLoadHistory", "(Ljava/lang/String;)V"); jri_checkExceptions(lenv, 0); #ifdef JRI_DEBUG printf("jriLoadHistory mid=%x\n", mid); #endif if (!mid) { #ifdef JRI_DEBUG printf("can't find jriLoadHistory method\n"); #endif return; } { SEXP sfile; const char *p; checkArity(op, args); sfile = CAR(args); if (!isString(sfile) || LENGTH(sfile) < 1) errorcall(call, "invalid file argument"); p = R_ExpandFileName((char*)CHAR(STRING_ELT(sfile, 0))); if(strlen(p) > PATH_MAX - 1) errorcall(call, "file argument is too long"); s=(*lenv)->NewStringUTF(lenv, p); } (*lenv)->CallVoidMethod(lenv, engineObj, mid, s); jri_checkExceptions(lenv, 1); if (s) (*lenv)->DeleteLocalRef(lenv, s); } void Re_savehistory(SEXP call, SEXP op, SEXP args, SEXP env) { jmethodID mid; jstring s; JNIEnv *lenv=checkEnvironment(); jri_checkExceptions(lenv, 1); mid=(*lenv)->GetMethodID(lenv, engineClass, "jriSaveHistory", "(Ljava/lang/String;)V"); jri_checkExceptions(lenv, 0); #ifdef JRI_DEBUG printf("jriSaveHistory mid=%x\n", mid); #endif if (!mid) errorcall(call, "can't find jriSaveHistory method"); { SEXP sfile; const char *p; checkArity(op, args); sfile = CAR(args); if (!isString(sfile) || LENGTH(sfile) < 1) errorcall(call, "invalid file argument"); p = R_ExpandFileName(CHAR(STRING_ELT(sfile, 0))); if(strlen(p) > PATH_MAX - 1) errorcall(call, "file argument is too long"); s=(*lenv)->NewStringUTF(lenv, p); } (*lenv)->CallVoidMethod(lenv, engineObj, mid, s); jri_checkExceptions(lenv, 1); if (s) (*lenv)->DeleteLocalRef(lenv, s); /* strcpy(file, p); write_history(file); history_truncate_file(file, R_HistorySize); */ } /* R_CleanUp is invoked at the end of the session to give the user the option of saving their data. If ask == SA_SAVEASK the user should be asked if possible (and this option should not occur in non-interactive use). If ask = SA_SAVE or SA_NOSAVE the decision is known. If ask = SA_DEFAULT use the SaveAction set at startup. In all these cases run .Last() unless quitting is cancelled. If ask = SA_SUICIDE, no save, no .Last, possibly other things. */ /* void Re_CleanUp(SA_TYPE saveact, int status, int runLast) { unsigned char buf[1024]; char * tmpdir; if(saveact == SA_DEFAULT) saveact = SaveAction; if(saveact == SA_SAVEASK) { if(R_Interactive) { qask: R_ClearerrConsole(); R_FlushConsole(); R_ReadConsole("Save workspace image? [y/n/c]: ", buf, 128, 0); switch (buf[0]) { case 'y': case 'Y': saveact = SA_SAVE; break; case 'n': case 'N': saveact = SA_NOSAVE; break; case 'c': case 'C': jump_to_toplevel(); break; default: goto qask; } } else saveact = SaveAction; } switch (saveact) { case SA_SAVE: if(runLast) R_dot_Last(); if(R_DirtyImage) R_SaveGlobalEnv(); stifle_history(R_HistorySize); write_history(R_HistoryFile); break; case SA_NOSAVE: if(runLast) R_dot_Last(); break; case SA_SUICIDE: default: break; } R_RunExitFinalizers(); CleanEd(); if(saveact != SA_SUICIDE) KillAllDevices(); if((tmpdir = getenv("R_SESSION_TMPDIR"))) { snprintf((char *)buf, 1024, "rm -rf %s", tmpdir); R_system((char *)buf); } if(saveact != SA_SUICIDE && R_CollectWarnings) PrintWarnings(); fpu_setup(FALSE); exit(status); } void Rstd_Suicide(char *s) { REprintf("Fatal error: %s\n", s); R_CleanUp(SA_SUICIDE, 2, 0); } */ int Re_ShowFiles(int nfile, /* number of files */ RCCONST char **file, /* array of filenames */ RCCONST char **headers,/* the `headers' args of file.show. Printed before each file. */ RCCONST char *wtitle, /* title for window = `title' arg of file.show */ Rboolean del, /* should files be deleted after use? */ RCCONST char *pager) /* pager to be used */ { return 1; }