Rev 35751 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Language for Statistical Data Analysis* Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka* Copyright (C) 1997--2005 The R Development Core Team** 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*** See ./printutils.c for general remarks on Printing* and the Encode.. utils.** See ./format.c for the format_Foo_ functions.*//* <UTF8> char here is handled as a whole */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include "Defn.h"#include "Rmath.h" /* imax2 */#include "Print.h"/* .Internal(paste(args, sep, collapse))** do_paste uses two passes to paste the arguments (in CAR(args)) together.* The first pass calculates the width of the paste buffer,* then it is alloc-ed and the second pass stuffs the information in.*/SEXP do_paste(SEXP call, SEXP op, SEXP args, SEXP env){SEXP ans, collapse, sep, x, tmpchar;int i, j, k, maxlen, nx, pwidth, sepw;char *s, *buf;checkArity(op, args);/* We use formatting and so we *//* must initialize printing. */PrintDefaults(env);/* Check the arguments */x = CAR(args);if (!isVectorList(x))errorcall(call, _("invalid first argument"));sep = CADR(args);if (!isString(sep) || LENGTH(sep) <= 0)errorcall(call, _("invalid separator"));sep = STRING_ELT(sep, 0);sepw = strlen(CHAR(sep)); /* not LENGTH as might contain \0 */collapse = CADDR(args);if (!isNull(collapse))if(!isString(collapse) || LENGTH(collapse) <= 0)errorcall(call, _("invalid '%s' argument"), "collapse");/* Maximum argument length and *//* check for arguments of list type */nx = length(x);maxlen = 0;for (j = 0; j < nx; j++) {if (!isString(VECTOR_ELT(x, j)))error(_("non-string argument to Internal paste"));if(length(VECTOR_ELT(x, j)) > maxlen)maxlen = length(VECTOR_ELT(x, j));}if(maxlen == 0)return (!isNull(collapse)) ? mkString("") : allocVector(STRSXP, 0);PROTECT(ans = allocVector(STRSXP, maxlen));for (i = 0; i < maxlen; i++) {pwidth = 0;for (j = 0; j < nx; j++) {k = length(VECTOR_ELT(x, j));if (k > 0)pwidth += strlen(CHAR(STRING_ELT(VECTOR_ELT(x, j), i % k)));}pwidth += (nx - 1) * sepw;tmpchar = allocString(pwidth);buf = CHAR(tmpchar);for (j = 0; j < nx; j++) {k = length(VECTOR_ELT(x, j));if (k > 0) {s = CHAR(STRING_ELT(VECTOR_ELT(x, j), i % k));strcpy(buf, s);buf += strlen(s);}if (j != nx - 1 && sepw != 0) {strcpy(buf, CHAR(sep));buf += sepw;}}SET_STRING_ELT(ans, i, tmpchar);}/* Now collapse, if required. */if(collapse != R_NilValue && (nx=LENGTH(ans)) != 0) {sep = STRING_ELT(collapse, 0);sepw = strlen(CHAR(sep));pwidth = 0;for (i = 0; i < nx; i++)pwidth += strlen(CHAR(STRING_ELT(ans, i)));pwidth += (nx - 1) * sepw;tmpchar = allocString(pwidth);buf = CHAR(tmpchar);for (i = 0; i < nx; i++) {if(i > 0) {strcpy(buf, CHAR(sep));buf += sepw;}s = CHAR(STRING_ELT(ans, i));strcpy(buf, s);while (*buf)buf++;}PROTECT(tmpchar);ans = allocVector(STRSXP, 1);UNPROTECT(1);SET_STRING_ELT(ans, 0, tmpchar);}UNPROTECT(1);return ans;}/* format.default(x, trim, digits, nsmall, width, justify, na.encode,scientific) */SEXP do_format(SEXP call, SEXP op, SEXP args, SEXP env){SEXP l, x, y, swd;int i, il, n, digits, trim = 0, nsmall = 0, wd = 0, adj = -1, na, sci = 0;int w, d, e;int wi, di, ei;char *strp;checkArity(op, args);PrintDefaults(env);if (!isVector(x = CAR(args)))errorcall(call, _("first argument must be atomic"));args = CDR(args);trim = asLogical(CAR(args));if (trim == NA_INTEGER)errorcall(call, _("invalid '%s' argument"), "trim");args = CDR(args);if (!isNull(CAR(args))) {digits = asInteger(CAR(args));if (digits == NA_INTEGER || digits < R_MIN_DIGITS_OPT|| digits > R_MAX_DIGITS_OPT)errorcall(call, _("invalid '%s' argument"), "digits");R_print.digits = digits;}args = CDR(args);nsmall = asInteger(CAR(args));if (nsmall == NA_INTEGER || nsmall < 0 || nsmall > 20)errorcall(call, _("invalid '%s' argument"), "nsmall");args = CDR(args);if (isNull(swd = CAR(args))) wd = 0; else wd = asInteger(swd);if(wd == NA_INTEGER)errorcall(call, _("invalid '%s' argument"), "width");args = CDR(args);adj = asInteger(CAR(args));if(adj == NA_INTEGER || adj < 0 || adj > 3)errorcall(call, _("invalid '%s' argument"), "justify");args = CDR(args);na = asLogical(CAR(args));if(na == NA_LOGICAL)errorcall(call, _("invalid '%s' argument"), "na.encode");args = CDR(args);if(LENGTH(CAR(args)) != 1)errorcall(call, _("invalid '%s' argument"), "scientific");if(isLogical(CAR(args))) {int tmp = LOGICAL(CAR(args))[0];if(tmp == NA_LOGICAL) sci = NA_INTEGER;else sci = tmp > 0 ?-100 : 100;} else if (isNumeric(CAR(args))) {sci = asInteger(CAR(args));} elseerrorcall(call, _("invalid '%s' argument"), "scientific");if(sci != NA_INTEGER) R_print.scipen = sci;if ((n = LENGTH(x)) <= 0) {PROTECT(y = allocVector(STRSXP, 0));} else {switch (TYPEOF(x)) {case LGLSXP:PROTECT(y = allocVector(STRSXP, n));if (trim) w = 0; else formatLogical(LOGICAL(x), n, &w);w = imax2(w, wd);for (i = 0; i < n; i++) {strp = EncodeLogical(LOGICAL(x)[i], w);SET_STRING_ELT(y, i, mkChar(strp));}break;case INTSXP:PROTECT(y = allocVector(STRSXP, n));if (trim) w = 0;else formatInteger(INTEGER(x), n, &w);w = imax2(w, wd);for (i = 0; i < n; i++) {strp = EncodeInteger(INTEGER(x)[i], w);SET_STRING_ELT(y, i, mkChar(strp));}break;case REALSXP:formatReal(REAL(x), n, &w, &d, &e, nsmall);if (trim) w = 0;w = imax2(w, wd);PROTECT(y = allocVector(STRSXP, n));for (i = 0; i < n; i++) {strp = EncodeReal(REAL(x)[i], w, d, e, OutDec);SET_STRING_ELT(y, i, mkChar(strp));}break;case CPLXSXP:formatComplex(COMPLEX(x), n, &w, &d, &e, &wi, &di, &ei, nsmall);if (trim) wi = w = 0;w = imax2(w, wd); wi = imax2(wi, wd);PROTECT(y = allocVector(STRSXP, n));for (i = 0; i < n; i++) {strp = EncodeComplex(COMPLEX(x)[i], w, d, e, wi, di, ei, OutDec);SET_STRING_ELT(y, i, mkChar(strp));}break;case STRSXP:{/* this has to be different from formatString/EncodeString aswe don't actually want to encode here */char *s, *buff, *q;int b, b0, cnt = 0, j;SEXP s0;w = wd;if (adj != Rprt_adj_none) {for (i = 0; i < n; i++)if (STRING_ELT(x, i) != NA_STRING)w = imax2(w, Rstrlen(STRING_ELT(x, i), 0));else if (na) w = imax2(w, R_print.na_width);} else w = 0;/* now calculate the buffer size needed, in bytes */for (i = 0; i < n; i++)if (STRING_ELT(x, i) != NA_STRING) {il = Rstrlen(STRING_ELT(x, i), 0);cnt = imax2(cnt, LENGTH(STRING_ELT(x, i)) + imax2(0, w-il));} else if (na) cnt = imax2(cnt, R_print.na_width);buff = alloca(cnt+1);PROTECT(y = allocVector(STRSXP, n));for (i = 0; i < n; i++) {if(!na && STRING_ELT(x, i) == NA_STRING) {SET_STRING_ELT(y, i, NA_STRING);} else {q = buff;if(STRING_ELT(x, i) == NA_STRING) s0 = R_print.na_string;else s0 = STRING_ELT(x, i) ;s = CHAR(s0);il = Rstrlen(s0, 0);b = w - il;if(b > 0 && adj != Rprt_adj_left) {b0 = (adj == Rprt_adj_centre) ? b/2 : b;for(j = 0 ; j < b0 ; j++) *q++ = ' ';b -= b0;}for(j = 0; j < LENGTH(s0); j++) *q++ = *s++;if(b > 0 && adj != Rprt_adj_right)for(j = 0 ; j < b ; j++) *q++ = ' ';*q = '\0';SET_STRING_ELT(y, i, mkChar(buff));}}}break;default:errorcall(call, _("Impossible mode ( x )")); y = R_NilValue;/* -Wall */}}if((l = getAttrib(x, R_DimSymbol)) != R_NilValue) {setAttrib(y, R_DimSymbol, l);if((l = getAttrib(x, R_DimNamesSymbol)) != R_NilValue)setAttrib(y, R_DimNamesSymbol, l);} else if((l = getAttrib(x, R_NamesSymbol)) != R_NilValue)setAttrib(y, R_NamesSymbol, l);UNPROTECT(1);return y;}/* format.info(obj) --> 3 integers (w,d,e) with the formatting information* w = total width (#{chars}) per item* d = #{digits} to RIGHT of "."* e = {0:2}. 0: Fixpoint;* 1,2: exponential with 2/3 digit expon.** for complex : 2 x 3 integers for (Re, Im)*/SEXP do_formatinfo(SEXP call, SEXP op, SEXP args, SEXP env){SEXP x;int n, digits, nsmall, no = 1, w, d, e, wi, di, ei;checkArity(op, args);x = CAR(args);n = LENGTH(x);PrintDefaults(env);digits = asInteger(CADR(args));if (!isNull(CADR(args))) {digits = asInteger(CADR(args));if (digits == NA_INTEGER || digits < R_MIN_DIGITS_OPT|| digits > R_MAX_DIGITS_OPT)errorcall(call, _("invalid '%s' argument"), "digits");R_print.digits = digits;}nsmall = asInteger(CADDR(args));if (nsmall == NA_INTEGER || nsmall < 0 || nsmall > 20)errorcall(call, _("invalid '%s' argument"), "nsmall");w = 0;d = 0;e = 0;switch (TYPEOF(x)) {case RAWSXP:formatRaw(RAW(x), n, &w);break;case LGLSXP:formatLogical(LOGICAL(x), n, &w);break;case INTSXP:formatInteger(INTEGER(x), n, &w);break;case REALSXP:no = 3;formatReal(REAL(x), n, &w, &d, &e, nsmall);break;case CPLXSXP:no = 6;wi = di = ei = 0;formatComplex(COMPLEX(x), n, &w, &d, &e, &wi, &di, &ei, nsmall);break;case STRSXP:{int i, il;for (i = 0; i < n; i++)if (STRING_ELT(x, i) != NA_STRING) {il = Rstrlen(STRING_ELT(x, i), 0);if (il > w) w = il;}}break;default:errorcall(call, _("atomic vector arguments only"));}x = allocVector(INTSXP, no);INTEGER(x)[0] = w;if(no > 1) {INTEGER(x)[1] = d;INTEGER(x)[2] = e;}if(no > 3) {INTEGER(x)[3] = wi;INTEGER(x)[4] = di;INTEGER(x)[5] = ei;}return x;}