Open hturner opened 4 months ago
Options:
TODO:
c_pr
next to r_pr
. If the number of columns is larger than the max.print
argument, truncate the number of coumns printed and message the user.c_pr
argument to the C macros https://github.com/r-devel/r-svn/blob/09f3acb92dcc180636a7c4e257491302e9a22ae8/src/main/format.c#L106captureOutput
(?) to create testsThis seems to work
Index: src/main/printarray.c
===================================================================
--- src/main/printarray.c (revision 86890)
+++ src/main/printarray.c (working copy)
@@ -116,8 +116,9 @@
* We define macros that will be re-used in the other functions,
* and comment the common code here (only):
*/
-static void printLogicalMatrix(SEXP sx, int offset, int r_pr, int r, int c,
- SEXP rl, SEXP cl, const char *rn, const char *cn,
+static void printLogicalMatrix(SEXP sx, int offset, int r_pr, int c_pr,
+ int r, int c, SEXP rl, SEXP cl,
+ const char *rn, const char *cn,
Rboolean print_ij)
{
/* initialization; particularly of row labels, rl= dimnames(.)[[1]] and
@@ -181,7 +182,7 @@
MatrixRowLabel(rl, i, rlabw, lbloff); \
Rprintf("\n"); \
} \
- else while (jmin < c) { \
+ else while (jmin < c_pr) { \
/* print columns jmin:(jmax-1) where jmax has to be determined first */ \
\
width = rlabw; \
@@ -190,7 +191,7 @@
width += w[jmax] _W_EXTRA_; \
jmax++; \
} \
- while (jmax < c && width + w[jmax] _W_EXTRA_ < R_print.width); \
+ while (jmax < c_pr && width + w[jmax] _W_EXTRA_ < R_print.width); \
\
_PRINT_ROW_LAB; \
\
@@ -220,7 +221,7 @@
}
-static void printIntegerMatrix(SEXP sx, int offset, int r_pr, int r, int c,
+static void printIntegerMatrix(SEXP sx, int offset, int r_pr, int c_pr, int r, int c,
SEXP rl, SEXP cl, const char *rn, const char *cn,
Rboolean print_ij)
{
@@ -233,7 +234,7 @@
Rprintf("%s", EncodeInteger(x[i + j * (R_xlen_t) r], w[j])));
}
-static void printRealMatrix(SEXP sx, int offset, int r_pr, int r, int c,
+static void printRealMatrix(SEXP sx, int offset, int r_pr, int c_pr, int r, int c,
SEXP rl, SEXP cl, const char *rn, const char *cn,
Rboolean print_ij)
{
@@ -250,7 +251,7 @@
w[j], d[j], e[j], OutDec)) );
}
-static void printComplexMatrix(SEXP sx, int offset, int r_pr, int r, int c,
+static void printComplexMatrix(SEXP sx, int offset, int r_pr, int c_pr, int r, int c,
SEXP rl, SEXP cl, const char *rn, const char *cn,
Rboolean print_ij)
{
@@ -283,7 +284,7 @@
wi[j], di[j], ei[j], OutDec)) )
}
-static void printStringMatrix(SEXP sx, int offset, int r_pr, int r, int c,
+static void printStringMatrix(SEXP sx, int offset, int r_pr, int c_pr, int r, int c,
int quote, int right, SEXP rl, SEXP cl,
const char *rn, const char *cn, Rboolean print_ij)
{
@@ -309,7 +310,7 @@
w[j], quote, right)) );
}
-static void printRawMatrix(SEXP sx, int offset, int r_pr, int r, int c,
+static void printRawMatrix(SEXP sx, int offset, int r_pr, int c_pr, int r, int c,
SEXP rl, SEXP cl, const char *rn, const char *cn,
Rboolean print_ij)
{
@@ -345,28 +346,32 @@
return;
}
r_pr = r;
+ int c_pr = c;
+ if (c > 0 && R_print.max < c)
+ c_pr = R_print.max;
if(c > 0 && R_print.max / c < r) /* avoid integer overflow */
/* using floor(), not ceil(), since 'c' could be huge: */
r_pr = R_print.max / c;
+ if(c > c_pr && r_pr < 1 && r > 0) r_pr = 1;
switch (TYPEOF(x)) {
case LGLSXP:
- printLogicalMatrix(x, offset, r_pr, r, c, rl, cl, rn, cn, TRUE);
+ printLogicalMatrix(x, offset, r_pr, c_pr, r, c, rl, cl, rn, cn, TRUE);
break;
case INTSXP:
- printIntegerMatrix(x, offset, r_pr, r, c, rl, cl, rn, cn, TRUE);
+ printIntegerMatrix(x, offset, r_pr, c_pr, r, c, rl, cl, rn, cn, TRUE);
break;
case REALSXP:
- printRealMatrix (x, offset, r_pr, r, c, rl, cl, rn, cn, TRUE);
+ printRealMatrix (x, offset, r_pr, c_pr, r, c, rl, cl, rn, cn, TRUE);
break;
case CPLXSXP:
- printComplexMatrix(x, offset, r_pr, r, c, rl, cl, rn, cn, TRUE);
+ printComplexMatrix(x, offset, r_pr, c_pr, r, c, rl, cl, rn, cn, TRUE);
break;
case STRSXP:
if (quote) quote = '"';
- printStringMatrix (x, offset, r_pr, r, c, quote, right, rl, cl, rn, cn, TRUE);
+ printStringMatrix (x, offset, r_pr, c_pr, r, c, quote, right, rl, cl, rn, cn, TRUE);
break;
case RAWSXP:
- printRawMatrix (x, offset, r_pr, r, c, rl, cl, rn, cn, TRUE);
+ printRawMatrix (x, offset, r_pr, c_pr, r, c, rl, cl, rn, cn, TRUE);
break;
default:
UNIMPLEMENTED_TYPE("printMatrix", x);
@@ -382,6 +387,17 @@
Rprintf(" [ reached getOption(\"max.print\") -- omitted %d rows ]\n",
r - r_pr);
#endif
+#ifdef ENABLE_NLS
+ if(c_pr < c) // number of formats must be consistent here
+ Rprintf(ngettext(" [ reached getOption(\"max.print\") -- omitted %d column ]\n",
+ " [ reached getOption(\"max.print\") -- omitted %d columns ]\n",
+ c - c_pr),
+ c - c_pr);
+#else
+ if(c_pr < c)
+ Rprintf(" [ reached getOption(\"max.print\") -- omitted %d columns ]\n",
+ c - c_pr);
+#endif
vmaxset(vmax);
}
@@ -447,6 +463,7 @@
Rboolean do_ij = nb > 0,
i_last = (i == nb_pr - 1); /* for the last slice */
int use_nr = i_last ? nr_last : nr;
+ int use_nc = nc;
if(do_ij) {
int k = 1;
Rprintf(", ");
@@ -472,24 +489,24 @@
}
switch (TYPEOF(x)) {
case LGLSXP:
- printLogicalMatrix(x, i * b, use_nr, nr, nc, dn0, dn1, rn, cn, do_ij);
+ printLogicalMatrix(x, i * b, use_nr, use_nc, nr, nc, dn0, dn1, rn, cn, do_ij);
break;
case INTSXP:
- printIntegerMatrix(x, i * b, use_nr, nr, nc, dn0, dn1, rn, cn, do_ij);
+ printIntegerMatrix(x, i * b, use_nr, use_nc, nr, nc, dn0, dn1, rn, cn, do_ij);
break;
case REALSXP:
- printRealMatrix (x, i * b, use_nr, nr, nc, dn0, dn1, rn, cn, do_ij);
+ printRealMatrix (x, i * b, use_nr, use_nc, nr, nc, dn0, dn1, rn, cn, do_ij);
break;
case CPLXSXP:
- printComplexMatrix(x, i * b, use_nr, nr, nc, dn0, dn1, rn, cn, do_ij);
+ printComplexMatrix(x, i * b, use_nr, use_nc, nr, nc, dn0, dn1, rn, cn, do_ij);
break;
case STRSXP:
if (quote) quote = '"';
- printStringMatrix (x, i * b, use_nr, nr, nc,
+ printStringMatrix (x, i * b, use_nr, use_nc, nr, nc,
quote, right, dn0, dn1, rn, cn, do_ij);
break;
case RAWSXP:
- printRawMatrix (x, i * b, use_nr, nr, nc, dn0, dn1, rn, cn, do_ij);
+ printRawMatrix (x, i * b, use_nr, use_nc, nr, nc, dn0, dn1, rn, cn, do_ij);
break;
}
Rprintf("\n");
Full file
/*
* R : A Computer Language for Statistical Data Analysis
* Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka
* Copyright (C) 2000--2023 The R Core Team
* Copyright (C) 2001--2012 The R Foundation
*
* 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 printMatrix()
* printArray()
*
* See ./printutils.c for general remarks on Printing
* and the Encode.. utils.
*
* See ./format.c for the format_FOO_ functions used below.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <Defn.h>
#include <Print.h>
#include <stdlib.h> /* for div() */
/* We need display width of a string.
Used only for row/column names found by GetMatrixDimnames,
so in native encoding. (NULL ones from do_prmatrix are skipped.)
*/
int Rstrwid(const char *str, int slen, int enc, int quote); /* from printutils.c */
#define strwidth(x) Rstrwid(x, (int) strlen(x), CE_NATIVE, 0)
/* ceil_DIV(a,b) := ceil(a / b) in _int_ arithmetic : */
static R_INLINE
int ceil_DIV(int a, int b)
{
div_t div_res = div(a, b);
return div_res.quot + ((div_res.rem != 0) ? 1 : 0);
}
/* moved from printutils.c */
static void MatrixColumnLabel(SEXP cl, int j, int w)
{
if (!isNull(cl)) {
SEXP tmp = STRING_ELT(cl, j);
int l = (tmp == NA_STRING) ? R_print.na_width_noquote : Rstrlen(tmp, 0);
Rprintf("%*s%s", w-l, "",
EncodeString(tmp, l, 0, Rprt_adj_left));
}
else {
Rprintf("%*s[,%ld]", w-IndexWidth(j+1)-3, "", (long)j+1);
}
}
static void RightMatrixColumnLabel(SEXP cl, int j, int w)
{
if (!isNull(cl)) {
SEXP tmp = STRING_ELT(cl, j);
int l = (tmp == NA_STRING) ? R_print.na_width_noquote : Rstrlen(tmp, 0);
/* This does not work correctly at least on FC3
Rprintf("%*s", R_print.gap+w,
EncodeString(tmp, l, 0, Rprt_adj_right)); */
Rprintf("%*s%s", R_print.gap+w-l, "",
EncodeString(tmp, l, 0, Rprt_adj_right));
}
else {
Rprintf("%*s[,%ld]%*s", R_print.gap, "", (long)j+1, w-IndexWidth(j+1)-3, "");
}
}
static void LeftMatrixColumnLabel(SEXP cl, int j, int w)
{
if (!isNull(cl)) {
SEXP tmp = STRING_ELT(cl, j);
int l = (tmp == NA_STRING) ? R_print.na_width_noquote : Rstrlen(tmp, 0);
Rprintf("%*s%s%*s", R_print.gap, "",
EncodeString(tmp, l, 0, Rprt_adj_left), w-l, "");
}
else {
Rprintf("%*s[,%ld]%*s", R_print.gap, "", (long)j+1, w-IndexWidth(j+1)-3, "");
}
}
static void MatrixRowLabel(SEXP rl, int i, int rlabw, int lbloff)
{
if (!isNull(rl)) {
SEXP tmp = STRING_ELT(rl, i);
int l = (tmp == NA_STRING) ? R_print.na_width_noquote : Rstrlen(tmp, 0);
Rprintf("\n%*s%s%*s", lbloff, "",
EncodeString(tmp, l, 0, Rprt_adj_left),
rlabw-l-lbloff, "");
}
else {
Rprintf("\n%*s[%ld,]", rlabw-3-IndexWidth(i + 1), "", (long)i+1);
}
}
/* This is the first (of 6) print<TYPE>Matrix() functions.
* We define macros that will be re-used in the other functions,
* and comment the common code here (only):
*/
static void printLogicalMatrix(SEXP sx, int offset, int r_pr, int c_pr,
int r, int c, SEXP rl, SEXP cl,
const char *rn, const char *cn,
Rboolean print_ij)
{
/* initialization; particularly of row labels, rl= dimnames(.)[[1]] and
* rn = names(dimnames(.))[1] : */
#define _PRINT_INIT_rl_rn \
int *w = (int *) R_alloc(c, sizeof(int)); \
int width, rlabw = -1, clabw = -1; /* -Wall */ \
int i, j, jmin = 0, jmax = 0, lbloff = 0; \
\
if (!isNull(rl)) \
formatString(STRING_PTR_RO(rl), r, &rlabw, 0); \
else \
rlabw = IndexWidth(r + 1) + 3; \
\
if (rn) { \
int rnw = strwidth(rn); \
if ( rnw < rlabw + R_MIN_LBLOFF ) \
lbloff = R_MIN_LBLOFF; \
else \
lbloff = rnw - rlabw; \
\
rlabw += lbloff; \
}
# define _COMPUTE_W2_(_FORMAT_j_, _LAST_j_) \
/* compute w[j] = column-width of j(+1)-th column : */ \
for (j = 0; j < c; j++) { \
if(print_ij) { _FORMAT_j_; } else w[j] = 0; \
\
if (!isNull(cl)) { \
const void *vmax = vmaxget(); \
if(STRING_ELT(cl, j) == NA_STRING) \
clabw = R_print.na_width_noquote; \
else clabw = strwidth(translateChar(STRING_ELT(cl, j))); \
vmaxset(vmax); \
} else \
clabw = IndexWidth(j + 1) + 3; \
\
if (w[j] < clabw) \
w[j] = clabw; \
_LAST_j_; \
}
# define _COMPUTE_W_(F_j) _COMPUTE_W2_(F_j, w[j] += R_print.gap)
// _LAST_j ------------------- for all but String
# define _PRINT_ROW_LAB \
\
if (cn != NULL) \
Rprintf("%*s%s\n", rlabw, "", cn); \
if (rn != NULL) \
Rprintf("%*s", -rlabw, rn); \
else \
Rprintf("%*s", rlabw, "")
# define _PRINT_MATRIX_(_W_EXTRA_, DO_COLUMN_LABELS, ENCODE_I_J) \
\
if (c == 0) { \
_PRINT_ROW_LAB; \
for (i = 0; i < r; i++) \
MatrixRowLabel(rl, i, rlabw, lbloff); \
Rprintf("\n"); \
} \
else while (jmin < c_pr) { \
/* print columns jmin:(jmax-1) where jmax has to be determined first */ \
\
width = rlabw; \
/* initially, jmax = jmin */ \
do { \
width += w[jmax] _W_EXTRA_; \
jmax++; \
} \
while (jmax < c_pr && width + w[jmax] _W_EXTRA_ < R_print.width); \
\
_PRINT_ROW_LAB; \
\
DO_COLUMN_LABELS; \
\
for (i = 0; i < r_pr; i++) { \
MatrixRowLabel(rl, i, rlabw, lbloff); /* starting with an "\n" */ \
if(print_ij) for (j = jmin; j < jmax; j++) { \
ENCODE_I_J; \
} \
} \
Rprintf("\n"); \
jmin = jmax; \
}
# define STD_ColumnLabels \
for (j = jmin; j < jmax ; j++) \
MatrixColumnLabel(cl, j, w[j])
_PRINT_INIT_rl_rn;
const int *x = LOGICAL_RO(sx) + offset;
_COMPUTE_W_( formatLogical(&x[j * (R_xlen_t) r], (R_xlen_t) r, &w[j]) );
_PRINT_MATRIX_( , STD_ColumnLabels,
Rprintf("%s", EncodeLogical(x[i + j * (R_xlen_t) r], w[j])));
}
static void printIntegerMatrix(SEXP sx, int offset, int r_pr, int c_pr, int r, int c,
SEXP rl, SEXP cl, const char *rn, const char *cn,
Rboolean print_ij)
{
_PRINT_INIT_rl_rn;
const int *x = INTEGER_RO(sx) + offset;
_COMPUTE_W_( formatInteger(&x[j * (R_xlen_t) r], (R_xlen_t) r, &w[j]) );
_PRINT_MATRIX_( , STD_ColumnLabels,
Rprintf("%s", EncodeInteger(x[i + j * (R_xlen_t) r], w[j])));
}
static void printRealMatrix(SEXP sx, int offset, int r_pr, int c_pr, int r, int c,
SEXP rl, SEXP cl, const char *rn, const char *cn,
Rboolean print_ij)
{
_PRINT_INIT_rl_rn;
const double *x = REAL_RO(sx) + offset;
int *d = (int *) R_alloc(c, sizeof(int)),
*e = (int *) R_alloc(c, sizeof(int));
_COMPUTE_W_( formatReal(&x[j * (R_xlen_t) r], (R_xlen_t) r, &w[j],
&d[j], &e[j], 0) );
_PRINT_MATRIX_( , STD_ColumnLabels,
Rprintf("%s", EncodeReal0(x[i + j * (R_xlen_t) r],
w[j], d[j], e[j], OutDec)) );
}
static void printComplexMatrix(SEXP sx, int offset, int r_pr, int c_pr, int r, int c,
SEXP rl, SEXP cl, const char *rn, const char *cn,
Rboolean print_ij)
{
_PRINT_INIT_rl_rn;
const Rcomplex *x = COMPLEX_RO(sx) + offset;
int *dr = (int *) R_alloc(c, sizeof(int)),
*er = (int *) R_alloc(c, sizeof(int)),
*wr = (int *) R_alloc(c, sizeof(int)),
*di = (int *) R_alloc(c, sizeof(int)),
*ei = (int *) R_alloc(c, sizeof(int)),
*wi = (int *) R_alloc(c, sizeof(int));
/* Determine the column widths */
_COMPUTE_W_( formatComplex(&x[j * (R_xlen_t) r], (R_xlen_t) r,
&wr[j], &dr[j], &er[j],
&wi[j], &di[j], &ei[j], 0);
w[j] = wr[j] + wi[j] + 2 );
_PRINT_MATRIX_( , STD_ColumnLabels,
if (ISNA(x[i + j * (R_xlen_t) r].r) ||
ISNA(x[i + j * (R_xlen_t) r].i))
Rprintf("%s", EncodeReal0(NA_REAL, w[j], 0, 0, OutDec));
else
/* Note that the label printing may modify w[j], so wr[j] is not
necessarily still valid, and we use w[j] - wi[j] - 2 */
Rprintf("%s",
EncodeComplex(x[i + j * (R_xlen_t) r],
w[j] - wi[j] - 2, dr[j], er[j],
wi[j], di[j], ei[j], OutDec)) )
}
static void printStringMatrix(SEXP sx, int offset, int r_pr, int c_pr, int r, int c,
int quote, int right, SEXP rl, SEXP cl,
const char *rn, const char *cn, Rboolean print_ij)
{
_PRINT_INIT_rl_rn;
const SEXP *x = STRING_PTR_RO(sx)+offset;
_COMPUTE_W2_( formatString(&x[j * (R_xlen_t) r], (R_xlen_t) r,
&w[j], quote), );
_PRINT_MATRIX_( + R_print.gap,
/* DO_COLUMN_LABELS = */
if (right) {
for (j = jmin; j < jmax ; j++)
RightMatrixColumnLabel(cl, j, w[j]);
}
else {
for (j = jmin; j < jmax ; j++)
LeftMatrixColumnLabel(cl, j, w[j]);
},
/* ENCODE_I = */
Rprintf("%*s%s", R_print.gap, "",
EncodeString(x[i + j * (R_xlen_t) r],
w[j], quote, right)) );
}
static void printRawMatrix(SEXP sx, int offset, int r_pr, int c_pr, int r, int c,
SEXP rl, SEXP cl, const char *rn, const char *cn,
Rboolean print_ij)
{
_PRINT_INIT_rl_rn;
const Rbyte *x = RAW_RO(sx) + offset;
_COMPUTE_W_( formatRaw(&x[j * (R_xlen_t) r], (R_xlen_t) r, &w[j]) )
_PRINT_MATRIX_( , STD_ColumnLabels,
Rprintf("%*s%s", w[j]-2, "",
EncodeRaw(x[i + j * (R_xlen_t) r], "")) );
}
/* rm and cn are found by GetMatrixDimnames so in native encoding */
attribute_hidden
void printMatrix(SEXP x, int offset, SEXP dim, int quote, int right,
SEXP rl, SEXP cl, const char *rn, const char *cn)
{
/* 'rl' and 'cl' are dimnames(.)[[1]] and dimnames(.)[[2]] whereas
* 'rn' and 'cn' are the names(dimnames(.))
*/
const void *vmax = vmaxget();
const int *pdim = INTEGER_RO(dim);
int r = pdim[0];
int c = pdim[1], r_pr;
/* PR#850 */
if ((rl != R_NilValue) && (r > length(rl)))
error(_("too few row labels"));
if ((cl != R_NilValue) && (c > length(cl)))
error(_("too few column labels"));
if (r == 0 && c == 0) { // FIXME? names(dimnames(.)) :
Rprintf("<0 x 0 matrix>\n");
return;
}
r_pr = r;
//
int c_pr = c > R_print.max ? R_print.max : c;
if(c > 0 && R_print.max / c < r) /* avoid integer overflow */
/* using floor(), not ceil(), since 'c' could be huge: */
r_pr = R_print.max / c;
if(c > c_pr && r_pr < 1 && r > 0) r_pr = 1;
switch (TYPEOF(x)) {
case LGLSXP:
printLogicalMatrix(x, offset, r_pr, c_pr, r, c, rl, cl, rn, cn, TRUE);
break;
case INTSXP:
printIntegerMatrix(x, offset, r_pr, c_pr, r, c, rl, cl, rn, cn, TRUE);
break;
case REALSXP:
printRealMatrix (x, offset, r_pr, c_pr, r, c, rl, cl, rn, cn, TRUE);
break;
case CPLXSXP:
printComplexMatrix(x, offset, r_pr, c_pr, r, c, rl, cl, rn, cn, TRUE);
break;
case STRSXP:
if (quote) quote = '"';
printStringMatrix (x, offset, r_pr, c_pr, r, c, quote, right, rl, cl, rn, cn, TRUE);
break;
case RAWSXP:
printRawMatrix (x, offset, r_pr, c_pr, r, c, rl, cl, rn, cn, TRUE);
break;
default:
UNIMPLEMENTED_TYPE("printMatrix", x);
}
if (r_pr < r || c_pr < c) {
Rprintf(" [ reached getOption(\"max.print\") -- omitted");
if (r_pr < r) {
Rprintf(ngettext(" %d row", " %d rows", r - r_pr), r - r_pr);
}
if (c_pr < c) {
if (r_pr < r) Rprintf(" and");
Rprintf(ngettext(" %d column", " %d columns", c - c_pr), c - c_pr);
}
Rprintf(" ]\n");
}
vmaxset(vmax);
}
attribute_hidden
void printArray(SEXP x, SEXP dim, int quote, int right, SEXP dimnames)
{
/* == printArray(.) */
const void *vmax = vmaxget();
int ndim = LENGTH(dim), nprotect = 0;
const char *rn = NULL, *cn = NULL;
if (ndim == 1)
printVector(x, 1, quote);
else if (ndim == 2) {
SEXP rl, cl;
GetMatrixDimnames(x, &rl, &cl, &rn, &cn);
printMatrix(x, 0, dim, quote, 0, rl, cl, rn, cn);
}
else { /* ndim >= 3 */
SEXP dn, dnn, dn0, dn1;
const int *dims = INTEGER_RO(dim);
int i, j, nb, nb_pr, nr_last,
nr = dims[0], nc = dims[1],
b = nr * nc;
Rboolean max_reached, has_dimnames = (dimnames != R_NilValue),
has_dnn = has_dimnames;
if (!has_dimnames) {
dn0 = R_NilValue;
dn1 = R_NilValue;
dnn = R_NilValue; /* -Wall */
}
else {
dn0 = VECTOR_ELT(dimnames, 0);
dn1 = VECTOR_ELT(dimnames, 1);
dnn = getAttrib(dimnames, R_NamesSymbol);
has_dnn = !isNull(dnn);
if ( has_dnn ) {
PROTECT(dnn);
nprotect++;
rn = (char *) translateChar(STRING_ELT(dnn, 0));
cn = (char *) translateChar(STRING_ELT(dnn, 1));
}
}
/* nb := #{entries} in a slice such as x[1,1,..] or equivalently,
* the number of matrix slices x[ , , *, ..] which
* are printed as matrices -- if options("max.print") allows */
for (i = 2, nb = 1; i < ndim; i++)
nb *= dims[i];
max_reached = (b > 0 && R_print.max / b < nb);
if (max_reached) { /* i.e., also b > 0, nr > 0, nc > 0, nb > 0 */
/* nb_pr := the number of matrix slices to be printed */
nb_pr = ceil_DIV(R_print.max, b);
/* for the last, (nb_pr)th matrix slice, use only nr_last rows;
* using floor(), not ceil(), since 'nc' could be huge: */
nr_last = (R_print.max - b * (nb_pr - 1)) / nc;
if(nr_last == 0) { nb_pr--; nr_last = nr; }
} else {
nb_pr = (nb > 0) ? nb : 1; // do print *something* when dim = c(a,b,0)
nr_last = nr;
}
for (i = 0; i < nb_pr; i++) {
Rboolean do_ij = nb > 0,
i_last = (i == nb_pr - 1); /* for the last slice */
int use_nr = i_last ? nr_last : nr;
int use_nc = nc;
if(do_ij) {
int k = 1;
Rprintf(", ");
for (j = 2 ; j < ndim; j++) {
int l = (i / k) % dims[j] + 1;
if (has_dimnames &&
((dn = VECTOR_ELT(dimnames, j)) != R_NilValue)) {
if ( has_dnn )
Rprintf(", %s = %s",
translateChar(STRING_ELT(dnn, j)),
translateChar(STRING_ELT(dn, l - 1)));
else
Rprintf(", %s", translateChar(STRING_ELT(dn, l - 1)));
} else
Rprintf(", %d", l);
k *= dims[j];
}
Rprintf("\n\n");
} else { // nb == 0 -- e.g. <2 x 3 x 0 array of logical>
for (i = 0; i < ndim; i++)
Rprintf("%s%d", (i == 0) ? "<" : " x ", dims[i]);
Rprintf(" array of %s>\n", CHAR(type2str_nowarn(TYPEOF(x))));
}
switch (TYPEOF(x)) {
case LGLSXP:
printLogicalMatrix(x, i * b, use_nr, use_nc, nr, nc, dn0, dn1, rn, cn, do_ij);
break;
case INTSXP:
printIntegerMatrix(x, i * b, use_nr, use_nc, nr, nc, dn0, dn1, rn, cn, do_ij);
break;
case REALSXP:
printRealMatrix (x, i * b, use_nr, use_nc, nr, nc, dn0, dn1, rn, cn, do_ij);
break;
case CPLXSXP:
printComplexMatrix(x, i * b, use_nr, use_nc, nr, nc, dn0, dn1, rn, cn, do_ij);
break;
case STRSXP:
if (quote) quote = '"';
printStringMatrix (x, i * b, use_nr, use_nc, nr, nc,
quote, right, dn0, dn1, rn, cn, do_ij);
break;
case RAWSXP:
printRawMatrix (x, i * b, use_nr, use_nc, nr, nc, dn0, dn1, rn, cn, do_ij);
break;
}
Rprintf("\n");
}
if(max_reached && nb_pr < nb) {
Rprintf(" [ reached getOption(\"max.print\") -- omitted");
if(nr_last < nr) Rprintf(" %d row(s) and", nr - nr_last);
Rprintf(" %d matrix slice(s) ]\n", nb - nb_pr);
}
}
UNPROTECT(nprotect);
vmaxset(vmax);
}
Potential tests for print-tests.R
## max.print and max
## bug 15027 https://bugs.r-project.org/show_bug.cgi?id=15027
## whenever the columns are larger than max.print, no values inside the matrix are displayed
print(matrix(nrow = 100, ncol = 4), max = 5) ## works
## fix: ommiting rows **and** columns and warning printed
## case: omiting rows and columns
options(max.print = 100)
matrix(nrow=20000,ncol=20000)
print(matrix(nrow = 10, ncol = 4), max = 3)
## case: omitting rows
print(matrix(nrow = 10, ncol = 2), max = 5)
## case: omitting cols, at least one row prints
print(matrix(nrow = 1, ncol = 6), max = 5)
## in R 4.4.0 there should be a warning for ommited rows (NEW BUG)
print(array(dim= c(2, 2, 1)), max = 2)
## this does not print anything but it should show
## at least one element according to the logic of max.print
print(array(dim= c(2, 2, 1)), max = 1)
Patch submitted at https://bugs.r-project.org/show_bug.cgi?id=15027#c6
It was great working with you on this patch @hanneoberman @loreabad6 @Abhi-1U @ekaterina-akimova!
Still needs a related fix for arrays, in case anyone wants to work on one:
print(array(dim = c(2, 2, 1)), max = 1)
#> [ reached getOption("max.print") -- omitted 1 matrix slice(s) ]
This bug was analysed by @huizezhang-sherry and @gmbecker and the Bug BBQ in 2024 and also by @elinw on the original bug report.
I think a potential solution would be to avoid printing the column headers from matrices/data.frames when all rows are omitted due to the
max
argument or themax.print
option. This is consistent with the behaviour for arrays, e.g.(Note the message is misleading here, see #3).
According to
?print.data.frame
, this functionSo, without digging too deep, I think a fix for both cases might be implemented by modifying the C function
printMatrix
, e.g. changing the logic to skip printing the matrix and just print the message when there are zero rows.Potential a good issue for someone new to working on C code in base R.