| /* |
| * R : A Computer Language for Statistical Data Analysis |
| * Copyright (C) 1998-2022 The R Core Team. |
| * Copyright (C) 1995-1998 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, a copy is available at |
| * https://www.R-project.org/Licenses/ |
| * |
| * EXPORTS printVector() |
| * printNamedVector() |
| * printRealVector() |
| * printRealVectorS() |
| * printIntegerVector() |
| * printIntegerVectorS() |
| * printComplexVector() |
| * printComplexVectorS() |
| * |
| * See ./printutils.c for remarks on Printing and the Encoding utils. |
| * See ./format.c for the formatXXXX functions used below. |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif |
| |
| #include "Defn.h" |
| #include "Print.h" |
| #include <R_ext/Itermacros.h> /* for ITERATE_BY_REGION */ |
| |
| #ifdef Win32 |
| #include <trioremap.h> /* for %lld */ |
| #endif |
| |
| #define DO_first_lab \ |
| if (indx) { \ |
| labwidth = IndexWidth(n) + 2; \ |
| /* labwidth may well be \ |
| one more than desired ..*/ \ |
| VectorIndex(1, labwidth); \ |
| width = labwidth; \ |
| } \ |
| else width = 0 |
| |
| #define DO_newline \ |
| Rprintf("\n"); \ |
| if (indx) { \ |
| VectorIndex(i + 1, labwidth); \ |
| width = labwidth; \ |
| } \ |
| else \ |
| width = 0 |
| |
| /* print*Vector (* in {Real, Integer, Complex}) are exported, but no |
| longer directly called by internal R sources (which now call |
| print*VectorS for ALTREP support). Macros are used to prevent drift |
| between print*Vector and print*VectorS. |
| |
| printIntegerVector(INTEGER(x)) and printIntegerVector(x) must |
| always give identical output, unless INTEGER(x) fails, en.g. during |
| allocation. */ |
| |
| /* i must be defined and contain the overall position in the vector |
| because DO_newline uses it |
| ENCCALL is the full invocation of Encode*() which |
| is passed to Rprintf |
| */ |
| |
| /* used for logical, integer, numeric and complex vectors */ |
| #define NUMVECTOR_TIGHTLOOP(ENCCALL) do { \ |
| if (i > 0 && width + w > R_print.width) { \ |
| DO_newline; \ |
| } \ |
| Rprintf("%s", ENCCALL); \ |
| width += w; \ |
| } while(0) |
| |
| /* used when printing character vectors */ |
| #define CHARVECTOR_TIGHTLOOP(ENCCALL) do { \ |
| if (i > 0 && width + w + R_print.gap > R_print.width) { \ |
| DO_newline; \ |
| } \ |
| Rprintf("%*s%s", R_print.gap, "", \ |
| ENCCALL); \ |
| width += w + R_print.gap; \ |
| } while (0) |
| |
| /* used for raw vectors. Could be combined with character vectors |
| above but NB the different second conditions for the if |
| (width + w vs width + w + R_print.gap) and the different increment |
| on width. |
| */ |
| #define RAWVECTOR_TIGHTLOOP(ptr, pos) do { \ |
| if (i > 0 && width + w > R_print.width) { \ |
| DO_newline; \ |
| } \ |
| Rprintf("%*s%s", R_print.gap, "", EncodeRaw(ptr[pos], "")); \ |
| width += w; \ |
| } while (0) |
| |
| static |
| void printLogicalVectorS(SEXP x, R_xlen_t n, int indx) { |
| int w, labwidth=0, width; |
| R_xlen_t i; |
| DO_first_lab; |
| formatLogicalS(x, n, &w); |
| w += R_print.gap; |
| |
| ITERATE_BY_REGION_PARTIAL(x, px, idx, nb, int, LOGICAL, 0, n, |
| for(R_xlen_t j = 0; j < nb; j++) { |
| i = idx + j; /* for Do_newline */ |
| NUMVECTOR_TIGHTLOOP( EncodeLogical(px[j], w) ); |
| }); |
| Rprintf("\n"); |
| } |
| |
| attribute_hidden |
| void printIntegerVector(const int *x, R_xlen_t n, int indx) |
| { |
| int w, labwidth=0, width; |
| |
| DO_first_lab; |
| formatInteger(x, n, &w); |
| w += R_print.gap; |
| |
| for (R_xlen_t i = 0; i < n; i++) { |
| NUMVECTOR_TIGHTLOOP(EncodeInteger(x[i], w)); |
| } |
| Rprintf("\n"); |
| } |
| |
| attribute_hidden |
| void printIntegerVectorS(SEXP x, R_xlen_t n, int indx) |
| { |
| int w, labwidth=0, width; |
| R_xlen_t i; |
| DO_first_lab; |
| formatIntegerS(x, n, &w); |
| w += R_print.gap; |
| |
| ITERATE_BY_REGION_PARTIAL(x, px, idx, nb, int, INTEGER, 0, n, |
| for (R_xlen_t j = 0; j < nb; j++) { |
| i = idx + j; /* for macros */ |
| NUMVECTOR_TIGHTLOOP(EncodeInteger(px[j], w)); |
| }); |
| |
| Rprintf("\n"); |
| } |
| |
| // used in uncmin.c |
| // Not easily converted to printRealVectorS calls |
| attribute_hidden |
| void printRealVector(const double *x, R_xlen_t n, int indx) |
| { |
| int w, d, e, labwidth=0, width; |
| |
| DO_first_lab; |
| formatReal(x, n, &w, &d, &e, 0); |
| w += R_print.gap; |
| |
| for (R_xlen_t i = 0; i < n; i++) { |
| NUMVECTOR_TIGHTLOOP( EncodeReal0(x[i], w, d, e, OutDec) ); |
| } |
| Rprintf("\n"); |
| } |
| |
| attribute_hidden |
| void printRealVectorS(SEXP x, R_xlen_t n, int indx) |
| { |
| int w, d, e, labwidth=0, width; |
| R_xlen_t i; |
| DO_first_lab; |
| formatRealS(x, n, &w, &d, &e, 0); |
| w += R_print.gap; |
| |
| ITERATE_BY_REGION_PARTIAL(x, px, idx, nb, double, REAL, 0, n, |
| for(R_xlen_t j = 0; j < nb; j++) { |
| i = idx + j; /* for macros */ |
| NUMVECTOR_TIGHTLOOP(EncodeReal0(px[j], w, d, e, OutDec)); |
| }); |
| |
| Rprintf("\n"); |
| } |
| |
| #define CMPLX_ISNA(cplx) (ISNA(cplx.r) || ISNA(cplx.i)) |
| attribute_hidden |
| void printComplexVector(const Rcomplex *x, R_xlen_t n, int indx) |
| { |
| int w, wr, dr, er, wi, di, ei, labwidth=0, width; |
| |
| DO_first_lab; |
| formatComplex(x, n, &wr, &dr, &er, &wi, &di, &ei, 0); |
| |
| w = wr + wi + 2; /* +2 for "+" and "i" */ |
| w += R_print.gap; |
| |
| for (R_xlen_t i = 0; i < n; i++) { |
| NUMVECTOR_TIGHTLOOP(CMPLX_ISNA(x[i]) ? |
| EncodeReal0(NA_REAL, w, 0, 0, OutDec) : |
| EncodeComplex(x[i], wr + R_print.gap, |
| dr, er, wi, di, ei, OutDec)); |
| } |
| Rprintf("\n"); |
| } |
| |
| attribute_hidden |
| void printComplexVectorS(SEXP x, R_xlen_t n, int indx) |
| { |
| int w, wr, dr, er, wi, di, ei, labwidth=0, width; |
| R_xlen_t i; |
| DO_first_lab; |
| formatComplexS(x, n, &wr, &dr, &er, &wi, &di, &ei, 0); |
| |
| w = wr + wi + 2; /* +2 for "+" and "i" */ |
| w += R_print.gap; |
| |
| ITERATE_BY_REGION_PARTIAL(x, px, idx, nb, Rcomplex, COMPLEX, 0, n, |
| for(R_xlen_t j = 0; j < nb; j++) { |
| i = idx + j; /* for macros */ |
| NUMVECTOR_TIGHTLOOP(CMPLX_ISNA(px[j]) ? |
| EncodeReal0(NA_REAL, w, 0, 0, OutDec) : |
| EncodeComplex(px[j], wr + R_print.gap , dr, er, wi, di, ei, OutDec)); |
| }); |
| Rprintf("\n"); |
| } |
| |
| |
| static void printStringVector(const SEXP *x, R_xlen_t n, int quote, int indx) |
| { |
| int w, labwidth=0, width; |
| |
| DO_first_lab; |
| formatString(x, n, &w, quote); |
| |
| for (R_xlen_t i = 0; i < n; i++) { |
| if (i > 0 && width + w + R_print.gap > R_print.width) { |
| DO_newline; |
| } |
| Rprintf("%*s%s", R_print.gap, "", |
| EncodeString(x[i], w, quote, R_print.right)); |
| width += w + R_print.gap; |
| } |
| Rprintf("\n"); |
| } |
| |
| static void printStringVectorS(SEXP x, R_xlen_t n, int quote, int indx) |
| { |
| /* because there's no get_region method for ALTSTRINGs |
| we hit the old version if we can to avoid the |
| STRING_ELT in the tight loop. |
| |
| This will work for all nonALTREP STRSXPs as well as whenever |
| the ALTSTRING class is willing to give us a full dataptr from |
| Dataptr_or_null method. */ |
| |
| const SEXP *xptr = (const SEXP *) DATAPTR_OR_NULL(x); |
| if(xptr != NULL) { |
| printStringVector(xptr, n, quote, indx); |
| return; |
| } |
| |
| int w, labwidth=0, width; |
| |
| DO_first_lab; |
| formatStringS(x, n, &w, quote); |
| |
| for (R_xlen_t i = 0; i < n; i++) { |
| CHARVECTOR_TIGHTLOOP( |
| EncodeString(STRING_ELT(x, i), w, quote, R_print.right) |
| ); |
| } |
| Rprintf("\n"); |
| } |
| |
| |
| |
| |
| attribute_hidden |
| void printRawVector(const Rbyte *x, R_xlen_t n, int indx) |
| { |
| int w, labwidth=0, width; |
| |
| DO_first_lab; |
| formatRaw(x, n, &w); |
| w += R_print.gap; |
| |
| for (R_xlen_t i = 0; i < n; i++) { |
| RAWVECTOR_TIGHTLOOP(x, i); |
| } |
| Rprintf("\n"); |
| } |
| |
| |
| static |
| void printRawVectorS(SEXP x, R_xlen_t n, int indx) |
| { |
| int w, labwidth=0, width; |
| R_xlen_t i; |
| DO_first_lab; |
| formatRawS(x, n, &w); |
| w += R_print.gap; |
| |
| ITERATE_BY_REGION_PARTIAL(x, px, idx, nb, Rbyte, RAW, 0, n, |
| for(R_xlen_t j = 0; j < nb; j++) { |
| i = idx + j; /* for macros */ |
| RAWVECTOR_TIGHTLOOP(px, j); |
| }); |
| Rprintf("\n"); |
| } |
| |
| |
| void printVector(SEXP x, int indx, int quote) |
| { |
| /* print R vector x[]; if(indx) print indices; if(quote) quote strings */ |
| R_xlen_t n; |
| |
| if ((n = XLENGTH(x)) != 0) { |
| R_xlen_t n_pr = (n <= R_print.max +1) ? n : R_print.max; |
| /* '...max +1' ==> will omit at least 2 ==> plural in msg below */ |
| switch (TYPEOF(x)) { |
| case LGLSXP: |
| printLogicalVectorS(x, n_pr, indx); |
| break; |
| case INTSXP: |
| printIntegerVectorS(x, n_pr, indx); |
| break; |
| case REALSXP: |
| printRealVectorS(x, n_pr, indx); |
| break; |
| case STRSXP: |
| if (quote) |
| printStringVectorS(x, n_pr, '"', indx); |
| else |
| printStringVectorS(x, n_pr, 0, indx); |
| break; |
| case CPLXSXP: |
| printComplexVectorS(x, n_pr, indx); |
| break; |
| case RAWSXP: |
| printRawVectorS(x, n_pr, indx); |
| break; |
| } |
| if(n_pr < n) |
| Rprintf(" [ reached getOption(\"max.print\") -- omitted %lld entries ]\n", |
| (long long)n - n_pr); |
| } |
| else |
| #define PRINT_V_0 \ |
| switch (TYPEOF(x)) { \ |
| case LGLSXP: Rprintf("logical(0)\n"); break; \ |
| case INTSXP: Rprintf("integer(0)\n"); break; \ |
| case REALSXP: Rprintf("numeric(0)\n"); break; \ |
| case CPLXSXP: Rprintf("complex(0)\n"); break; \ |
| case STRSXP: Rprintf("character(0)\n"); break; \ |
| case RAWSXP: Rprintf("raw(0)\n"); break; \ |
| } |
| PRINT_V_0; |
| } |
| |
| #undef DO_first_lab |
| #undef DO_newline |
| |
| |
| /* The following code prints vectors which have every element named. |
| |
| * Primitives for each type of vector are presented first, followed |
| * by the main (dispatching) function. |
| * 1) These primitives are almost identical... ==> use PRINT_N_VECTOR_SEXP macro |
| * 2) S prints a _space_ in the first column for named vectors; we dont. |
| */ |
| |
| #define PRINT_N_VECTOR_SEXP(INI_FORMAT, PRINT_1) \ |
| { \ |
| int nperline, w, wn; \ |
| R_xlen_t i, j, k, nlines; \ |
| INI_FORMAT; \ |
| \ |
| formatStringS(names, n, &wn, 0); \ |
| if (w < wn) w = wn; \ |
| nperline = R_print.width / (w + R_print.gap); \ |
| if (nperline <= 0) nperline = 1; \ |
| nlines = n / nperline; \ |
| if (n % nperline) nlines += 1; \ |
| \ |
| for (i = 0; i < nlines; i++) { \ |
| if (i) Rprintf("\n"); \ |
| for (j = 0; j < nperline && (k = i * nperline + j) < n; j++) \ |
| Rprintf("%s%*s", \ |
| EncodeString(STRING_ELT(names, k), w, 0, \ |
| Rprt_adj_right), \ |
| R_print.gap, ""); \ |
| Rprintf("\n"); \ |
| for (j = 0; j < nperline && (k = i * nperline + j) < n; j++) \ |
| PRINT_1; \ |
| } \ |
| Rprintf("\n"); \ |
| } |
| |
| static void printNamedLogicalVectorS(SEXP x, R_xlen_t n, SEXP names) |
| PRINT_N_VECTOR_SEXP(formatLogicalS(x, n, &w), |
| Rprintf("%s%*s", EncodeLogical(LOGICAL_ELT(x, k), w), |
| R_print.gap,"")) |
| |
| static void printNamedIntegerVectorS(SEXP x, R_xlen_t n, SEXP names) |
| PRINT_N_VECTOR_SEXP(formatIntegerS(x, n, &w), |
| Rprintf("%s%*s", EncodeInteger(INTEGER_ELT(x, k), w), |
| R_print.gap,"")) |
| |
| #undef INI_F_REAL_S |
| #define INI_F_REAL_S int d, e; formatRealS(x, n, &w, &d, &e, 0) |
| |
| static void printNamedRealVectorS(SEXP x, R_xlen_t n, SEXP names) |
| PRINT_N_VECTOR_SEXP(INI_F_REAL_S, |
| Rprintf("%s%*s", |
| EncodeReal0(REAL_ELT(x, k), w, d, e, OutDec), |
| R_print.gap,"")) |
| |
| #undef INI_F_CPLX_S |
| #define INI_F_CPLX_S \ |
| int wr, dr, er, wi, di, ei; \ |
| formatComplexS(x, n, &wr, &dr, &er, &wi, &di, &ei, 0); \ |
| w = wr + wi + 2; \ |
| Rcomplex tmp |
| |
| #undef P_IMAG_NA |
| #define P_IMAG_NA(VALUE) \ |
| if(ISNAN(VALUE.i)) \ |
| Rprintf("+%si", "NaN"); \ |
| else |
| |
| static void printNamedComplexVectorS(SEXP x, R_xlen_t n, SEXP names) |
| PRINT_N_VECTOR_SEXP(INI_F_CPLX_S, |
| { /* PRINT_1 */ |
| tmp = COMPLEX_ELT(x, k); |
| if(j) Rprintf("%*s", R_print.gap, ""); |
| if (ISNA(tmp.r) || ISNA(tmp.i)) { |
| Rprintf("%s", EncodeReal0(NA_REAL, w, 0, 0, OutDec)); |
| } |
| else { |
| Rprintf("%s", EncodeReal0(tmp.r, wr, dr, er, OutDec)); |
| P_IMAG_NA(tmp) |
| if (tmp.i >= 0) |
| Rprintf("+%si", EncodeReal0(tmp.i, wi, di, ei, OutDec)); |
| else |
| Rprintf("-%si", EncodeReal0(-tmp.i, wi, di, ei, OutDec)); |
| } |
| }) |
| |
| static void printNamedStringVectorS(SEXP x, R_xlen_t n, int quote, SEXP names) |
| PRINT_N_VECTOR_SEXP(formatStringS(x, n, &w, quote), |
| Rprintf("%s%*s", |
| EncodeString(STRING_ELT(x, k), w, quote, |
| Rprt_adj_right), |
| R_print.gap, "")) |
| |
| static void printNamedRawVectorS(SEXP x, R_xlen_t n, SEXP names) |
| PRINT_N_VECTOR_SEXP(formatRawS(x, n, &w), |
| Rprintf("%*s%s%*s", w - 2, "", |
| EncodeRaw(RAW_ELT(x, k), ""), R_print.gap,"")) |
| |
| attribute_hidden |
| void printNamedVector(SEXP x, SEXP names, int quote, const char *title) |
| { |
| |
| if (title != NULL) |
| Rprintf("%s\n", title); |
| |
| R_xlen_t n = XLENGTH(x); |
| if (n != 0) { |
| R_xlen_t n_pr = (n <= R_print.max +1) ? n : R_print.max; |
| /* '...max +1' ==> will omit at least 2 ==> plural in msg below */ |
| switch (TYPEOF(x)) { |
| case LGLSXP: |
| printNamedLogicalVectorS(x, n_pr, names); |
| break; |
| case INTSXP: |
| printNamedIntegerVectorS(x, n_pr, names); |
| break; |
| case REALSXP: |
| printNamedRealVectorS(x, n_pr, names); |
| break; |
| case CPLXSXP: |
| printNamedComplexVectorS(x, n_pr, names); |
| break; |
| case STRSXP: |
| if(quote) quote = '"'; |
| printNamedStringVectorS(x, n_pr, quote, names); |
| break; |
| case RAWSXP: |
| printNamedRawVectorS(x, n_pr, names); |
| break; |
| } |
| if(n_pr < n) |
| Rprintf(" [ reached getOption(\"max.print\") -- omitted %lld entries ]\n", |
| (long long)n - n_pr); |
| } |
| else { |
| Rprintf("named "); |
| PRINT_V_0; |
| } |
| } |