The R Project SVN R

Rev

Rev 81461 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

/*
 *  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;
    }
}