Rev 12525 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Language for Statistical Data Analysis* Copyright (C) 1998--1999 Tiki Wan, Ross Ihaka** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*//** SYSTEM DEPENDENT CODE** This source file contains the platform dependent code for* the Macintosh port of R.** The first group of functions is concerned with reading and* writing to the system console.** int R_ReadConsole(char *prompt, char *buf, int buflen, int hist)** This function prints the given prompt at the console and then* does a gets(3)-like operation, transfering up to "buflen" characters* into the buffer "buf". The last two characters are set to "\n\0"* to preserve sanity. If "hist" is non-zero, then the line is added* to any command history which is being maintained. Note that this* is one natural place from which to run an event loop.** void R_WriteConsole(char *buf, int buflen)** This function writes the given buffer out to the console. No* special actions are required. Under Unix the characters are* just appended to stdout.** void R_ResetConsole(void)** This function is called when the system is reset after an error.* It probably isn't really needed.** void R_FlushConsole(void)** This called to flush any output to the system console. Under Unix* this is just fflush(stdout). Other systems may not need this.** void R_ClearerrConsole(void)** This function clears any errors associated with reading from the* console. In Unix is is used to clear any EOF condition associated* with stdin.** void R_Suicide(char *msg)** This function displays the given message and the causes R to* die immediately. It is used for non-recoverable errors such as* not having enough memory to launch etc. The phrase "dialog box"* springs to mind for non-unix platforms.** void R_Busy(int which)** This function invokes actions (such as change of cursor) when* R embarks on an extended computation (which=1) and when such a* state terminates (which=0).** void R_CleanUp(int ask)** This function invokes any actions which occur at system termination.** char* R_ExpandFileName(char *s)** This is a utility function which can be used to expand special* characters in file names. In Unix it's sole function is to expand* and "~"s which occur in filenames (and then only when the readline* library is available. The minimal action is to return the argument* unaltered.** void R_InitialData(void)* FILE* R_OpenInitFile(void)* FILE* R_OpenLibraryFile(char *file)* FILE* R_OpenSysInitFile(void)** The following two functions save and restore the user's global* environment. The system specific aspect of this what files* are used for this.** void R_RestoreGlobalEnv(void)* void R_SaveGlobalEnv(void)** Platform dependent functions.** SEXP do_interactive(SEXP call, SEXP op, SEXP args, SEXP rho)* SEXP do_machine(SEXP call, SEXP op, SEXP args, SEXP rho)* SEXP do_proctime(SEXP call, SEXP op, SEXP args, SEXP rho)* SEXP do_quit(SEXP call, SEXP op, SEXP args, SEXP rho)* SEXP do_system(SEXP call, SEXP op, SEXP args, SEXP rho)*/#include "Defn.h"#include "Fileio.h"#include "Graphics.h"#include "RIntf.h"#include "RFLaunch.h"#include "TFLaunch.h"#include "Defn.h" // Jago#ifdef macintosh // Jagoint pclose(FILE *fp);int pclose(FILE *fp){return(fclose(fp));}#endifvoid R_Suicide(char *s);#include <unistd.h>#include <errno.h>//extern int errno;#include <stdio.h>#include <string.h>#include <stdlib.h>#include <time.h>#include <unix.h>#include <Files.h>#include <Folders.h>#include "pathname.h"#include "helpers.h"typedef struct _EnviromentPair {char *key;char *value;} EnviromentPair;FILE * FSp_fopen(ConstFSSpecPtr spec, const char * open_mode);char *load_entry(FILE *file);EnviromentPair *ParseLine(char *line);//#include "devMacintosh.h"static int DefaultSaveAction = 0;static int DefaultRestoreAction = 1;SA_TYPE SaveAction = SA_SAVEASK;SA_TYPE RestoreAction = SA_RESTORE;Rboolean UsingReadline = TRUE;Rboolean LoadSiteFile = TRUE;Rboolean LoadInitFile = TRUE;Rboolean DebugInitFile = FALSE;/*--- I/O Support Code ---*//* These routines provide hooks for supporting console I/O.* Under raw Unix these routines simply provide a* connection to the stdio library.* Under a Motif interface the routines would be* considerably more complex.*/long start_Time, last_Time;SInt16 gAppResFileRefNum;char testBuf[ALLOW_INPUT_LENGTH];extern WindowPtr gWindowPtrArray[kMaxWindows + 2];extern void doGetPreferences(void);extern char InitFile[256];extern WindowPtr Console_Window;extern SInt16 gTextSize;void R_doErrorAlert(Str255 labelText);void StrToStr255(char* sourceText, Str255 targetText);void R_ShowMessage(char *);extern void R_Edit(char** lines, int nlines);extern void main_1 ( void );/* Fill a text buffer with user typed console input. *///extern void R_WriteConsole1(Ptr buf, SInt32 buflen);//extern void R_ReadConsole1(char*, char*, int, int);//extern void RWrite(char*);//extern void DRWrite(long);char *mac_getenv(const char *name);void R_setStartTime(void);int R_ReadConsole(char *prompt, unsigned char *buf, int len, int addtohistory){/* Fill a text buffer with user typed console input. */char buffo[1000];R_ReadConsole1(prompt, buf, len, addtohistory);buf[strlen(buf)-1] = '\n';buf[strlen(buf)] = '\0';return 1;}/* Write a text buffer to the console. *//* All system output is filtered through this routine. */void R_WriteConsole(char *buf, int len){R_WriteConsole1(buf, len);}/* Indicate that input is coming from the console *//* No longer used ??? */void R_ResetConsole(){}/* Make sure that pending output is flushed *//* Unneeded for the Macintosh */void R_FlushConsole(){}/* Clear Console EOF *//* Unneeded for the Macintosh */void R_ClearerrConsole(){}/*--- File Handling Code ---*//* Tab induced filename expansion *//* Unimplemented for the Macintosh */char *R_ExpandFileName(char *s){/* return the string unmodified */return s;}/* RHOME is the Folder where the R binary resides */FILE *R_OpenLibraryFile(char *file){/* This code finds where the R application was invoked *//* and descends from there to "library:base:R and opens *//* the specified file within that directory. It returns *//* the resulting file pointer. */return R_OpenLibraryFile1(file);/* ... */}FILE *R_OpenSysInitFile(void){/* This code finds where the R application was invoked *//* and descends from there to the folder "library:base:R" *//* and opens the file "Rprofile" within that directory. *//* It returns the resulting file pointer. */return R_OpenSysInitFile1();}FILE *R_OpenSiteFile(void){/* This code finds where the R application was invoked *//* and descends from there to the folder "etc" and opens *//* the file "Rprofile" within that directory. It returns *//* the resulting file pointer. */}FILE *R_OpenInitFile(void){/* This code attempts to open the file ".Rprofile" in the *//* current folder and returns the resulting file pointer. *//* Does thos make sense on the Mac. Probably not. */return NULL;}#define MAC_FILE_SIZE FILENAME_MAXstatic char R_HomeLocation[MAC_FILE_SIZE];void GetHomeLocation(void);void GetHomeLocation(void){getcwd(R_HomeLocation,MAC_FILE_SIZE);R_HomeLocation[strlen(R_HomeLocation)-1]='\0';}char *R_HomeDir(){return R_HomeLocation;}Rboolean R_HiddenFile(char *filename){int len = strlen(filename);if (filename[len - 1] == '\r')return 1;elsereturn 0;}/*--- Initialization Code ---*//* NOTE: The timing code below will have to be adpated *//* to use the macintosh specific timing code. */#include <sioux.h>int Mac_initialize_R(int ac, char **av);int main(int ac, char **av){int value;char *p;SInt16 a;gc_inhibit_torture = 1;SIOUXSettings.standalone = false; // I only use SIOUX to have command lineSIOUXSettings.setupmenus = false; // I'll set up the menusSIOUXSettings.initializeTB = false; // I manage the ToolBoxac = ccommand(&av); // This must be the first command after variables initializations !!!/* FIXME HERE: record the time at which the program started. *//* This is probably zero on the mac as we have direct *//* access to the number of ticks since process start *//* ... *//* FIXME HERE: Command line options are not available. *//* Application resources must be inspected here *//* and used to modify the compiled-in defaults. *//* Compare with the Unix code. *//* ... *//* Set up the file handling defaults. */R_Quiet = 0;R_Interactive = 1; /* On the Mac we must be interactive */// R_Consolefile = NULL; /* We don't use a file for console input. */// R_Outputfile = NULL; /* We don't use a file for console output. */// R_Sinkfile = NULL; /* We begin writing to the console. */// R_HistoryFile = ".Rhistory";/* ... *//* Call the real R main program (in ../main/main.c) */// start_Time = last_Time = TickCount();/* *** */Mac_initialize_R ( ac, av );/* *** */changeSize(Console_Window, gTextSize);mainloop();return 0;}int Mac_initialize_R(int ac, char **av){int i, ioff = 1, j, value, ierr;char *p, msg[1024], **avv;structRstart rstart;Rstart Rp = &rstart;if ( Initialize() == noErr ){gAppResFileRefNum = CurResFile();doGetPreferences();for(i=0;i<kMaxWindows+2;i++)gWindowPtrArray[i] = NULL;}elsereturn(1);GetHomeLocation();if((R_Home = R_HomeDir()) == NULL)R_Suicide("R home directory is not defined");// process_global_Renviron();#ifdef HAVE_TIMESR_setStartTime();#endifR_DefParams(Rp);/* Store the command line arguments before they are processedby the R option handler. These are stored in Rp and then movedto the global variable CommandLineArgs in R_SetParams.*/R_set_command_line_arguments(ac, av, Rp);/* first task is to select the GUI *//*for(i = 0, avv = av; i < ac; i++, avv++) {if(!strncmp(*avv, "--gui", 5) || !strncmp(*avv, "-g", 2)) {if(!strncmp(*avv, "--gui", 5) && strlen(*avv) >= 7)p = &(*avv)[6];else {if(i+1 < ac) {avv++; p = *avv; ioff++;} else {sprintf(msg, "WARNING: --gui or -g without value ignored");R_ShowMessage(msg);p = "X11";}}if(!strcmp(p, "none"))useX11 = FALSE;else if(!strcmp(p, "gnome") || !strcmp(p, "GNOME"))usegnome = TRUE;else if(!strcmp(p, "X11") || !strcmp(p, "x11"))useX11 = TRUE;else {// now remove it/themfor(j = i; j < ac-ioff; j++) {av[j] = av[j + ioff];}ac -= ioff;break;}}*/R_common_command_line(&ac, av, Rp);while (--ac) {if (**++av == '-') {if(!strcmp(*av, "--no-readline")) {UsingReadline = 0;} else {sprintf(msg, "WARNING: unknown option %s\n", *av);R_ShowMessage(msg);}} else {sprintf(msg, "ARGUMENT '%s' __ignored__\n", *av);R_ShowMessage(msg);}}R_SetParams(Rp);if(!Rp->NoRenviron) process_users_Renviron();/* On Unix the console is a file; we just use stdio to write on it */R_Interactive = isatty(0);R_Consolefile = NULL; /* We don't use a file for console input. */R_Outputfile = NULL; /* We don't use a file for console output. */R_Sinkfile = NULL; /* We begin writing to the console. *//** Since users' expectations for save/no-save will differ, we decided* that they should be forced to specify in the non-interactive case.*/if (!R_Interactive && SaveAction != SA_SAVE && SaveAction != SA_NOSAVE)R_Suicide("you must specify `--save', `--no-save' or `--vanilla'");if ((R_HistoryFile = getenv("R_HISTFILE")) == NULL)R_HistoryFile = ":etc:.Rhistory";R_HistorySize = 512;if ((p = getenv("R_HISTSIZE"))) {value = Decode2Long(p, &ierr);if (ierr != 0 || value < 0)REprintf("WARNING: invalid R_HISTSIZE ignored;");elseR_HistorySize = value;}if (R_RestoreHistory)mac_loadhistory(R_HistoryFile);return(0);}void R_InitialData(void){R_RestoreGlobalEnv();}/* R_CleanUp is invoked at the end of the session to give *//* the user the option of saving their data. If ask=1 the *//* user is asked their preference, if ask=2 the answer is *//* assumed to be "no" and if ask=3 the answer is assumed to *//* be "yes". When R is being used non-interactively, and *//* ask=1, the value is changed to 3. The philosophy is *//* that saving unwanted data is less bad than non saving *//* data that is wanted. */extern void MacFinalCleanup(void);void R_CleanUp(SA_TYPE saveact, int status, int runLast){unsigned char buf[128];if(saveact == SA_DEFAULT) /* The normal case apart from R_Suicide */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;}} elsesaveact = SaveAction;}switch (saveact) {case SA_SAVE:if(runLast) R_dot_Last();if(R_DirtyImage) R_SaveGlobalEnv();if(R_Interactive)mac_savehistory(R_HistoryFile);break;case SA_NOSAVE:if(runLast) R_dot_Last();break;case SA_SUICIDE:default:break;}KillAllDevices();if(saveact != SA_SUICIDE && R_CollectWarnings)PrintWarnings(); /* from device close and .Last */MacFinalCleanup();exit(status);}void R_Busy(int which){/* This can be used to gray out menus and change the *//* cursor (to a watch or equivalent) to indicate that an *//* extended computation is taking place. */}void R_SaveGlobalEnv(void){OSErr err;Boolean haveCancel;err = doRSave(&haveCancel);// err = doRSaveAs(&haveCancel);if (haveCancel){jump_to_toplevel();}}void R_RestoreGlobalEnv(void){FILE *fp;SEXP img, lst;int i;// int RestoreAction = SA_RESTORE;if(RestoreAction == SA_RESTORE) {if(!(fp = R_fopen(":etc:.RData", "rb"))) { /* binary file *//* warning here perhaps */return;}#ifdef OLDFRAME(R_GlobalEnv) = R_LoadFromFile(fp, 1);#elsePROTECT(img = R_LoadFromFile(fp, 1));switch (TYPEOF(img)) {case LISTSXP:while (img != R_NilValue) {defineVar(TAG(img), CAR(img), R_GlobalEnv);img = CDR(img);}break;case VECSXP:for (i = 0; i < LENGTH(img); i++) {// lst = VECTOR(img)[i];lst = VECTOR_ELT(img,i);while (lst != R_NilValue) {defineVar(TAG(lst), CAR(lst), R_GlobalEnv);lst = CDR(lst);}}break;}UNPROTECT(1);#endifif(!R_Quiet)Rprintf("[Previously saved workspace restored]\n\n");fclose(fp);}}/*--- Platform Dependent Functions ---*/#ifdef HAVE_TIMES#include <time.h>static clock_t StartTime;void R_setStartTime(void){StartTime = clock(); // ticks from system boot}void R_getProcTime(double *data){double elapsed;elapsed = (clock() - StartTime) / (double)CLOCKS_PER_SEC;data[0] = R_NaReal; // we have no total user timedata[1] = clock() / (double)CLOCKS_PER_SEC; // Real total system timedata[2] = elapsed; // process system timedata[3] = R_NaReal; // we don't have this under MacOSdata[4] = R_NaReal; // as above}double R_getClockIncrement(void){return 1.0 / (double) CLOCKS_PER_SEC;}SEXP do_proctime(SEXP call, SEXP op, SEXP args, SEXP env){SEXP ans = allocVector(REALSXP, 5);R_getProcTime(REAL(ans));return ans;}#endif /* HAVE_TIMES */static char CompleteEnvPath[NAME_MAX];/* getenv() doesn't exists on Macintosh. We can only extract someinformation from the System when available. For the time beeingwe only check for the TimeZone string.Stefano M. Iacus Gen 01*/SEXP do_getenv(SEXP call, SEXP op, SEXP args, SEXP env){int i, j;char *s = NULL;SEXP ans;FILE *fp;EnviromentPair *Env1;FSSpec spec;OSErr err;char env_buff[1000];char temp_path[NAME_MAX];checkArity(op, args);if (!isString(CAR(args)))errorcall(call, "wrong type for argument");i = LENGTH(CAR(args));if (i == 0) {sprintf(temp_path,"%s:%s",R_Home,"etc:.Renviron");GetCompletePath(CompleteEnvPath,temp_path,&spec,&err);/* try open the file in the current folder */fp = FSp_fopen(&spec,"r");if (fp == NULL){ /* Okey, lets try open the file in the preference folder */FSpFindFolder_Name(kOnSystemDisk,kPreferencesFolderType,kDontCreateFolder,&spec,"\p.Renviron");fp = FSp_fopen(&spec,"r");if (fp == NULL){errorcall(call,"There is no environment file");return R_NilValue; /* there is no enviroment-file */}}s = load_entry(fp);while (s != NULL){ /* parse the file line by line */Env1 = ParseLine(s);if (strlen(Env1->value) > 0)i++;s = load_entry(fp); /* read next line */}if(i==0) {fclose(fp);errorcall(call,"The environment file is empty");return R_NilValue;}PROTECT(ans = allocVector(STRSXP, i));i=0;fseek(fp,0,0);s = load_entry(fp);while (s != NULL){ /* parse the file line by line */Env1 = ParseLine(s);if (strlen(Env1->value) > 0){ /* we found a key/value pair */sprintf(env_buff,"%s=%s",Env1->key,Env1->value);SET_STRING_ELT(ans, i, mkChar(env_buff));i++;}s = load_entry(fp); /* read next line */}fclose(fp);} else {PROTECT(ans = allocVector(STRSXP, i));for (j = 0; j < i; j++) {s = mac_getenv(CHAR(STRING_ELT(CAR(args), j)));if (s == NULL)SET_STRING_ELT(ans, j, mkChar(""));elseSET_STRING_ELT(ans, j, mkChar(s));}}UNPROTECT(1);return (ans);}SEXP do_machine(SEXP call, SEXP op, SEXP args, SEXP env){return mkString("Macintosh");}SEXP do_system(SEXP call, SEXP op, SEXP args, SEXP rho){errorcall(call, "\n The function \"system\" is not implemented on Macintosh\n");return R_NilValue;}/*SEXP do_commandArgs(SEXP call, SEXP op, SEXP args, SEXP rho){errorcall(call, "\n The function \"commandArgs\" is not implemented on Macintosh\n");return R_NilValue;} // Jago*//*Rmac_tmpnam is a version of Runix_tmpnam for Macintosh. It assumesthat the directory "tmp" exists in the same directory where theR application resides if not, it attemps to create it.(Stefano M. Iacus) Jago Nov-00, implemented pre-alpha 3*/#define MAC_SIZE FILENAME_MAX#define MAC_READ_OR_WRITE 0x0 /* fake a UNIX mode */static char * Rmac_tmpnam(char * prefix){char *tmp, tm[PATH_MAX], tmp1[PATH_MAX], *res;char curFolder[MAC_SIZE], newFolder[MAC_SIZE];unsigned int n, done = 0, pid;getcwd( curFolder, MAC_SIZE );if( chdir(":tmp") ){sprintf(newFolder,"%s%s", curFolder, "tmp" );if( mkdir(newFolder, MAC_READ_OR_WRITE ) == -1 )error("Failed to create temporary folder");}chdir( curFolder );strcpy(tmp1, ":tmp");pid = (unsigned int) getpid();for (n = 0; n < 100; n++) {/* try a random number at the end */sprintf(tm, "%s:%sR%xS%x", tmp1, prefix, pid, rand());if (!R_FileExists(tm)) { done = 1; break; }}if(!done)error("cannot find unused tempfile name");res = (char *) malloc((strlen(tm)+1) * sizeof(char));strcpy(res, tm);return res;}/*do_tempfile it is just as under unix. No changes other thenRmac_tmpnam() instead of the Unix Runix_tmpnam();(Stefano M. Iacus) Jago Nov-00, implemented pre-alpha 3*/SEXP do_tempfile(SEXP call, SEXP op, SEXP args, SEXP env){SEXP ans;char *tn, *tm;int i, slen=0 /* -Wall */;checkArity(op, args);if (!isString(CAR(args)) || (slen = LENGTH(CAR(args))) < 1)errorcall(call, "invalid file name argument");PROTECT(ans = allocVector(STRSXP, slen));for(i = 0; i < slen; i++) {// tn = CHAR( STRING( CAR(args) )[i] );tn = CHAR( STRING_ELT( CAR(args) ,i ) );/* try to get a new file name */tm = Rmac_tmpnam(tn);// STRING(ans)[i] = mkChar(tm);SET_STRING_ELT( ans,i,mkChar(tm) );free(tm);}UNPROTECT(1);return (ans);}/*do_dircreate it is just as under Windows.(Stefano M. Iacus) Jago Jan-01, implemented in R 1.2.0 beta 1*/SEXP do_dircreate(SEXP call, SEXP op, SEXP args, SEXP env){SEXP path, ans;char *p, dir[PATH_MAX];int res;checkArity(op, args);path = CAR(args);if (!isString(path) || length(path) != 1)errorcall(call, "invalid path argument");strcpy(dir, CHAR(STRING_ELT(path, 0)));for(p = dir; *p != '\0'; p++)if(*p == '/') *p = ':'; // Differs from Windows, Jagores = mkdir(dir,0); // Differs from Windows, JagoPROTECT(ans = allocVector(LGLSXP, 1));LOGICAL(ans)[0] = (res==0);UNPROTECT(1);return (ans);}static void SelectTargetsToLaunch(void);/*do_helpstart it is just as under Windows.(Stefano M. Iacus) Jago Jan-01, implemented in R 1.x.x*/SEXP do_helpstart(SEXP call, SEXP op, SEXP args, SEXP env){char *home, buf[PATH_MAX];FILE *ff;FSSpec fileSpec;OSErr err;Str255 HelpFileName;char errbuf[512];checkArity(op, args);home = R_Home; // No env, Jagoif (home == NULL)error("R_HOME not set");sprintf(buf, "%s:doc:html:rmac.html", home);ff = fopen(buf, "r");if (!ff) {sprintf(buf, "%s:doc:html:rmac.htm", home);ff = fopen(buf, "r");if (!ff) {sprintf(buf, "%s:doc:html:rmac.htm[l] not found", home);error(buf);}}fclose(ff);if (strlen(buf) < 254)strcpy((char *) HelpFileName, buf);else {error("file name too long");return R_NilValue;}CtoPstr((char *) HelpFileName);err = FSMakeFSSpecFromPath((ConstStr255Param) HelpFileName, &fileSpec);if (err != noErr) {sprintf(errbuf, "error code %d creating file spec for help file %s",err, buf);error(errbuf);return R_NilValue;}err = FinderLaunch(1, &fileSpec);if(err!=noErr)error("Cannot lauch browser");return R_NilValue;}/* As under Windows. We only handle HTML help filesStefano M. Iacus (Jago Jan 2001)*/SEXP do_helpitem(SEXP call, SEXP op, SEXP args, SEXP env){/** type = 1: launch html file.**/char *item;char *home, buf[PATH_MAX];FILE *ff;int type;Str255 HelpFileName;FSSpec fileSpec;OSErr err;char errbuf[512];checkArity(op, args);if (!isString(CAR(args)))errorcall(call, "invalid topic argument");item = CHAR(STRING_ELT(CAR(args), 0));type = asInteger(CADR(args));if (type == 1) {ff = fopen(item, "r");if (!ff) {sprintf(buf, "%s not found", item);error(buf);}fclose(ff);/* home = getenv("R_HOME");*/home = R_Home;if (home == NULL)error("R_HOME not set");if (strlen(item) < 254)strcpy((char *) HelpFileName, item);else {error("file name too long");return R_NilValue;}CtoPstr((char *) HelpFileName);err = FSMakeFSSpecFromPath((ConstStr255Param) HelpFileName, &fileSpec);if (err != noErr) {sprintf(errbuf, "error code %d creating file spec for help file %s",err, item);error(errbuf);return R_NilValue;}err = FinderLaunch(1, &fileSpec);if(err!=noErr)error("Cannot lauch browser");}elsewarning("type not yet implemented");return R_NilValue;}SEXP do_dataentry(SEXP call, SEXP op, SEXP args, SEXP rho){errorcall(call, "unimplemented function\n");}SEXP do_edit(SEXP call, SEXP op, SEXP args, SEXP rho){int i, n;SEXP x;char **lines, *vmaxsave;checkArity(op, args);vmaxsave = vmaxget();/* x is the object to be edited *//* note that we ignore the file and editor args */PROTECT(x = deparse1(CAR(args), 0));n = length(x);lines = (char**)R_alloc(n, sizeof(char*));for (i = 0; i < n; i++) {// lines[i] = CHAR(STRING(x)[i]);lines[i] = CHAR( STRING_ELT(x,i) );}for (i = 0; i < n; i++) {Rprintf("%s\n", lines[i]);}R_Edit(lines, n);vmaxset(vmaxsave);UNPROTECT(1);R_Visible = 0;return R_NilValue;}/* Adapted from Windows code for MacintoshIt does not allow wildcars and only files/dirscreated in the current session can be removed.(Stefano M. Iacus) Jago Nov-00*/SEXP do_unlink(SEXP call, SEXP op, SEXP args, SEXP env){SEXP fn, ans;char *p, tmp[PATH_MAX], dir[PATH_MAX];int i, nfiles, failures = 0;struct stat sb;checkArity(op, args);fn = CAR(args);nfiles = length(fn);if (!isString(fn) || nfiles < 1)errorcall(call, "invalid file name argument");for(i = 0; i < nfiles; i++) {// strcpy(tmp, CHAR(STRING(fn)[i]));strcpy(tmp, CHAR( STRING_ELT(fn,i) ));for(p = tmp; *p != '\0'; p++)if(*p == '/') *p = ':';if(stat(tmp, &sb) == 0)/* Is this a directory? */if(sb.st_mode & S_IFDIR) {if(rmdir(tmp)) failures++;continue;}/* Regular file (or more) */strcpy(dir, tmp);if ((p = strrchr(dir, ':'))) *(++p) = '\0'; else *dir = '\0';/* wildcard not allowed */// strcpy(tmp, dir); //strcat(tmp, find_data.cFileName);failures += (unlink(tmp) !=0);}PROTECT(ans = allocVector(INTSXP, 1));if (!failures)INTEGER(ans)[0] = 0;elseINTEGER(ans)[0] = 1;UNPROTECT(1);return (ans);}void R_Suicide(char *s){Str255 LabelText;int msglen,i;/* FIXME HERE: This should pop up a dialog box with the given *//* error message displayed, and the quit when the user hits the *//* OK button. */msglen = strlen(s);for(i=1;i<msglen;i++)if(s[i]==0x0A)s[i]=0x0D;StrToStr255(s, LabelText);R_doErrorAlert(LabelText);R_CleanUp(SA_NOSAVE,0,0);/* SA_NOSAVE means don't save anything and it's an unrecoverable abort */}void StrToStr255(char* sourceText, Str255 targetText){SInt16 StringLength, Counter;StringLength = strlen(sourceText);if (StringLength > 254)StringLength = 254;targetText[0] = StringLength;for (Counter = 1; Counter <=StringLength; Counter ++){targetText[Counter] = sourceText[Counter-1];}}void R_doErrorAlert(Str255 labelText){AlertStdAlertParamRec paramRec;//Str255 labelText;Str255 narrativeText;SInt16 itemHit;paramRec.movable = false;paramRec.helpButton = false;paramRec.filterProc = NULL;paramRec.defaultText = (StringPtr) kAlertDefaultOKText;paramRec.cancelText = NULL;paramRec.otherText = NULL;paramRec.defaultButton = kAlertStdAlertOKButton;paramRec.cancelButton = 0;paramRec.position = kWindowAlertPositionMainScreen;Do_StandardAlert(labelText);//(kAlertStopAlert,labelText,0,¶mRec,&itemHit);}/* Declarations to keep f77 happy */int MAIN_() {return 0;}int MAIN__() {return 0;}int __main() {return 0;}/*What follows is adapted from src/unix/sys-common.c*//*See ../unix/system.txt for a description of functions*//*#ifdef HAVE_CONFIG_H#include <config.h>#endif#include "Defn.h"#include "Fileio.h"#include "Startup.h"#include <string.h>*/#ifndef HAVE_STRDUPextern char *strdup();#endif/* Permanent copy of the command line arguments and the numberof them passed to the application.These are populated via the routine R_set_command_line_arguments()called from R_common_command_line().*/int NumCommandLineArgs = 0;char **CommandLineArgs = NULL;/*FILE *R_OpenSysInitFile(void){char buf[256];FILE *fp;sprintf(buf, "%s/library/base/R/Rprofile", R_Home);fp = R_fopen(buf, "r");return fp;}*//*FILE *R_OpenSiteFile(void){char buf[256];FILE *fp;fp = NULL;if (LoadSiteFile) {if ((fp = R_fopen(getenv("R_PROFILE"), "r")))return fp;if ((fp = R_fopen(getenv("RPROFILE"), "r")))return fp;sprintf(buf, "%s/etc/Rprofile", R_Home);if ((fp = R_fopen(buf, "r")))return fp;}return fp;}*//* Saving and Restoring the Global Environment *//*void R_RestoreGlobalEnv(void){FILE *fp;SEXP img, lst;int i;if(RestoreAction == SA_RESTORE) {if(!(fp = R_fopen(".RData", "rb"))) {return;}#ifdef OLDFRAME(R_GlobalEnv) = R_LoadFromFile(fp, 1);#elsePROTECT(img = R_LoadFromFile(fp, 1));switch (TYPEOF(img)) {case LISTSXP:while (img != R_NilValue) {defineVar(TAG(img), CAR(img), R_GlobalEnv);img = CDR(img);}break;case VECSXP:for (i = 0; i < LENGTH(img); i++) {lst = VECTOR_ELT(img, i);while (lst != R_NilValue) {defineVar(TAG(lst), CAR(lst), R_GlobalEnv);lst = CDR(lst);}}break;}UNPROTECT(1);#endifif(!R_Quiet)Rprintf("[Previously saved workspace restored]\n\n");fclose(fp);}}*//*void R_SaveGlobalEnv(void){FILE *fp = R_fopen(".RData", "wb");if (!fp)error("can't save data -- unable to open ./.RData");if (HASHTAB(R_GlobalEnv) != R_NilValue)R_SaveToFile(HASHTAB(R_GlobalEnv), fp, 0);elseR_SaveToFile(FRAME(R_GlobalEnv), fp, 0);fclose(fp);}*//** 5) FILESYSTEM INTERACTION*//** This call provides a simple interface to the "stat" system call.*/#ifdef HAVE_STAT#include <types.h>#include <stat.h>#include <stat.h>/*Rboolean R_FileExists(char *path){struct stat sb;return stat(path, &sb) == 0;}*/Rboolean R_FileExists(char *path){struct stat sb;return stat(R_ExpandFileName(path), &sb) == 0;}#elseRboolean R_FileExists(char *path){error("file existence is not available on this system");}#endif/** Unix file names which begin with "." are invisible.*//*Rboolean R_HiddenFile(char *name){if (name && name[0] != '.') return 0;else return 1;}*/FILE *R_fopen(const char *filename, const char *mode){return(filename ? fopen(filename, mode) : NULL );}/** 6) SYSTEM INFORMATION*//* The location of the R system files *//** 7) PLATFORM DEPENDENT FUNCTIONS*/SEXP do_putenv(SEXP call, SEXP op, SEXP args, SEXP env){#ifdef HAVE_PUTENVint i, n;SEXP ans, vars;checkArity(op, args);if (!isString(vars =CAR(args)))errorcall(call, "wrong type for argument");n = LENGTH(vars);PROTECT(ans = allocVector(LGLSXP, n));for (i = 0; i < n; i++) {LOGICAL(ans)[i] = putenv(CHAR(STRING_ELT(vars, i))) == 0;}UNPROTECT(1);return ans;#elseerror("`putenv' is not available on this system");return R_NilValue; /* -Wall */#endif}SEXP do_interactive(SEXP call, SEXP op, SEXP args, SEXP rho){SEXP rval;rval=allocVector(LGLSXP, 1);LOGICAL(rval)[0]= (R_Interactive) ? 1 : 0;return rval;}/** INITIALIZATION HELPER CODE*/void R_ShowMessage(char *msg){Str255 LabelText;int msglen,i;msglen = strlen(msg);for(i=1;i<msglen;i++)if(msg[i]==0x0A)msg[i]=0x0D;StrToStr255(msg, LabelText);R_doErrorAlert(LabelText);}void R_DefParams(Rstart Rp){Rp->R_Quiet = FALSE;Rp->R_Slave = FALSE;Rp->R_Interactive = TRUE;Rp->R_Verbose = FALSE;Rp->RestoreAction = SA_RESTORE;Rp->SaveAction = SA_SAVEASK;Rp->LoadSiteFile = TRUE;Rp->LoadInitFile = TRUE;Rp->DebugInitFile = FALSE;Rp->vsize = R_VSIZE;Rp->nsize = R_NSIZE;Rp->max_vsize = INT_MAX;Rp->max_nsize = INT_MAX;Rp->NoRenviron = FALSE;}#define Max_Nsize 50000000 /* must be < LONG_MAX (= 2^32 - 1 =)2147483647 = 2.1e9 *//* limit was 2e7, changed to 5e7, which givesnearly 2Gb of cons cells */#define Max_Vsize (2048*Mega) /* 2048*Mega = 2^(11+20) must be < LONG_MAX */#define Min_Nsize 160000#define Min_Vsize (1*Mega)void R_SizeFromEnv(Rstart Rp){int value, ierr;char *p;if((p = getenv("R_VSIZE"))) {value = Decode2Long(p, &ierr);if(ierr != 0 || value > Max_Vsize || value < Min_Vsize)R_ShowMessage("WARNING: invalid R_VSIZE ignored\n");elseRp->vsize = value;}if((p = getenv("R_NSIZE"))) {value = Decode2Long(p, &ierr);if(ierr != 0 || value > Max_Nsize || value < Min_Nsize)R_ShowMessage("WARNING: invalid R_NSIZE ignored\n");elseRp->nsize = value;}}static void SetSize(int vsize, int nsize){char msg[1024];/* vsize >0 to catch long->int overflow */if (vsize < 1000 && vsize > 0) {R_ShowMessage("WARNING: vsize ridiculously low, Megabytes assumed\n");vsize *= Mega;}if(vsize < Min_Vsize || vsize > Max_Vsize) {sprintf(msg, "WARNING: invalid v(ector heap)size `%d' ignored\n""using default = %gM\n", vsize, R_VSIZE / Mega);R_ShowMessage(msg);R_VSize = R_VSIZE;} elseR_VSize = vsize;if(nsize < Min_Nsize || nsize > Max_Nsize) {sprintf(msg, "WARNING: invalid language heap (n)size `%d' ignored,"" using default = %ld\n", nsize, R_NSIZE);R_ShowMessage(msg);R_NSize = R_NSIZE;} elseR_NSize = nsize;}void R_SetParams(Rstart Rp){R_Quiet = Rp->R_Quiet;R_Slave = Rp->R_Slave;R_Interactive = Rp->R_Interactive;R_Verbose = Rp->R_Verbose;RestoreAction = Rp->RestoreAction;SaveAction = Rp->SaveAction;LoadSiteFile = Rp->LoadSiteFile;LoadInitFile = Rp->LoadInitFile;DebugInitFile = Rp->DebugInitFile;SetSize(Rp->vsize, Rp->nsize);R_SetMaxNSize(Rp->max_nsize);R_SetMaxVSize(Rp->max_vsize);CommandLineArgs = Rp->CommandLineArgs;NumCommandLineArgs = Rp->NumCommandLineArgs;}/* Remove and process common command-line arguments *//*This copies the command line arguments to the Rstartstructure. The memory is obtained from calloc, etc.since these are permanent and it is not intended thatthey be modified. This is why they are copied beforebeing processed and removed from the list.We might store these as a SEXP. I have no strong opinionabout this.*/voidR_set_command_line_arguments(int argc, char **argv, Rstart Rp){int i;Rp->NumCommandLineArgs = argc;Rp->CommandLineArgs = (char**) calloc(argc, sizeof(char*));for(i = 0; i < argc; i++) {Rp->CommandLineArgs[i] = strdup(argv[i]);}}/*The .Internal which returns the command line arguments that are storedin global variables.*/SEXPdo_commandArgs(SEXP call, SEXP op, SEXP args, SEXP env){int i;SEXP vals;vals = allocVector(STRSXP, NumCommandLineArgs);for(i = 0; i < NumCommandLineArgs; i++) {SET_STRING_ELT(vals, i, mkChar(CommandLineArgs[i]));}return(vals);}voidR_common_command_line(int *pac, char **argv, Rstart Rp){int ac = *pac, newac = 1; /* argv[0] is process name */int ierr;long value;char *p, **av = argv, msg[1024];R_RestoreHistory = 1;while(--ac) {if(**++av == '-') {if (!strcmp(*av, "--version")) {PrintVersion(msg);R_ShowMessage(msg);exit(0);}#if 0else if(!strcmp(*av, "--print-nsize")) {Rprintf("%d\n", R_NSize);exit(0);}else if(!strcmp(*av, "--print-vsize")) {Rprintf("%d\n", R_VSize);exit(0);}#endifelse if(!strcmp(*av, "--save")) {Rp->SaveAction = SA_SAVE;}else if(!strcmp(*av, "--no-save")) {Rp->SaveAction = SA_NOSAVE;}else if(!strcmp(*av, "--restore")) {Rp->RestoreAction = SA_RESTORE;}else if(!strcmp(*av, "--no-restore")) {Rp->RestoreAction = SA_NORESTORE;R_RestoreHistory = 0;}else if(!strcmp(*av, "--no-restore-data")) {Rp->RestoreAction = SA_NORESTORE;}else if(!strcmp(*av, "--no-restore-history")) {R_RestoreHistory = 0;}else if (!strcmp(*av, "--silent") ||!strcmp(*av, "--quiet") ||!strcmp(*av, "-q")) {Rp->R_Quiet = TRUE;}else if (!strcmp(*av, "--vanilla")) {Rp->SaveAction = SA_NOSAVE; /* --no-save */Rp->RestoreAction = SA_NORESTORE; /* --no-restore */Rp->LoadSiteFile = FALSE; /* --no-site-file */Rp->LoadInitFile = FALSE; /* --no-init-file */R_RestoreHistory = 0; /* --no-restore-history */Rp->NoRenviron = TRUE;}else if (!strcmp(*av, "--no-environ")) {Rp->NoRenviron = TRUE;}else if (!strcmp(*av, "--verbose")) {Rp->R_Verbose = TRUE;}else if (!strcmp(*av, "--slave") ||!strcmp(*av, "-s")) {Rp->R_Quiet = TRUE;Rp->R_Slave = TRUE;Rp->SaveAction = SA_NOSAVE;}else if (!strcmp(*av, "--no-site-file")) {Rp->LoadSiteFile = FALSE;}else if (!strcmp(*av, "--no-init-file")) {Rp->LoadInitFile = FALSE;}else if (!strcmp(*av, "--debug-init")) {Rp->DebugInitFile = TRUE;}else if (!strcmp(*av, "-save") ||!strcmp(*av, "-nosave") ||!strcmp(*av, "-restore") ||!strcmp(*av, "-norestore") ||!strcmp(*av, "-noreadline") ||!strcmp(*av, "-quiet") ||!strcmp(*av, "-V") ||!strcmp(*av, "-n") ||!strcmp(*av, "-v")) {sprintf(msg, "WARNING: option %s no longer supported\n", *av);R_ShowMessage(msg);}/* mop up --max/min/-n/vsize */else if(strncmp(*av+7, "size", 4) == 0) {if(strlen(*av) < 13) {ac--; av++; p = *av;}else p = &(*av)[12];if (p == NULL) {sprintf(msg, "WARNING: no value given for %s\n", *av);R_ShowMessage(msg);break;}value = Decode2Long(p, &ierr);if(ierr) {if(ierr < 0)sprintf(msg, "WARNING: %s value is invalid: ignored\n",*av);elsesprintf(msg, "WARNING: %s=%ld`%c': too large and ignored\n",*av, value,(ierr == 1) ? 'M': ((ierr == 2) ? 'K' : 'k'));R_ShowMessage(msg);} else {if(!strncmp(*av, "--min-nsize", 11)) Rp->nsize = value;if(!strncmp(*av, "--max-nsize", 11)) Rp->max_nsize = value;if(!strncmp(*av, "--min-vsize", 11)) Rp->vsize = value;if(!strncmp(*av, "--max-vsize", 11)) Rp->max_vsize = value;}}else if(strncmp(*av, "--vsize", 7) == 0) {if(strlen(*av) < 9) {ac--; av++; p = *av;}elsep = &(*av)[8];if (p == NULL) {R_ShowMessage("WARNING: no vsize given\n");break;}value = Decode2Long(p, &ierr);if(ierr) {if(ierr < 0) /* R_common_badargs(); */sprintf(msg, "WARNING: --vsize value is invalid: ignored\n");elsesprintf(msg, "WARNING: --vsize=%ld`%c': too large and ignored\n",value,(ierr == 1) ? 'M': ((ierr == 2) ? 'K' : 'k'));R_ShowMessage(msg);} elseRp->vsize = value;}else if(strncmp(*av, "--nsize", 7) == 0) {if(strlen(*av) < 9) {ac--; av++; p = *av;}elsep = &(*av)[8];if (p == NULL) {R_ShowMessage("WARNING: no nsize given\n");break;}value = Decode2Long(p, &ierr);if(ierr) {if(ierr < 0) /* R_common_badargs(); */sprintf(msg, "WARNING: --nsize value is invalid: ignored\n");elsesprintf(msg, "WARNING: --nsize=%ld`%c': too large and ignored\n",value,(ierr == 1) ? 'M': ((ierr == 2) ? 'K':'k'));R_ShowMessage(msg);} elseRp->nsize = value;}else {argv[newac++] = *av;}}else {argv[newac++] = *av;}}*pac = newac;return;}/* ------------------- process .Renviron files in C ----------------- *//* remove leading and trailing space */static char *rmspace(char *s){int i;for (i = strlen(s) - 1; isspace((int)s[i]); i--) s[i] = '\0';for (i = 0; isspace((int)s[i]); i++);return s + i;}/* look for ${FOO:-bar} constructs, recursively */static char *findterm(char *s){char *p, *q;if(!strlen(s)) return "";if(strncmp(s, "${", 2)) return s;/* found one, so remove leading ${ and final } */if(s[strlen(s) - 1] != '}') return "";s[strlen(s) - 1] = '\0';s += 2;p = strchr(s, '-');if(!p) return "";q = p + 1; /* start of value */if(p - s > 1 && *(p-1) == ':') *(p-1) = '\0'; else *p = '\0';s = rmspace(s);if(!strlen(s)) return "";p = getenv(s);if(p && strlen(p)) return p; /* variable was set and non-empty */return findterm(q);}static void Putenv(char *a, char *b){char *buf;buf = (char *) malloc((strlen(a) + strlen(b) + 2) * sizeof(char));if(!buf) R_Suicide("allocation failure in reading Renviron");strcpy(buf, a); strcat(buf, "="); strcat(buf, b);// putenv(buf);/* no free here: storage remains in use */}#define BUF_SIZE 255#define MSG_SIZE 2000static int process_Renviron(char *filename){FILE *fp;char *s, *p, sm[BUF_SIZE], *lhs, *rhs, msg[MSG_SIZE+50];int errs = 0;if (!filename || !(fp = fopen(filename, "r"))) return 0;sprintf(msg, "\n File %s contains invalid line(s)", filename);while(fgets(sm, BUF_SIZE, fp)) {sm[BUF_SIZE] = '\0';s = rmspace(sm);if(strlen(s) == 0 || s[0] == '#') continue;if(!(p = strchr(s, '='))) {errs++;if(strlen(msg) < MSG_SIZE) {strcat(msg, "\n "); strcat(msg, s);}continue;}*p = '\0';lhs = rmspace(s);rhs = findterm(rmspace(p+1));/* set lhs = rhs */if(strlen(lhs) && strlen(rhs)) Putenv(lhs, rhs);}fclose(fp);if (errs) {strcat(msg, "\n They were ignored\n");R_ShowMessage(msg);}return 1;}/* read R_HOME/etc/Renviron: Unix only *//* try ./.Renviron, then value of R_ENVIRON, then ~/.Renviron */void process_users_Renviron(){char *s;if(process_Renviron(".Renviron")) return;if((s = getenv("R_ENVIRON"))) {process_Renviron(s);return;}process_Renviron(s);}