Rev 2 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Langage for Statistical Data Analysis* Copyright (C) 1995, 1996 Robert Gentleman and 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.*/#include "Defn.h"#include "Print.h"#include "Fileio.h"#ifdef HAVE_LIBREADLINEchar *tilde_expand (char *);#endifSEXP do_delay(SEXP call, SEXP op, SEXP args, SEXP rho){SEXP expr, env;checkArity(op, args);expr = CAR(args);env = eval(CADR(args), rho);if(!isEnvironment(env))errorcall(call, "invalid argument\n");return mkPROMISE(expr, env);}SEXP do_onexit(SEXP call, SEXP op, SEXP args, SEXP rho){RCNTXT *ctxt;SEXP code;switch (length(args)) {case 0:code = R_NilValue;break;case 1:code = CAR(args);break;default:errorcall(call, "invalid number of arguments\n");}ctxt = R_GlobalContext;while (ctxt != R_ToplevelContext && ctxt->callflag != CTXT_RETURN)ctxt = ctxt->nextcontext;if (ctxt->callflag == CTXT_RETURN)ctxt->conexit = code;return R_NilValue;}SEXP do_args(SEXP call, SEXP op, SEXP args, SEXP rho){SEXP s;checkArity(op,args);if (TYPEOF(CAR(args)) == STRSXP && length(CAR(args))==1) {PROTECT(s = install(CHAR(STRING(CAR(args))[0])));CAR(args) = findFun(s, rho);UNPROTECT(1);}if (TYPEOF(CAR(args)) == CLOSXP) {s = allocSExp(CLOSXP);FORMALS(s) = FORMALS(CAR(args));BODY(s) = R_NilValue;CLOENV(s) = R_GlobalEnv;return(s);}return R_NilValue;}SEXP do_formals(SEXP call, SEXP op, SEXP args, SEXP rho){checkArity(op, args);if( TYPEOF(CAR(args)) == CLOSXP )return duplicate(FORMALS(CAR(args)));elsereturn R_NilValue;}SEXP do_body(SEXP call, SEXP op, SEXP args, SEXP rho){checkArity(op, args);if( TYPEOF(CAR(args)) == CLOSXP )return duplicate(BODY(CAR(args)));else return R_NilValue;}SEXP do_envir(SEXP call, SEXP op, SEXP args, SEXP rho){checkArity(op, args);if (TYPEOF(CAR(args)) == CLOSXP)return CLOENV(CAR(args));else if (CAR(args) == R_NilValue)return R_GlobalContext->sysparent;return R_NilValue;}SEXP do_envirgets(SEXP call, SEXP op, SEXP args, SEXP rho){checkArity(op, args);if (TYPEOF(CAR(args)) == CLOSXP && isEnvironment(CADR(args)))CLOENV(CAR(args)) = CADR(args);return CAR(args);}static void cat_newline(SEXP labels, int * width, int lablen, int ntot){Rprintf("\n");*width = 0;if (labels != R_NilValue) {Rprintf("%s ", EncodeString(CHAR(STRING(labels)[ntot % lablen]), 1, 0));*width += Rstrlen(CHAR(STRING(labels)[ntot % lablen])) + 1;}}static void cat_sepwidth(SEXP sep, int * width, int ntot){if (sep == R_NilValue || LENGTH(sep) == 0)*width = 0;else*width = Rstrlen(CHAR(STRING(sep)[ntot % LENGTH(sep)]));}static void cat_printsep(SEXP sep, int ntot){char *sepchar;if (sep == R_NilValue || LENGTH(sep) == 0)return;sepchar = CHAR(STRING(sep)[ntot % LENGTH(sep)]);Rprintf("%s",sepchar);return;}SEXP do_cat(SEXP call, SEXP op, SEXP args, SEXP rho){SEXP a, objs, file, fill, sepr, labs, s;FILE *savefp;int havefile, append;int w, i, n, pwidth, width, sepw, lablen, ntot, nlsep;char *p;checkArity(op, args);/* Use standard printing defaults */PrintDefaults(rho);objs = CAR(args); args = CDR(args);file = CAR(args); args = CDR(args);if(!isString(file) || length(file) != 1)errorcall(call, "invalid file= specification\n");sepr = CAR(args); args = CDR(args);if (!isString(sepr))errorcall(call, "invalid sep= specification\n");nlsep = 0;for (i = 0; i < LENGTH(sepr); i++)if (strstr(CHAR(STRING(sepr)[i]), "\n")) nlsep = 1;fill = CAR(args); args = CDR(args);if ((!isNumeric(fill) && !isLogical(fill)) || (length(fill) != 1))errorcall(call, "invalid fill argument\n");if (isLogical(fill)) {if (asLogical(fill) == 1)pwidth = PRINT_WIDTH;elsepwidth = INT_MAX;}else pwidth = asInteger(fill);labs = CAR(args); args = CDR(args);if (!isString(labs) && labs != R_NilValue)errorcall(call, "invalid label argument\n");lablen = length(labs);append = asLogical(CAR(args));if(append == NA_LOGICAL)errorcall(call, "invalid append specification\n");if (strlen(CHAR(STRING(file)[0])) > 0) {savefp = R_Outputfile;if (append)#ifdef HAVE_LIBREADLINER_Outputfile = R_fopen(tilde_expand(CHAR(STRING(file)[0])), "a");elseR_Outputfile = R_fopen(tilde_expand(CHAR(STRING(file)[0])), "w");#elseR_Outputfile = R_fopen(CHAR(STRING(file)[0]), "a");elseR_Outputfile = R_fopen(CHAR(STRING(file)[0]), "w");#endifif (!R_Outputfile) {R_Outputfile = savefp;errorcall(call, "unable to open file\n");}havefile = 1 ;}else havefile = 0;n = 0;for (a = objs; a != R_NilValue; a = CDR(a)) {if (!isVector(CAR(a)) && !isNull(CAR(a)))errorcall(call, "argument %d has invalid type\n", n+1);n += 1;}width = 0;ntot = 0;for (a = objs; a != R_NilValue; a = CDR(a)) {s = CAR(a);if (a != objs && !isNull(s) )cat_printsep(sepr, 0);n = length(s);if (n > 0) {if (labs != R_NilValue && a == objs) {Rprintf("%s ", CHAR(STRING(labs)[0]));width += strlen(CHAR(STRING(labs)[ntot % lablen])) + 1;ntot++;}if(isString(s))p = CHAR(STRING(s)[0]);elsep = EncodeElement(s, 0, 0);w = strlen(p);cat_sepwidth(sepr, &sepw, ntot);if (a != objs && (width + w + sepw > pwidth))cat_newline(labs, &width, lablen, ntot);for (i = 0; i < n; i++, ntot++) {Rprintf("%s", p);width += w + sepw;if (i < (n - 1)) {cat_printsep(sepr, ntot);if(isString(s))p = CHAR(STRING(s)[i+1]);elsep = EncodeElement(s, i+1, 0);cat_sepwidth(sepr, &sepw, ntot);if ((width + w + sepw > pwidth) && pwidth)cat_newline(labs, &width, lablen, ntot);}}}}if ((pwidth != INT_MAX) || nlsep)Rprintf("\n");if (havefile) {fclose(R_Outputfile);R_Outputfile = savefp;}elsefflush(stdout);return R_NilValue;}SEXP do_makelist(SEXP call, SEXP op, SEXP args, SEXP rho){SEXP s = args;while (s != R_NilValue) {if (NAMED(CAR(s)))CAR(s) = duplicate(CAR(s));s = CDR(s);}return args;}SEXP do_makefactor(SEXP call, SEXP op, SEXP args, SEXP rho){SEXP x, y;int i, j, nx, nl, ord;checkArity(op, args);x = CAR(args) = coerceVector(CAR(args), INTSXP);nl = asInteger(CADR(args));if (nl == NA_INTEGER || nl < 1)errorcall(call, "invalid number of factor levels\n");ord = asLogical(CADDR(args));if(ord == NA_LOGICAL) ord = 0;nx = LENGTH(x);PROTECT(y = allocVector(ord ? ORDSXP : FACTSXP, nx));LEVELS(y) = nl;for (i = 0; i < nx; i++) {j = INTEGER(x)[i];if (1 <= j && j <= nl)FACTOR(y)[i] = j;elseFACTOR(y)[i] = NA_INTEGER;}if(ord) {PROTECT(x = allocVector(STRSXP, 2));STRING(x)[0] = mkChar("ordered");STRING(x)[1] = mkChar("factor");}else {PROTECT(x = allocVector(STRSXP, 1));STRING(x)[0] = mkChar("factor");}setAttrib(y, R_ClassSymbol, x);UNPROTECT(2);return y;}SEXP do_expression(SEXP call, SEXP op, SEXP args, SEXP rho){SEXP a, blank, ans, nms;int i, n, named;named = 0;n = length(args);PROTECT(ans = allocVector(EXPRSXP, n));a = args;for(i=0 ; i<n ; i++) {VECTOR(ans)[i] = duplicate(CAR(a));if (TAG(a) != R_NilValue) named = 1;a = CDR(a);}if(named) {PROTECT(blank=mkChar(""));PROTECT(nms = allocVector(STRSXP, n));a = args;for(i=0 ; i<n ; i++) {if(TAG(a) != R_NilValue)STRING(nms)[i] = PRINTNAME(TAG(a));elseSTRING(nms)[i] = blank;a = CDR(a);}setAttrib(ans, R_NamesSymbol, nms);UNPROTECT(2);}UNPROTECT(1);return ans;}SEXP do_makevector(SEXP call, SEXP op, SEXP args, SEXP rho){int len, i;SEXP s, blank;SEXPTYPE mode;checkArity(op, args);len = asInteger(CADR(args));s = coerceVector(CAR(args), STRSXP);mode = str2type(CHAR(STRING(s)[0]));if (mode == -1 && streql(CHAR(STRING(s)[0]), "double"))mode = REALSXP;if ((CHARSXP < mode && mode <= STRSXP) || mode == EXPRSXP)s = allocVector(mode, len);else if (mode == LISTSXP)s = allocList(len);elseerror("vector: cannot make a vector of the type specified\n");if (mode == INTSXP || mode == LGLSXP)for (i = 0; i < len; i++)INTEGER(s)[i] = 0;if (mode == FACTSXP || mode == ORDSXP)for (i = 0; i < len; i++)FACTOR(s)[i] = 1;else if (mode == REALSXP)for (i = 0; i < len; i++)REAL(s)[i] = 0.0;else if (mode == STRSXP) {PROTECT(s);PROTECT(blank = mkChar(""));for (i = 0; i < len; i++)STRING(s)[i] = blank;UNPROTECT(2);}return s;}/* do_lengthgets: assign a length to a vector or a list *//* (if it is vectorizable). We could probably be fairly *//* clever with memory here if we wanted to. */SEXP do_lengthgets(SEXP call, SEXP op, SEXP args, SEXP rho){int len, lenx, i;SEXP rval, x, names, xnames, t;checkArity(op, args);x = CAR(args);if (!isVector(x) && !isVectorizable(x))error("length<- invalid first argument\n");if (length(CADR(args)) != 1)error("length<- invalid second argument\n");len = asInteger(CADR(args));if (len == NA_INTEGER)error("length<- missing value for length\n");lenx = length(x);if (lenx == len)return (x);rval = allocVector(TYPEOF(x), len);PROTECT(xnames = getAttrib(x, R_NamesSymbol));if (xnames != R_NilValue)names = allocVector(STRSXP, len);switch (TYPEOF(x)) {case LGLSXP:case FACTSXP:case ORDSXP:case INTSXP:for (i = 0; i < len; i++)if (i < lenx) {INTEGER(rval)[i] = INTEGER(x)[i];if (xnames != R_NilValue)STRING(names)[i] = STRING(xnames)[i];}elseINTEGER(rval)[i] = NA_INTEGER;break;case REALSXP:for (i = 0; i < len; i++)if (i < lenx) {REAL(rval)[i] = REAL(x)[i];if (xnames != R_NilValue)STRING(names)[i] = STRING(xnames)[i];}elseREAL(rval)[i] = NA_REAL;break;#ifdef COMPLEX_DATAcase CPLXSXP:for (i = 0; i < len; i++)if (i < lenx) {COMPLEX(rval)[i] = COMPLEX(x)[i];if (xnames != R_NilValue)STRING(names)[i] = STRING(xnames)[i];}else {COMPLEX(rval)[i].r = NA_REAL;COMPLEX(rval)[i].i = NA_REAL;}break;#endifcase STRSXP:for (i = 0; i < len; i++)if (i < lenx) {STRING(rval)[i] = STRING(x)[i];if (xnames != R_NilValue)STRING(names)[i] = STRING(xnames)[i];}elseSTRING(rval)[i] = NA_STRING;break;case LISTSXP:for (t = rval; t != R_NilValue; t = CDR(t), x = CDR(x)) {CAR(t) = CAR(x);TAG(t) = TAG(x);}}if (isVector(x) && xnames != R_NilValue)setAttrib(rval, R_NamesSymbol, names);UNPROTECT(1);return rval;}SEXP do_assign(SEXP call, SEXP op, SEXP args, SEXP rho){SEXP name, val, aenv;int ginherits;checkArity(op, args);name = findVar(CAR(args), rho);PROTECT(args = evalList(args, rho));if (!isString(CAR(args)))error("assign: invalid argument\n");elsename = install(CHAR(STRING(CAR(args))[0]));PROTECT(val = eval(CADR(args), rho));R_Visible = 0;aenv = CAR(CDDR(args));if (TYPEOF(aenv) != ENVSXP && aenv != R_NilValue)error("invalid envir argument\n");if (isLogical(CAR(nthcdr(args, 3))))ginherits = LOGICAL(CAR(nthcdr(args, 3)))[0];elseerror("get: invalid inherits argument\n");if (ginherits)setVar(name, val, aenv);elsedefineVar(name, val, aenv);UNPROTECT(2);return val;}/** do_remove has 3 arguments, a list of names to remove, an optional* environment (if missing set it to R_GlobalEnv) and inherits, a logical* indicating whether to look in the parent env if a symbol is not found in* the supplied env. This is ignored if environment is not specified*/SEXP do_remove(SEXP call, SEXP op, SEXP args, SEXP rho){SEXP name, aenv, tsym, tenv, tframe;int ginherits;int set, i;checkArity(op, args);name = CAR(args);if (!isString(name))error("invalid first argument to remove.\n");if (CADR(args) != R_NilValue) {if (TYPEOF(CADR(args)) != ENVSXP)error("invalid envir argument\n");elseaenv = CADR(args);}elseaenv = R_GlobalContext->sysparent;if (isLogical(CAR(nthcdr(args, 2))))ginherits = LOGICAL(CAR(nthcdr(args, 2)))[0];elseerror("get: invalid inherits argument\n");for (i=0 ; i<LENGTH(name) ; i++) {set = 0;tsym = install(CHAR(STRING(name)[i]));tenv = aenv;rmset: for (tframe = FRAME(tenv); tframe != R_NilValue; tframe = CDR(tframe))if (TAG(tframe) == tsym) {unbindVar(tsym, tenv);set = 1;}if (ginherits && !set && (tenv = ENCLOS(tenv)) != R_NilValue)goto rmset;if (!set)warning("remove: variable \"%s\" was not found\n", CHAR(PRINTNAME(tsym)));}return R_NilValue;}/** do_get returns the SEXP associated with the character argument, do_get* needs the environment of the calling function as a default,**/#define FUNSXP 999SEXP do_get(SEXP call, SEXP op, SEXP args, SEXP rho){SEXP rval, genv, t1;SEXPTYPE gmode;int ginherits, where;checkArity(op, args);/* set up the default environment */rval = findVar(CAR(args), rho);if (TYPEOF(rval) == PROMSXP)genv = PRENV(rval);args = evalList(args, rho);if (!isString(CAR(args)) || length(CAR(args)) < 1|| strlen(CHAR(STRING(CAR(args))[0])) == 0)errorcall(call, "invalid first argument\n");elset1 = install(CHAR(STRING(CAR(args))[0]));if (CADR(args) != R_NilValue) {if (TYPEOF(CADR(args)) == REALSXP || TYPEOF(CADR(args)) == INTSXP) {where = asInteger(CADR(args));genv = sysframe(where,R_GlobalContext);}else if (TYPEOF(CADR(args)) != ENVSXP)errorcall(call,"invalid envir argument\n");elsegenv = CADR(args);}if (isString(CAR(CDDR(args)))) {if(!strcmp(CHAR(STRING(CAR(CDDR(args)))[0]),"function"))gmode = FUNSXP;elsegmode = str2type(CHAR(STRING(CAR(CDDR(args)))[0]));} else errorcall(call,"invalid mode argument\n");if (isLogical(CAR(nthcdr(args, 3))))ginherits = LOGICAL(CAR(nthcdr(args, 3)))[0];elseerrorcall(call,"invalid inherits argument\n");rval = findVar1(t1, genv, gmode, ginherits);if (PRIMVAL(op)) { /* we have a get */if (rval == R_UnboundValue)errorcall(call,"variable \"%s\" was not found\n", CHAR(PRINTNAME(t1)));rval = eval(rval, genv);NAMED(rval) = 1;return rval;}else {if (rval == R_UnboundValue)ginherits = 0;elseginherits = 1;rval = allocVector(LGLSXP, 1);LOGICAL(rval)[0] = ginherits;return (rval);}}SEXP findVar1(SEXP symbol, SEXP rho, SEXPTYPE mode, int inherits){SEXP vl;while (rho != R_NilValue) {vl = findVarInFrame(FRAME(rho), symbol);if (vl != R_UnboundValue ) {if(mode == ANYSXP || TYPEOF(vl) == mode) return vl;if(mode == FUNSXP && (TYPEOF(vl) == CLOSXP ||TYPEOF(vl) == BUILTINSXP ||TYPEOF(vl) == SPECIALSXP)) return (vl);}if (inherits)rho = ENCLOS(rho);elsereturn (R_UnboundValue);}return (SYMVALUE(symbol));}/** for switch, evaluate the first arg, if it is a character then try to match* the name with the remaining args, and evaluate the match, if there is no* match then evaluate the first unnamed arg. If the value of the first arg* is not a character string then coerce it to integer (k) and choose the kth* argument from those that remain provided 0 < k < (nargs-1)* For character matching, if the value is missing then take the next* non-missing arg as the value* then things like* switch(as.character(answer), yes=, YES=1, no=, NO=2, 3)* work*/SEXP switchList(SEXP el, SEXP rho){SEXP h;if (CAR(el) == R_DotsSymbol) {h = findVar(CAR(el), rho);if (h == R_NilValue)return R_NilValue;if (TYPEOF(h) != DOTSXP) {if (h == R_MissingArg)return R_MissingArg;error("... used in an incorrect context\n");}return h;}elseerror("bad parameter in switch \n");}SEXP do_switch(SEXP call, SEXP op, SEXP args, SEXP rho){int argval;SEXP x, y, w;x = eval(CAR(args), rho);if (!isVector(x) && length(x) != 1)error("switch: EXPR must return a length 1 vector\n");PROTECT(w = switchList(CDR(args), rho));if (isString(x)) {for (y = w; y != R_NilValue; y = CDR(y))if (TAG(y) != R_NilValue && pmatch(STRING(x)[0], TAG(y), 1)) {while (CAR(y) == R_MissingArg && y != R_NilValue)y = CDR(y);UNPROTECT(1);return (eval(CAR(y), rho));}for (y = w; y != R_NilValue; y = CDR(y))if (TAG(y) == R_NilValue) {UNPROTECT(1);return (eval(CAR(y), rho));}UNPROTECT(1);return R_NilValue;}argval = asInteger(x);if (argval <= 0 || argval > (length(w))) {UNPROTECT(1);return R_NilValue;}x = eval(CAR(nthcdr(w, argval - 1)), rho);UNPROTECT(1);return x;}