blob: 859c4e136473473d3afe8a9e85e292ed05ba4f82 [file]
/*
* 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;
}
}