Coverage Report

Created: 2026-09-14 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/r-source/src/main/deparse.c
Line
Count
Source
1
/*
2
 *  R : A Computer Language for Statistical Data Analysis
3
 *  Copyright (C) 1997--2026  The R Core Team
4
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; either version 2 of the License, or
9
 *  (at your option) any later version.
10
 *
11
 *  This program is distributed in the hope that it will be useful,
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *  GNU General Public License for more details.
15
 *
16
 *  You should have received a copy of the GNU General Public License
17
 *  along with this program; if not, a copy is available at
18
 *  https://www.R-project.org/Licenses/
19
 *
20
 *
21
 *  IMPLEMENTATION NOTES:
22
 *
23
 *  Deparsing has 3 layers.
24
 *  - The user interfaces, do_deparse(), do_dput(), and do_dump() should
25
 *    not be called from an internal function.
26
 *  - unless nlines > 0, the actual deparsing via deparse2() needs
27
 *    to be done twice, once to count things up and a second time to put
28
 *    them into the string vector for return.
29
 *  - Printing this to a file is handled by the calling routine.
30
 *
31
 *  Current call paths:
32
 *
33
 *    do_deparse() ------------> deparse1WithCutoff()
34
 *    do_dput() -> deparse1() -> deparse1WithCutoff()
35
 *    do_dump() -> deparse1() -> deparse1WithCutoff()
36
 *  ---------
37
 *  Workhorse: deparse1WithCutoff() -> deparse2() -> deparse2buff() --> {<itself>, ...}
38
 *  ---------  ~~~~~~~~~~~~~~~~~~  implicit arg R_BrowseLines == getOption("deparse.max.lines")
39
 *
40
 *  ./errors.c: PrintWarnings() | warningcall_dflt() ... -> deparse1s() -> deparse1WithCutoff()
41
 *  ./print.c : Print[Language|Closure|Expression]()    --> deparse1w() -> deparse1WithCutoff()
42
 *  bind.c,match.c,..: c|rbind(), match(), switch()...-> deparse1line() -> deparse1WithCutoff()
43
 *
44
 *  INDENTATION:
45
 *
46
 *  Indentation is carried out in the routine printtab2buff at the
47
 *  bottom of this file.  It seems like this should be settable via
48
 *  options.
49
 *
50
 *
51
 *  LocalParseData VARIABLES  (historically GLOBALs):
52
 *
53
 *  linenumber:  counts the number of lines that have been written,
54
 *     this is used to setup storage for deparsing.
55
 *
56
 *  len:   counts the length of the current line, it will be
57
 *     used to determine when to break lines.
58
 *
59
 *  incurly:   keeps track of whether we are inside a curly or not,
60
 *     this affects the printing of if-then-else.
61
 *
62
 *  inlist:  keeps track of whether we are inside a list or not,
63
 *     this affects the printing of if-then-else.
64
 *
65
 *  startline:   indicator TRUE=start of a line (so we can tab out to
66
 *     the correct place).
67
 *
68
 *  indent:  how many tabs should be written at the start of
69
 *     a line.
70
 *
71
 *  buff:  contains the current string, we attempt to break
72
 *     lines at cutoff, but can unlimited length.
73
 *
74
 *  lbreak:  often used to indicate whether a line has been
75
 *     broken, this makes sure that that indenting behaves
76
 *     itself.
77
 */
78
79
/* DTL ('duncan'):
80
* The code here used to use static variables to share values
81
* across the different routines. These have now been collected
82
* into a struct named  LocalParseData and this is explicitly
83
* passed between the different routines. This avoids the needs
84
* for the global variables and allows multiple evaluators, potentially
85
* in different threads, to work on their own independent copies
86
* that are local to their call stacks. This avoids any issues
87
* with interrupts, etc. not restoring values.
88
89
* The previous issue with the global "cutoff" variable is now implemented
90
* by creating a deparse1WithCutoff() routine which takes the cutoff from
91
* the caller and passes this to the different routines as a member of the
92
* LocalParseData struct. Access to the deparse1() routine remains unaltered.
93
* This is exactly as Ross had suggested ...
94
*
95
* One possible fix is to restructure the code with another function which
96
* takes a cutoff value as a parameter.   Then "do_deparse" and "deparse1"
97
* could each call this deeper function with the appropriate argument.
98
* I wonder why I didn't just do this? -- it would have been quicker than
99
* writing this note.  I guess it needs a bit more thought ...
100
*/
101
102
#ifdef HAVE_CONFIG_H
103
#include <config.h>
104
#endif
105
106
#define R_USE_SIGNALS 1
107
#include <Defn.h>
108
#include <Internal.h>
109
#include <float.h> /* for DBL_DIG */
110
#include <Print.h>
111
#include <Fileio.h>
112
#ifdef Win32
113
#include <trioremap.h>
114
#endif
115
116
28.1k
#define BUFSIZE 512
117
118
17.7k
#define MIN_Cutoff 20
119
38.6k
#define DEFAULT_Cutoff 60
120
8.86k
#define MAX_Cutoff (BUFSIZE - 12)
121
/* ----- MAX_Cutoff  <  BUFSIZE !! */
122
123
#include "RBufferUtils.h"
124
125
typedef R_StringBuffer DeparseBuffer;
126
127
typedef struct {
128
    int linenumber;
129
    int len; // FIXME: size_t
130
    int incurly;
131
    int inlist;
132
    bool startline; /* = true; */
133
    int indent;
134
    SEXP strvec;
135
    int left;
136
137
    DeparseBuffer buffer;
138
139
    int cutoff;
140
    int backtick;
141
    int opts;
142
    int sourceable;
143
#ifdef longstring_WARN
144
    int longstring;
145
#endif
146
    int maxlines;
147
    bool active;
148
    int isS4;
149
    bool fnarg; /* fn argument, so parenthesize = as assignment */
150
} LocalParseData;
151
152
static SEXP deparse1WithCutoff(SEXP call, bool abbrev, int cutoff,
153
             bool backtick, int opts, int nlines);
154
static void args2buff(SEXP, int, int, LocalParseData *);
155
static void deparse2buff(SEXP, LocalParseData *);
156
static void print2buff(const char *, LocalParseData *);
157
static void printtab2buff(int, LocalParseData *);
158
static void writeline(LocalParseData *);
159
static void vec2buff   (SEXP, LocalParseData *, bool do_names);
160
static void vector2buff(SEXP, LocalParseData *);
161
static void src2buff1(SEXP, LocalParseData *);
162
static bool src2buff(SEXP, int, LocalParseData *);
163
static void linebreak(bool *lbreak, LocalParseData *);
164
static void deparse2(SEXP, SEXP, LocalParseData *);
165
166
// .Internal(deparse(expr, width.cutoff, backtick, .deparseOpts(control), nlines))
167
attribute_hidden SEXP do_deparse(SEXP call, SEXP op, SEXP args, SEXP rho)
168
8.86k
{
169
8.86k
    checkArity(op, args);
170
171
8.86k
    SEXP expr = CAR(args); args = CDR(args);
172
8.86k
    int cut0 = DEFAULT_Cutoff;
173
8.86k
    if(!isNull(CAR(args))) {
174
8.86k
  cut0 = asInteger(CAR(args));
175
8.86k
  if(cut0 == NA_INTEGER|| cut0 < MIN_Cutoff || cut0 > MAX_Cutoff) {
176
0
      warning(_("invalid 'cutoff' value for 'deparse', using default"));
177
0
      cut0 = DEFAULT_Cutoff;
178
0
  }
179
8.86k
    }
180
8.86k
    args = CDR(args);
181
8.86k
    bool backtick = isNull(CAR(args)) ? 0 : asRbool(CAR(args), call);
182
8.86k
    args = CDR(args);
183
8.86k
    int opts = isNull(CAR(args)) ? SHOWATTRIBUTES : asInteger(CAR(args));
184
8.86k
    args = CDR(args);
185
8.86k
    int nlines = asInteger(CAR(args));
186
8.86k
    if (nlines == NA_INTEGER) nlines = -1;
187
8.86k
    return deparse1WithCutoff(expr, false, cut0, backtick, opts, nlines);
188
8.86k
}
189
190
// deparse1() version *looking* at getOption("deparse.max.lines")
191
attribute_hidden /* would need to be in an installed header if not hidden */
192
SEXP deparse1m(SEXP call, bool abbrev, int opts)
193
0
{
194
0
    bool backtick = true;
195
0
    int old_bl = R_BrowseLines,
196
0
        blines = asInteger(GetOption1(install("deparse.max.lines")));
197
0
    if (blines != NA_INTEGER && blines > 0)
198
0
        R_BrowseLines = blines;
199
0
    SEXP result = deparse1WithCutoff(call, abbrev, DEFAULT_Cutoff, backtick,
200
0
             opts, 0);
201
0
    R_BrowseLines = old_bl;
202
0
    return result;
203
0
}
204
205
// deparse1() version with R_BrowseLines := 0
206
SEXP deparse1(SEXP call, bool abbrev, int opts)
207
0
{
208
0
    bool backtick = true;
209
0
    int old_bl = R_BrowseLines;
210
0
    R_BrowseLines = 0;
211
0
    SEXP result = deparse1WithCutoff(call, abbrev, DEFAULT_Cutoff, backtick,
212
0
             opts, 0);
213
0
    R_BrowseLines = old_bl;
214
0
    return result;
215
0
}
216
217
218
/* used for language objects in print(), in print.c */
219
attribute_hidden
220
SEXP deparse1w(SEXP call, bool abbrev, int opts)
221
0
{
222
0
    bool backtick = true;
223
0
    return deparse1WithCutoff(call, abbrev, R_print.cutoff, backtick, opts, -1);
224
0
}
225
226
static void deparse_cleanup(void *data)
227
0
{
228
0
    LocalParseData *l = (LocalParseData *) data;
229
0
    R_FreeStringBuffer(&(l->buffer));
230
0
}
231
232
static SEXP deparse1WithCutoff(SEXP call, bool abbrev, int cutoff,
233
             bool backtick, int opts, int nlines)
234
19.3k
{
235
/* Arg. abbrev:
236
  If abbrev is TRUE, then the returned value
237
  is a STRSXP of length 1 with at most 13 characters.
238
  This is used for plot labelling etc.
239
*/
240
19.3k
    SEXP svec;
241
19.3k
    int savedigits;
242
19.3k
    bool need_ellipses = false;
243
19.3k
    LocalParseData localData = {
244
19.3k
  .linenumber = 0,
245
19.3k
  .len = 0,
246
19.3k
  .incurly = 0,
247
19.3k
  .inlist = 0,
248
19.3k
  .startline = true,
249
19.3k
  .indent = 0,
250
19.3k
  .strvec = NULL,
251
19.3k
  .left = 0,
252
19.3k
  .buffer = { NULL, 0, BUFSIZE },
253
19.3k
  .cutoff = DEFAULT_Cutoff,
254
19.3k
  .backtick = false,
255
19.3k
  .opts = 0,
256
19.3k
  .sourceable = true,
257
#ifdef longstring_WARN
258
  .longstring = false,
259
#endif
260
19.3k
  .maxlines = INT_MAX,
261
19.3k
  .active = true,
262
19.3k
  .isS4 = 0,
263
19.3k
  .fnarg = false
264
19.3k
    };
265
19.3k
    localData.cutoff = cutoff;
266
19.3k
    localData.backtick = backtick;
267
19.3k
    localData.opts = opts;
268
19.3k
    localData.strvec = R_NilValue;
269
270
    /* Set up a context to free the heap-allocated buffer when an error
271
       signalled during deparsing unwinds past this frame */
272
19.3k
    RCNTXT cntxt;
273
19.3k
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
274
19.3k
     R_NilValue, R_NilValue);
275
19.3k
    cntxt.cend = &deparse_cleanup;
276
19.3k
    cntxt.cenddata = &localData;
277
278
19.3k
    PrintDefaults(); /* from global options() */
279
19.3k
    savedigits = R_print.digits;
280
19.3k
    R_print.digits = DBL_DIG;/* MAX precision */
281
19.3k
    print2buff("", &localData); /* ensure allocation of buffer.data, PR#17876 */
282
283
19.3k
    svec = R_NilValue;
284
19.3k
    if (nlines > 0) {
285
10.4k
  localData.linenumber = localData.maxlines = nlines;
286
10.4k
    } else { // default: nlines = -1 (from R), or = 0 (from other C fn's)
287
8.86k
  if(R_BrowseLines > 0)// not by default; e.g. from getOption("deparse.max.lines")
288
0
      localData.maxlines = R_BrowseLines + 1; // enough to determine linenumber
289
8.86k
  deparse2(call, svec, &localData);
290
8.86k
  localData.active = true;
291
8.86k
  if(R_BrowseLines > 0 && localData.linenumber > R_BrowseLines) {
292
0
      localData.linenumber = R_BrowseLines + 1;
293
0
      need_ellipses = true;
294
0
  }
295
8.86k
    }
296
19.3k
    PROTECT(svec = allocVector(STRSXP, localData.linenumber));
297
19.3k
    deparse2(call, svec, &localData);
298
19.3k
    if (abbrev) {
299
0
  char data[14];
300
0
  strncpy(data, CHAR(STRING_ELT(svec, 0)), 10);
301
0
  data[10] = '\0';
302
0
  if (strlen(CHAR(STRING_ELT(svec, 0))) > 10) strcat(data, "...");
303
0
  svec = mkString(data);
304
19.3k
    } else if(need_ellipses) {
305
0
  SET_STRING_ELT(svec, R_BrowseLines, mkChar("  ..."));
306
0
    }
307
19.3k
    if(nlines > 0 && localData.linenumber < nlines) {
308
0
  UNPROTECT(1); /* old svec value */
309
0
  PROTECT(svec);
310
0
  svec = lengthgets(svec, localData.linenumber);
311
0
    }
312
19.3k
    UNPROTECT(1);
313
19.3k
    PROTECT(svec); /* protect from warning() allocating, PR#14356 */
314
19.3k
    R_print.digits = savedigits;
315
    /*: Don't warn anymore, we do deal with most (-> 'S4SXP' below)
316
    if ((opts & WARNINCOMPLETE) && localData.isS4)
317
  warning(_("deparse of an S4 object may not always be source()able"));
318
  else */
319
19.3k
    if ((opts & WARNINCOMPLETE) && !localData.sourceable)
320
0
  warning(_("deparse may be incomplete"));
321
#ifdef longstring_WARN
322
    if ((opts & WARNINCOMPLETE) && localData.longstring)
323
  warning(_("deparse may be not be source()able in R < 2.7.0"));
324
#endif
325
    /* somewhere lower down might have allocated ... */
326
19.3k
    endcontext(&cntxt);
327
19.3k
    R_FreeStringBuffer(&(localData.buffer));
328
19.3k
    UNPROTECT(1);
329
19.3k
    return svec;
330
19.3k
}
331
332
/* deparse1line(), e.g. for non-trivial list entries in as.character(<list>).
333
 * --------------
334
 * Concatenates all lines into one long one.
335
 * This is needed in terms.formula, where we must be able
336
 * to deparse a term label into a single line of text so
337
 * that it can be reparsed correctly */
338
// Used in coerce.c and relop.c
339
attribute_hidden
340
SEXP deparse1line_ex(SEXP call, bool abbrev, int opts)
341
0
{
342
0
    bool backtick=true;
343
0
    int lines;
344
0
    SEXP temp = PROTECT(
345
0
      deparse1WithCutoff(call, abbrev, MAX_Cutoff, backtick, opts, -1));
346
0
    if ((lines = length(temp)) > 1) {
347
0
  char *buf;
348
0
  int i;
349
0
  size_t len;
350
0
  const void *vmax;
351
0
  cetype_t enc = CE_NATIVE;
352
0
  for (len = 0, i = 0; i < length(temp); i++) {
353
0
      SEXP s = STRING_ELT(temp, i);
354
0
      cetype_t thisenc = getCharCE(s);
355
0
      len += strlen(CHAR(s));  // FIXME: check for overflow?
356
0
      if (thisenc != CE_NATIVE)
357
0
    enc = thisenc; /* assume only one non-native encoding */
358
0
  }
359
0
  vmax = vmaxget();
360
0
  buf = R_alloc((size_t) len+lines, sizeof(char));
361
0
  *buf = '\0';
362
0
  for (i = 0; i < length(temp); i++) {
363
0
      if (i % 1000 == 999) R_CheckUserInterrupt();
364
0
      strcat(buf, CHAR(STRING_ELT(temp, i)));
365
0
      if (i < lines - 1)
366
0
    strcat(buf, "\n");
367
0
  }
368
0
  temp = ScalarString(mkCharCE(buf, enc));
369
0
  vmaxset(vmax);
370
0
    }
371
0
    UNPROTECT(1);
372
0
    return(temp);
373
0
}
374
375
// used in bind.c builtin.c coerce.c match.c relop.c
376
SEXP deparse1line(SEXP call, bool abbrev)
377
0
{
378
0
    return deparse1line_ex(call, abbrev, SIMPLEDEPARSE);
379
0
}
380
381
382
// called only from ./errors.c  for calls in warnings and errors :
383
attribute_hidden SEXP deparse1s(SEXP call)
384
10.4k
{
385
10.4k
   bool backtick=true;
386
10.4k
   return
387
10.4k
       deparse1WithCutoff(call, false, DEFAULT_Cutoff, backtick,
388
10.4k
        DEFAULTDEPARSE, /* nlines = */ 1);
389
10.4k
}
390
391
#include "Rconnections.h"
392
393
static void con_cleanup(void *data)
394
0
{
395
0
    Rconnection con = data;
396
0
    if(con->isopen) con->close(con);
397
0
}
398
399
// .Internal(dput(x, file, .deparseOpts(control)))
400
attribute_hidden SEXP do_dput(SEXP call, SEXP op, SEXP args, SEXP rho)
401
0
{
402
0
    checkArity(op, args);
403
0
    SEXP tval = CAR(args);
404
0
    int opts = isNull(CADDR(args)) ? SHOWATTRIBUTES : asInteger(CADDR(args));
405
406
0
    if (TYPEOF(tval) == CLOSXP) {
407
0
  SEXP clo = PROTECT(duplicate(tval));
408
0
  SET_CLOENV(clo, R_GlobalEnv);
409
0
  tval = deparse1(clo, 0, opts);
410
0
  UNPROTECT(1);
411
0
    } else
412
0
  tval = deparse1(tval, 0, opts);
413
0
    PROTECT(tval); /* against Rconn_printf */
414
0
    if(!inherits(CADR(args), "connection"))
415
0
  error(_("'file' must be a character string or connection"));
416
0
    int ifile = asInteger(CADR(args));
417
0
    if (ifile != 1) {
418
0
  Rconnection con = getConnection(ifile);
419
0
  RCNTXT cntxt;
420
0
  bool wasopen = con->isopen;
421
0
  if(!wasopen) {
422
0
      char mode[5];
423
0
      strcpy(mode, con->mode);
424
0
      strcpy(con->mode, "w");
425
0
      if(!con->open(con)) error(_("cannot open the connection"));
426
0
      strcpy(con->mode, mode);
427
      /* Set up a context which will close the connection on error */
428
0
      begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
429
0
       R_NilValue, R_NilValue);
430
0
      cntxt.cend = &con_cleanup;
431
0
      cntxt.cenddata = con;
432
0
  }
433
0
  if(!con->canwrite) error(_("cannot write to this connection"));
434
0
  bool havewarned = false;
435
0
  for (int i = 0; i < LENGTH(tval); i++) {
436
0
      int res = Rconn_printf(con, "%s\n", CHAR(STRING_ELT(tval, i)));
437
0
      if(!havewarned &&
438
0
         res < strlen(CHAR(STRING_ELT(tval, i))) + 1) {
439
0
    warning(_("wrote too few characters"));
440
0
    havewarned = true;
441
0
      }
442
0
  }
443
0
  if(!wasopen) {endcontext(&cntxt); con->close(con);}
444
0
    }
445
0
    else { // ifile == 1 : "Stdout"
446
0
  for (int i = 0; i < LENGTH(tval); i++)
447
0
      Rprintf("%s\n", CHAR(STRING_ELT(tval, i)));
448
0
    }
449
0
    UNPROTECT(1); /* tval */
450
0
    return (CAR(args));
451
0
}
452
453
// .Internal(dump(list, file, envir, opts, evaluate))
454
attribute_hidden SEXP do_dump(SEXP call, SEXP op, SEXP args, SEXP rho)
455
0
{
456
0
    checkArity(op, args);
457
0
    SEXP names = CAR(args),
458
0
   file = CADR(args);
459
0
    if(!inherits(file, "connection"))
460
0
  error(_("'file' must be a character string or connection"));
461
0
    if(!isString(names))
462
0
  error( _("character arguments expected"));
463
0
    int nobjs = length(names);
464
0
    if(nobjs < 1 || length(file) < 1)
465
0
  error(_("zero-length argument"));
466
0
    SEXP source = CADDR(args);
467
0
    if (source != R_NilValue && TYPEOF(source) != ENVSXP)
468
0
  error(_("invalid '%s' argument"), "envir");
469
0
    int opts = asInteger(CADDDR(args));
470
    /* <NOTE>: change this if extra options are added */
471
0
    if(opts == NA_INTEGER || opts < 0 || opts > 2048)
472
0
  error(_("'opts' should be small non-negative integer"));
473
    // evaluate :
474
0
    if (!asLogical(CAD4R(args))) opts |= DELAYPROMISES;
475
476
0
    SEXP objs, o = PROTECT(objs = allocList(nobjs));
477
0
    int nout = 0;
478
0
    for (int i = 0; i < nobjs; i++, o = CDR(o)) {
479
0
  SET_TAG(o, installTrChar(STRING_ELT(names, i)));
480
0
  SETCAR(o, R_findVar(TAG(o), source));
481
0
  if (CAR(o) == R_UnboundValue)
482
0
      warning(_("object '%s' not found"), EncodeChar(PRINTNAME(TAG(o))));
483
0
  else nout++;
484
0
    }
485
0
    o = objs;
486
0
    SEXP outnames = PROTECT(allocVector(STRSXP, nout)); // -> result
487
0
    if(nout > 0) {
488
0
  if(INTEGER(file)[0] == 1) {
489
0
      for (int i = 0, nout = 0; i < nobjs; i++) {
490
0
    if (CAR(o) == R_UnboundValue) continue;
491
0
    const char *obj_name = translateChar(STRING_ELT(names, i));
492
0
    SET_STRING_ELT(outnames, nout++, STRING_ELT(names, i));
493
0
    if(isValidName(obj_name)) Rprintf("%s <-\n", obj_name);
494
0
    else if(opts & S_COMPAT) Rprintf("\"%s\" <-\n", obj_name);
495
0
    else Rprintf("`%s` <-\n", obj_name);
496
0
    SEXP tval = PROTECT(deparse1(CAR(o), 0, opts));
497
0
    for (int j = 0; j < LENGTH(tval); j++)
498
0
        Rprintf("%s\n", CHAR(STRING_ELT(tval, j)));/* translated */
499
0
    UNPROTECT(1); /* tval */
500
0
    o = CDR(o);
501
0
      }
502
0
  }
503
0
  else {
504
0
      Rconnection con = getConnection(INTEGER(file)[0]);
505
0
      bool wasopen = con->isopen;
506
0
      RCNTXT cntxt;
507
0
      if(!wasopen) {
508
0
    char mode[5];
509
0
    strcpy(mode, con->mode);
510
0
    strcpy(con->mode, "w");
511
0
    if(!con->open(con)) error(_("cannot open the connection"));
512
0
    strcpy(con->mode, mode);
513
    /* Set up a context which will close the connection on error */
514
0
    begincontext(&cntxt, CTXT_CCODE, R_NilValue, R_BaseEnv, R_BaseEnv,
515
0
           R_NilValue, R_NilValue);
516
0
    cntxt.cend = &con_cleanup;
517
0
    cntxt.cenddata = con;
518
0
      }
519
0
      if(!con->canwrite) error(_("cannot write to this connection"));
520
0
      bool havewarned = false;
521
0
      for (int i = 0, nout = 0; i < nobjs; i++) {
522
0
    if (CAR(o) == R_UnboundValue) continue;
523
0
    SET_STRING_ELT(outnames, nout++, STRING_ELT(names, i));
524
0
    int res;
525
0
    const char *s = translateChar(STRING_ELT(names, i));
526
0
    unsigned int extra = 6;
527
0
    if(isValidName(s)) {
528
0
        extra = 4;
529
0
        res = Rconn_printf(con, "%s <-\n", s);
530
0
    } else if(opts & S_COMPAT)
531
0
        res = Rconn_printf(con, "\"%s\" <-\n", s);
532
0
    else
533
0
        res = Rconn_printf(con, "`%s` <-\n", s);
534
0
    if(!havewarned && res < strlen(s) + extra)
535
0
        warning(_("wrote too few characters"));
536
0
    SEXP tval = PROTECT(deparse1(CAR(o), 0, opts));
537
0
    for (int j = 0; j < LENGTH(tval); j++) {
538
0
        res = Rconn_printf(con, "%s\n", CHAR(STRING_ELT(tval, j)));
539
0
        if(!havewarned &&
540
0
           res < strlen(CHAR(STRING_ELT(tval, j))) + 1) {
541
0
      warning(_("wrote too few characters"));
542
0
      havewarned = true;
543
0
        }
544
0
    }
545
0
    UNPROTECT(1); /* tval */
546
0
    o = CDR(o);
547
0
      }
548
0
      if(!wasopen) {endcontext(&cntxt); con->close(con);}
549
0
  }
550
0
    }
551
552
0
    UNPROTECT(2);
553
0
    return outnames;
554
0
}
555
556
static void linebreak(bool *lbreak, LocalParseData *d)
557
28.8k
{
558
28.8k
    if (d->len > d->cutoff) {
559
3.45k
  if (!*lbreak) {
560
3.18k
      *lbreak = true;
561
3.18k
      d->indent++;
562
3.18k
  }
563
3.45k
  writeline(d);
564
3.45k
    }
565
28.8k
}
566
567
static void deparse2(SEXP what, SEXP svec, LocalParseData *d)
568
28.1k
{
569
28.1k
    d->strvec = svec;
570
28.1k
    d->linenumber = 0;
571
28.1k
    d->indent = 0;
572
28.1k
    deparse2buff(what, d);
573
28.1k
    writeline(d);
574
28.1k
}
575
576
577
/* curlyahead looks at s to see if it is a list with
578
   the first op being a curly.  You need this kind of
579
   lookahead info to print if statements correctly.  */
580
static bool
581
curlyahead(SEXP s)
582
0
{
583
0
    if (isList(s) || isLanguage(s))
584
0
  if (TYPEOF(CAR(s)) == SYMSXP && CAR(s) == R_BraceSymbol)
585
0
      return true;
586
0
    return false;
587
0
}
588
589
/* needsparens looks at an arg to a unary or binary operator to
590
   determine if it needs to be parenthesized when deparsed
591
   mainop is a unary or binary operator,
592
   arg is an argument to it, on the left if left == 1 */
593
594
static bool needsparens(PPinfo mainop, SEXP arg, unsigned int left,
595
          unsigned int deepLeft)
596
95.0k
{
597
95.0k
    PPinfo arginfo;
598
95.0k
    if (TYPEOF(arg) == LANGSXP) {
599
56.2k
  if (TYPEOF(CAR(arg)) == SYMSXP) {
600
54.4k
      if ((TYPEOF(SYMVALUE(CAR(arg))) == BUILTINSXP) ||
601
45.9k
    (TYPEOF(SYMVALUE(CAR(arg))) == SPECIALSXP)) {
602
45.9k
    arginfo = PPINFO(SYMVALUE(CAR(arg)));
603
604
    /* Not all binary ops are binary! */
605
45.9k
    switch(arginfo.kind) {
606
15.8k
    case PP_BINARY:
607
36.7k
    case PP_BINARY2:
608
36.7k
        switch(length(CDR(arg))) {
609
11.4k
        case 1:
610
      /* binary +/- precedence upgraded as unary */
611
11.4k
      if (arginfo.precedence == PREC_SUM)
612
9.84k
          arginfo.precedence = PREC_SIGN;
613
11.4k
      arginfo.kind = PP_UNARY;
614
11.4k
      break;
615
25.2k
        case 2:
616
25.2k
      break;
617
3
        default:
618
3
      return false;
619
36.7k
        }
620
45.8k
    default:
621
45.8k
        break;
622
45.9k
    }
623
624
45.8k
    switch(arginfo.kind) {
625
1.55k
    case PP_SUBSET:
626
1.55k
        switch (mainop.kind) {
627
11
        case PP_DOLLAR:
628
1.29k
        case PP_SUBSET:
629
1.29k
      if (mainop.precedence > arginfo.precedence)
630
11
          return false;
631
      /* else fall through */
632
1.54k
        default:
633
1.54k
      break;
634
1.55k
        }
635
5.87k
    case PP_BINARY:
636
26.8k
    case PP_BINARY2:
637
26.8k
        if (mainop.precedence == PREC_COMPARE &&
638
63
      arginfo.precedence == PREC_COMPARE)
639
0
      return true;     /*   a < b < c   is not legal syntax */
640
        /* else fall through */
641
30.9k
    case PP_ASSIGN:
642
31.1k
    case PP_ASSIGN2:
643
32.3k
    case PP_DOLLAR:
644
32.3k
        if (mainop.precedence > arginfo.precedence
645
32.3k
      || (mainop.precedence == arginfo.precedence && left == mainop.rightassoc)) {
646
30
      return true;
647
30
        }
648
32.3k
        break;
649
32.3k
    case PP_UNARY:
650
12.5k
        return (left && mainop.precedence > arginfo.precedence)
651
12.4k
      || (deepLeft && deepLeft > arginfo.precedence);
652
12
    case PP_FOR:
653
67
    case PP_IF:
654
129
    case PP_WHILE:
655
222
    case PP_REPEAT:
656
222
        return left || deepLeft;
657
753
    default:
658
753
        return false;
659
45.8k
    }
660
45.8k
      } else if (isUserBinop(CAR(arg))) {
661
2.52k
    if (mainop.precedence > PREC_PERCENT
662
2.46k
        || (mainop.precedence == PREC_PERCENT && left == mainop.rightassoc)) {
663
63
        return true;
664
63
    }
665
2.52k
      }
666
54.4k
  }
667
56.2k
    }
668
38.8k
    else if ((TYPEOF(arg) == CPLXSXP) && (length(arg) == 1)) {
669
2.45k
  if (mainop.precedence > PREC_SUM
670
1.59k
      || (mainop.precedence == PREC_SUM && left == mainop.rightassoc)) {
671
1.16k
      return true;
672
1.16k
  }
673
2.45k
    }
674
80.2k
    return false;
675
95.0k
}
676
677
678
/* does the character() vector x contain one `NA_character_` or is all "",
679
 * or if(isAtomic) does it have one "recursive" or "use.names" ?  */
680
static bool usable_nice_names(SEXP x, bool isAtomic)
681
0
{
682
0
    if(TYPEOF(x) == STRSXP) {
683
0
  R_xlen_t i, n = xlength(x);
684
0
  bool all_0 = true;
685
0
  if(isAtomic) // c(*, recursive=, use.names=): cannot use these as nice_names
686
0
      for (i = 0; i < n; i++) {
687
0
    if (STRING_ELT(x, i) == NA_STRING
688
0
        || strcmp(CHAR(STRING_ELT(x, i)), "recursive") == 0
689
0
        || strcmp(CHAR(STRING_ELT(x, i)), "use.names") == 0)
690
0
        return false;
691
0
    else if (all_0 && *CHAR(STRING_ELT(x, i))) /* length test */
692
0
        all_0 = false;
693
0
      }
694
0
  else
695
0
      for (i = 0; i < n; i++) {
696
0
    if (STRING_ELT(x, i) == NA_STRING)
697
0
        return false;
698
0
    else if (all_0 && *CHAR(STRING_ELT(x, i))) /* length test */
699
0
        all_0 = false;
700
0
      }
701
702
0
  return !all_0;
703
0
    }
704
0
    return true;
705
0
}
706
707
708
typedef enum { UNKNOWN = -1,
709
         SIMPLE = 0,
710
         OK_NAMES,   // no structure(*); names written as  (n1 = v1, ..)
711
         STRUC_ATTR, // use structure(*, <attr> = *, ..) for non-names only
712
         STRUC_NMS_A // use structure(*, <attr> = *, ..)  for names, too
713
} attr_type;
714
715
#ifdef DEBUG_DEPARSE
716
static const char* attrT2char(attr_type typ) {
717
    switch(typ) {
718
    case UNKNOWN: return "UNKNOWN";
719
    case SIMPLE: return "SIMPLE";
720
    case OK_NAMES: return "OK_NAMES";
721
    case STRUC_ATTR: return "STRUC_ATTR";
722
    case STRUC_NMS_A: return "STRUC_NMS_A";
723
    default: return "_unknown_ attr_type -- should *NOT* happen!";
724
    }
725
}
726
# define ChTF(_logic_) (_logic_ ? "true" : "false")
727
#endif
728
729
/* Exact semantic of NICE_NAMES and SHOWATTRIBUTES i.e. "niceNames" and "showAttributes"
730
731
C|  depCtrl   | attr1() result
732
-| -----------+-----------------------------------------------------------------------------
733
1|  NN &&  SA | STRUCT_ATTR + NN  or  STRUC_NMS_A (if NN are not "allowed")
734
2| !NN &&  SA | if(has attr) STRUC_NMS_A  else "SIMPLE"
735
3|  NN && !SA | OK_NAMES   ||  SIMPLE  if(!has_names)
736
4| !NN && !SA | SIMPLE
737
738
739
C|  depCtrl   : what should   deparse(*, control = depCtrl)   do ?
740
-| -----------+-----------------------------------------------------------------------------
741
1|  NN &&  SA : all attributes(but srcref); names "NICE"ly (<nam> = <val>) if valid [no NA]
742
2| !NN &&  SA : all attributes( "    "   ) use structure(..) incl names but no _nice_ names
743
3|  NN && !SA : no attributes but names, names nicely even when "wrong" (i.e. NA in names(.))
744
4| !NN && !SA : no attributes shown, not even names
745
746
*/
747
748
// is *only* called  if (d->opts & SHOW_ATTR_OR_NMS) = d->opts & (SHOW_A | NICE_N)
749
static attr_type attr1(SEXP s, LocalParseData *d)
750
38.8k
{
751
38.8k
    SEXP a = ATTRIB(s), nm = getAttrib(s, R_NamesSymbol);
752
38.8k
    attr_type attr = UNKNOWN;
753
38.8k
    bool
754
38.8k
  nice_names = (bool) (d->opts & NICE_NAMES),
755
38.8k
  show_attr  = d->opts & SHOWATTRIBUTES,
756
38.8k
  has_names = !isNull(nm), ok_names;
757
#ifdef DEBUG_DEPARSE
758
    REprintf("  attr1(): has_names = %s", ChTF(has_names));
759
#endif
760
38.8k
    if(has_names) {
761
  // ok only if there's no  NA_character_,.. in names() nor all """
762
0
  ok_names = nice_names && usable_nice_names(nm, isVectorAtomic(s));
763
#ifdef DEBUG_DEPARSE
764
  REprintf(", ok_names = %s", ChTF(ok_names));
765
#endif
766
0
  if(!ok_names)
767
0
      attr = show_attr ? STRUC_NMS_A :
768
0
    /* nice_names */  OK_NAMES; // even when not ok
769
0
    }
770
771
38.8k
    while(attr == UNKNOWN && !isNull(a)) {
772
0
  if(has_names && TAG(a) == R_NamesSymbol) {
773
      // also  ok_names = true
774
0
  } else if(show_attr && TAG(a) != R_SrcrefSymbol) {
775
0
      attr = STRUC_ATTR;
776
0
      break;
777
0
  }
778
  // else
779
0
  a = CDR(a);
780
0
    }
781
38.8k
    if(attr == UNKNOWN)
782
38.8k
  attr = has_names ? OK_NAMES : SIMPLE;
783
784
38.8k
    if(attr >= STRUC_ATTR) {
785
0
  print2buff("structure(", d);
786
38.8k
    } else if(has_names) { // attr <= OK_NAMES
787
0
    }
788
#ifdef DEBUG_DEPARSE
789
    REprintf(", return()ing %s\n", attrT2char(attr));
790
#endif
791
38.8k
    return attr;
792
38.8k
}
793
794
/* deparse a single attribute as `<name> = <value>`, shared by attr2() (the
795
   structure(..) form) and the OBJSXP / object(..) deparse below. */
796
static void attrEntry(SEXP a, LocalParseData *d)
797
0
{
798
0
    if(TAG(a) == R_DimSymbol) {
799
0
  print2buff("dim", d); // was .Dim
800
0
    }
801
0
    else if(TAG(a) == R_DimNamesSymbol) {
802
0
  print2buff("dimnames", d); // was .Dimnames
803
0
    }
804
0
    else if(TAG(a) == R_NamesSymbol) {
805
0
  print2buff("names", d); // was .Names
806
0
    }
807
0
    else if(TAG(a) == R_TspSymbol) {
808
0
  print2buff("tsp", d); // was .Tsp
809
0
    }
810
0
    else if(TAG(a) == R_LevelsSymbol) {
811
0
  print2buff("levels", d); // was .Label
812
0
    }
813
0
    else {
814
  /* TAG(a) might contain spaces etc */
815
0
  const char *tag = CHAR(PRINTNAME(TAG(a)));
816
0
  int d_opts_in = d->opts;
817
0
  d->opts = SIMPLEDEPARSE; /* turn off quote()ing */
818
0
  if(isValidName(tag))
819
0
      deparse2buff(TAG(a), d);
820
0
  else {
821
0
      print2buff("\"", d);
822
0
      deparse2buff(TAG(a), d);
823
0
      print2buff("\"", d);
824
0
  }
825
0
  d->opts = d_opts_in;
826
0
    }
827
0
    print2buff(" = ", d);
828
0
    bool fnarg = d->fnarg;
829
0
    d->fnarg = true;
830
0
    deparse2buff(CAR(a), d);
831
0
    d->fnarg = fnarg;
832
0
}
833
834
// function attr2()  writes full  attributes(s) to 'buff'
835
static void attr2(SEXP s, LocalParseData *d, bool not_names)
836
0
{
837
0
    SEXP a = ATTRIB(s);
838
0
    while(!isNull(a)) {
839
0
  if(TAG(a) != R_SrcrefSymbol &&
840
0
     !(TAG(a) == R_NamesSymbol && not_names)) {
841
0
      print2buff(", ", d);
842
0
      attrEntry(a, d);
843
0
  }
844
0
  a = CDR(a);
845
0
    }
846
0
    print2buff(")", d);
847
0
}
848
849
static const char *quotify(SEXP name, int quote)
850
221k
{
851
221k
    const char *s = CHAR(name);
852
853
    /* If a symbol is not a valid name, put it in quotes, escaping
854
     * any quotes in the string itself */
855
856
221k
    if (isValidName(s) || *s == '\0') return s;
857
858
189k
    return EncodeString(name, 0, quote, Rprt_adj_none);
859
221k
}
860
861
/* check for whether we need to parenthesize a caller.  The unevaluated ones
862
   are tricky:
863
   We want
864
     x$f(z)
865
     x[n](z)
866
     base::mean(x)
867
   but
868
     (f+g)(z)
869
     (function(x) 1)(x)
870
     etc.
871
*/
872
static bool parenthesizeCaller(SEXP s)
873
5.39k
{
874
5.39k
    SEXP op, sym;
875
5.39k
    if (TYPEOF(s) == LANGSXP) { /* unevaluated */
876
5.15k
  op = CAR(s);
877
5.15k
  if (TYPEOF(op) == SYMSXP) {
878
1.89k
      if (isUserBinop(op)) return true;   /* %foo% */
879
1.56k
      sym = SYMVALUE(op);
880
1.56k
      if (TYPEOF(sym) == BUILTINSXP
881
1.34k
    || TYPEOF(sym) == SPECIALSXP) {
882
1.18k
    if (PPINFO(sym).precedence >= PREC_SUBSET
883
247
        || PPINFO(sym).kind == PP_FUNCALL
884
211
        || PPINFO(sym).kind == PP_PAREN
885
1.08k
        || PPINFO(sym).kind == PP_CURLY) return false; /* x$f(z) or x[n](z) or f(z) or (f) or {f} */
886
103
    else return true;   /* (f+g)(z) etc. */
887
1.18k
      }
888
376
      return false;     /* regular function call */
889
1.56k
   } else
890
3.26k
      return true;     /* something strange, like (1)(x) */
891
5.15k
    } else
892
243
  return TYPEOF(s) == CLOSXP;
893
5.39k
}
894
895
/* This is the recursive part of deparsing. */
896
897
0
#define SIMPLE_OPTS (~QUOTEEXPRESSIONS & ~SHOWATTRIBUTES & ~DELAYPROMISES)
898
/* keep KEEPINTEGER | USESOURCE | KEEPNA | S_COMPAT, also
899
   WARNINCOMPLETE but that is not used below this point. */
900
77.7k
#define SHOW_ATTR_OR_NMS (SHOWATTRIBUTES | NICE_NAMES)
901
902
static void deparse2buff(SEXP s, LocalParseData *d)
903
355k
{
904
355k
    bool lookahead = false, lbreak = false, fnarg = d->fnarg;
905
355k
    attr_type attr = STRUC_ATTR;
906
355k
    SEXP t;
907
355k
    int d_opts_in = d->opts, i, n;
908
909
355k
    d->fnarg = false;
910
911
    /* This flag should only be set when recursing through the LHS
912
       of binary ops, so by default we reset to zero */
913
355k
    int prevLeft = d->left;
914
355k
    d->left = 0;
915
916
355k
    if (!d->active) return;
917
918
332k
    if (IS_S4_OBJECT(s)) {
919
0
  d->isS4 = true;
920
  /* const void *vmax = vmaxget(); */
921
0
  SEXP class = getAttrib(s, R_ClassSymbol),
922
0
      cl_def = TYPEOF(class) == STRSXP ? STRING_ELT(class, 0) : R_NilValue;
923
0
  if(TYPEOF(cl_def) == CHARSXP) { // regular S4 objects
924
0
      print2buff("new(\"", d);
925
0
      print2buff(translateChar(cl_def), d);
926
0
      print2buff("\", ", d);
927
0
      SEXP slotNms; // ---- slotNms := methods::.slotNames(s)  ---------
928
      // computed alternatively, slotNms := names(getClassDef(class)@slots) :
929
0
      static SEXP R_getClassDef = NULL, R_slots = NULL, R_asS3 = NULL;
930
0
      if(R_getClassDef == NULL)
931
0
    R_getClassDef = findFun(install("getClassDef"), R_MethodsNamespace);
932
0
      if(R_slots == NULL) R_slots = install("slots");
933
0
      if(R_asS3  == NULL) R_asS3  = install("asS3");
934
0
      SEXP e = PROTECT(lang2(R_getClassDef, class));
935
0
      cl_def = PROTECT(eval(e, R_BaseEnv)); // correct env?
936
0
      slotNms = // names( cl_def@slots ) :
937
0
    getAttrib(R_do_slot(cl_def, R_slots), R_NamesSymbol);
938
0
      UNPROTECT(2); // (e, cl_def)
939
0
      int n;
940
0
      bool has_Data = false;// does it have ".Data" slot?
941
0
      bool hasS4_t = TYPEOF(s) == OBJSXP;
942
0
      if(TYPEOF(slotNms) == STRSXP && (n = LENGTH(slotNms))) {
943
0
    PROTECT(slotNms);
944
0
    SEXP slotlist = PROTECT(allocVector(VECSXP, n));
945
    // := structure(lapply(slotNms, slot, object=s), names=slotNms)
946
0
    for(int i=0; i < n; i++) {
947
0
        SEXP slot_i = STRING_ELT(slotNms, i);
948
0
        SET_VECTOR_ELT(slotlist, i, R_do_slot(s, installTrChar(slot_i)));
949
0
        if(!hasS4_t && !has_Data)
950
0
      has_Data = (strcmp(CHAR(slot_i), ".Data") == 0);
951
0
    }
952
0
    setAttrib(slotlist, R_NamesSymbol, slotNms);
953
0
    vec2buff(slotlist, d, true);
954
    /*-----------------*/
955
0
    UNPROTECT(2); // (slotNms, slotlist)
956
0
      }
957
0
      if(!hasS4_t && !has_Data) {
958
    // may have *non*-slot contents, (i.e., not in .Data)
959
    // ==> additionally deparse asS3(s) :
960
0
    e = PROTECT(lang2(R_asS3, s)); // = asS3(s)
961
0
    SEXP S3_s = PROTECT(eval(e, R_BaseEnv)); // correct env?
962
0
    print2buff(", ", d);
963
0
    deparse2buff(S3_s, d);
964
0
    UNPROTECT(2); // (e, S3_s)
965
0
      }
966
0
      print2buff(")", d);
967
0
  }
968
0
  else { // exception: class is not CHARSXP
969
0
      if(isNull(cl_def) && isNull(ATTRIB(s))) // special
970
0
    print2buff("getClass(\"S4\")@prototype", d);
971
0
      else { // irregular S4 ((does this ever trigger ??))
972
0
    d->sourceable = false;
973
0
    print2buff("<S4 object of class ", d);
974
0
    deparse2buff(class, d);
975
0
    print2buff(">", d);
976
0
      }
977
0
  }
978
  /* vmaxset(vmax); */
979
0
  return;
980
0
    } // if( S4 )
981
982
    // non-S4 cases:
983
332k
    switch (TYPEOF(s)) {
984
10
    case NILSXP:
985
10
  print2buff("NULL", d);
986
10
  break;
987
31.3k
    case SYMSXP: {
988
31.3k
  bool
989
31.3k
      doquote = (d_opts_in & QUOTEEXPRESSIONS) && strlen(CHAR(PRINTNAME(s)));
990
31.3k
  if (doquote) {
991
0
      attr = (d_opts_in & SHOW_ATTR_OR_NMS) ? attr1(s, d) : SIMPLE;
992
0
      print2buff("quote(", d);
993
0
  }
994
31.3k
  if (d_opts_in & S_COMPAT) {
995
0
      print2buff(quotify(PRINTNAME(s), '"'), d);
996
31.3k
  } else if (d->backtick)
997
13.6k
      print2buff(quotify(PRINTNAME(s), '`'), d);
998
17.7k
  else
999
17.7k
      print2buff(CHAR(PRINTNAME(s)), d);
1000
31.3k
  if (doquote) {
1001
0
      print2buff(")", d);
1002
0
      if(attr >= STRUC_ATTR) attr2(s, d, (attr == STRUC_ATTR));
1003
0
  }
1004
31.3k
  break;
1005
0
    }
1006
30
    case CHARSXP:
1007
30
    {
1008
30
  const void *vmax = vmaxget();
1009
30
  const char *ts = translateChar(s);
1010
#ifdef longstring_WARN
1011
  /* versions of R < 2.7.0 cannot parse strings longer than 8192 chars */
1012
  if(strlen(ts) >= 8192) d->longstring = true;
1013
#endif
1014
30
  print2buff(ts, d);
1015
30
  vmaxset(vmax);
1016
30
  break;
1017
0
    }
1018
0
    case SPECIALSXP:
1019
0
    case BUILTINSXP:
1020
0
  print2buff(".Primitive(\"", d);
1021
0
  print2buff(PRIMNAME(s), d);
1022
0
  print2buff("\")", d);
1023
0
  break;
1024
0
    case PROMSXP:
1025
0
  if(d->opts & DELAYPROMISES) {
1026
0
      d->sourceable = false;
1027
0
      print2buff("<promise: ", d);
1028
0
      d->opts &= ~QUOTEEXPRESSIONS; /* don't want delay(quote()) */
1029
0
      deparse2buff(PREXPR(s), d);
1030
0
      d->opts = d_opts_in;
1031
0
      print2buff(">", d);
1032
0
  } else {
1033
0
      PROTECT(s = eval(s, R_EmptyEnv)); /* eval uses env of promise */
1034
0
      deparse2buff(s, d);
1035
0
      UNPROTECT(1);
1036
0
  }
1037
0
  break;
1038
0
    case CLOSXP:
1039
0
  attr = (d_opts_in & SHOW_ATTR_OR_NMS) ? attr1(s, d) : SIMPLE;
1040
0
  if ((d->opts & USESOURCE)
1041
0
      && !isNull(t = getAttrib(s, R_SrcrefSymbol)))
1042
0
    src2buff1(t, d);
1043
0
  else {
1044
      /* We have established that we don't want to use the
1045
         source for this function */
1046
0
      d->opts &= SIMPLE_OPTS & ~USESOURCE;
1047
0
      print2buff("function (", d);
1048
0
      args2buff(FORMALS(s), 0, 1, d);
1049
0
      print2buff(") ", d);
1050
1051
0
      writeline(d);
1052
0
      deparse2buff(BODY_EXPR(s), d);
1053
0
      d->opts = d_opts_in;
1054
0
  }
1055
0
  if(attr >= STRUC_ATTR) attr2(s, d, (attr == STRUC_ATTR));
1056
0
  break;
1057
0
    case ENVSXP:
1058
0
  d->sourceable = false;
1059
0
  print2buff("<environment>", d);
1060
0
  break;
1061
0
    case VECSXP:
1062
0
  attr = (d_opts_in & SHOW_ATTR_OR_NMS) ? attr1(s, d) : SIMPLE;
1063
0
  print2buff("list(", d);
1064
0
  d->opts = d_opts_in;// vec2buff() must use unchanged d
1065
0
  vec2buff(s, d, attr == OK_NAMES || attr == STRUC_ATTR);
1066
0
  d->opts |= NICE_NAMES;
1067
0
  print2buff(")", d);
1068
0
  if(attr >= STRUC_ATTR) attr2(s, d, (attr == STRUC_ATTR));
1069
0
  d->opts = d_opts_in;
1070
0
  break;
1071
0
    case EXPRSXP:
1072
0
  attr = (d_opts_in & SHOW_ATTR_OR_NMS) ? attr1(s, d) : SIMPLE;
1073
0
  if(length(s) <= 0)
1074
0
      print2buff("expression()", d);
1075
0
  else {
1076
0
      int locOpts = d->opts;
1077
0
      print2buff("expression(", d);
1078
0
      d->opts &= SIMPLE_OPTS;
1079
0
      vec2buff(s, d, attr == OK_NAMES || attr == STRUC_ATTR);
1080
0
      d->opts = locOpts;
1081
0
      print2buff(")", d);
1082
0
  }
1083
0
  if(attr >= STRUC_ATTR) attr2(s, d, (attr == STRUC_ATTR));
1084
0
  d->opts = d_opts_in;
1085
0
  break;
1086
0
    case LISTSXP: {
1087
0
  attr = (d_opts_in & SHOW_ATTR_OR_NMS) ? attr1(s, d) : SIMPLE;
1088
  /* pairlist(x=) cannot be evaluated, hence with missings we use
1089
     as.pairlist(alist(...)) to allow evaluation of deparsed formals */
1090
0
  bool missing = false;
1091
0
  for(t=s; t != R_NilValue; t=CDR(t))
1092
0
      if (CAR(t) == R_MissingArg) {
1093
0
    missing = true;
1094
0
    break;
1095
0
      }
1096
0
  if (missing)
1097
0
      print2buff("as.pairlist(alist(", d);
1098
0
  else
1099
0
      print2buff("pairlist(", d);
1100
0
  d->inlist++;
1101
0
  for (t=s ; CDR(t) != R_NilValue ; t=CDR(t) ) {
1102
0
      if( TAG(t) != R_NilValue ) {
1103
0
    d->opts = SIMPLEDEPARSE; /* turn off quote()ing */
1104
0
    deparse2buff(TAG(t), d);
1105
0
    d->opts = d_opts_in;
1106
0
    print2buff(" = ", d);
1107
0
      }
1108
0
      deparse2buff(CAR(t), d);
1109
0
      print2buff(", ", d);
1110
0
  }
1111
0
  if( TAG(t) != R_NilValue ) {
1112
0
      d->opts = SIMPLEDEPARSE; /* turn off quote()ing */
1113
0
      deparse2buff(TAG(t), d);
1114
0
      d->opts = d_opts_in;
1115
0
      print2buff(" = ", d);
1116
0
  }
1117
0
  deparse2buff(CAR(t), d);
1118
0
  if (missing)
1119
0
      print2buff("))", d);
1120
0
  else
1121
0
      print2buff(")", d);
1122
0
  d->inlist--;
1123
0
  if(attr >= STRUC_ATTR) attr2(s, d, (attr == STRUC_ATTR));
1124
0
  break;
1125
0
    }
1126
262k
    case LANGSXP:
1127
262k
  if (!isNull(ATTRIB(s)))
1128
0
      d->sourceable = false;
1129
262k
  SEXP op = CAR(s);
1130
262k
  bool doquote = false;
1131
262k
  bool maybe_quote = d_opts_in & QUOTEEXPRESSIONS;
1132
262k
  if (maybe_quote) {
1133
      // do *not* quote() formulas:
1134
0
      doquote = // := op is not `~` (tilde) :
1135
0
    !((TYPEOF(op) == SYMSXP) &&
1136
0
      !strcmp(CHAR(PRINTNAME(op)), "~"));
1137
0
      if (doquote) {
1138
0
    print2buff("quote(", d);
1139
0
    d->opts &= SIMPLE_OPTS;
1140
0
      } else { // `~`
1141
0
    d->opts &= ~QUOTEEXPRESSIONS;
1142
0
      }
1143
0
  }
1144
1145
262k
  if (TYPEOF(op) == SYMSXP) {
1146
257k
      int userbinop = 0;
1147
257k
      if ((TYPEOF(SYMVALUE(op)) == BUILTINSXP) ||
1148
217k
    (TYPEOF(SYMVALUE(op)) == SPECIALSXP) ||
1149
201k
    (userbinop = isUserBinop(op))) {
1150
58.4k
    PPinfo fop;
1151
58.4k
    bool parens;
1152
58.4k
    s = CDR(s);
1153
58.4k
    if (userbinop) {
1154
2.84k
        if (isNull(getAttrib(s, R_NamesSymbol))) {
1155
      // not quite right for spacing, but can't be unary :
1156
2.78k
      fop.kind = PP_BINARY2;
1157
2.78k
      fop.precedence = PREC_PERCENT;
1158
2.78k
      fop.rightassoc = 0;
1159
2.78k
        } else
1160
      // if args are named, deparse as function call (PR#15350):
1161
63
      fop.kind = PP_FUNCALL;
1162
2.84k
    } else
1163
55.6k
        fop = PPINFO(SYMVALUE(op));
1164
1165
58.4k
    switch (fop.kind) {
1166
15.9k
    case PP_BINARY:
1167
15.9k
        switch (length(s)) {
1168
11.1k
        case 1:
1169
11.1k
      fop.kind = PP_UNARY;
1170
11.1k
      if (fop.precedence == PREC_SUM)
1171
          // binary +/- precedence upgraded as unary
1172
9.29k
          fop.precedence = PREC_SIGN;
1173
11.1k
      break;
1174
4.78k
        case 2:
1175
4.78k
      break;
1176
4
        default:
1177
4
      fop.kind = PP_FUNCALL;
1178
4
      break;
1179
15.9k
        }
1180
15.9k
        break;
1181
25.7k
    case PP_BINARY2:
1182
25.7k
        if (length(s) != 2)
1183
330
      fop.kind = PP_FUNCALL;
1184
25.3k
        else if (userbinop)
1185
2.45k
      fop.kind = PP_BINARY;
1186
25.7k
        break;
1187
3.38k
    case PP_DOLLAR: {
1188
3.38k
        if (length(s) != 2) {
1189
19
      fop.kind = PP_FUNCALL;
1190
19
      break;
1191
19
        }
1192
3.36k
        SEXP rhs = CADR(s);
1193
3.36k
        if (TYPEOF(rhs) != SYMSXP && !(isValidString(rhs)
1194
525
               && STRING_ELT(rhs, 0) != NA_STRING))
1195
3
      fop.kind = PP_FUNCALL;
1196
3.36k
        break;
1197
3.38k
    }
1198
13.4k
    default:
1199
13.4k
        break;
1200
58.4k
    }
1201
58.4k
    switch (fop.kind) {
1202
545
    case PP_IF:
1203
545
        print2buff("if (", d);
1204
        /* print the predicate */
1205
545
        deparse2buff(CAR(s), d);
1206
545
        print2buff(") ", d);
1207
545
        if (d->incurly && !d->inlist ) {
1208
0
      lookahead = curlyahead(CADR(s));
1209
0
      if (!lookahead) {
1210
0
          writeline(d);
1211
0
          d->indent++;
1212
0
      }
1213
0
        }
1214
        /* need to find out if there is an else */
1215
545
        if (length(s) > 2) {
1216
445
      deparse2buff(CADR(s), d);
1217
445
      if (d->incurly && !d->inlist) {
1218
0
          writeline(d);
1219
0
          if (!lookahead)
1220
0
        d->indent--;
1221
0
      }
1222
445
      else
1223
445
          print2buff(" ", d);
1224
445
      print2buff("else ", d);
1225
445
      deparse2buff(CADDR(s), d);
1226
445
        }
1227
100
        else {
1228
100
      deparse2buff(CADR(s), d);
1229
100
      if (d->incurly && !lookahead && !d->inlist )
1230
0
          d->indent--;
1231
100
        }
1232
545
        break;
1233
66
    case PP_WHILE:
1234
66
        print2buff("while (", d);
1235
66
        deparse2buff(CAR(s), d);
1236
66
        print2buff(") ", d);
1237
66
        deparse2buff(CADR(s), d);
1238
66
        break;
1239
20
    case PP_FOR:
1240
20
        print2buff("for (", d);
1241
20
        deparse2buff(CAR(s), d);
1242
20
        print2buff(" in ", d);
1243
20
        deparse2buff(CADR(s), d);
1244
20
        print2buff(") ", d);
1245
20
        deparse2buff(CADDR(s), d);
1246
20
        break;
1247
95
    case PP_REPEAT:
1248
95
        print2buff("repeat ", d);
1249
95
        deparse2buff(CAR(s), d);
1250
95
        break;
1251
12
    case PP_CURLY:
1252
12
        print2buff("{", d);
1253
12
        d->incurly += 1;
1254
12
        d->indent++;
1255
12
        writeline(d);
1256
94
        while (s != R_NilValue) {
1257
82
      deparse2buff(CAR(s), d);
1258
82
      writeline(d);
1259
82
      s = CDR(s);
1260
82
        }
1261
12
        d->indent--;
1262
12
        print2buff("}", d);
1263
12
        d->incurly -= 1;
1264
12
        break;
1265
1.18k
    case PP_PAREN:
1266
1.18k
        print2buff("(", d);
1267
1.18k
        deparse2buff(CAR(s), d);
1268
1.18k
        print2buff(")", d);
1269
1.18k
        break;
1270
1.59k
    case PP_SUBSET:
1271
1.59k
        if ((parens = needsparens(fop, CAR(s), 1, prevLeft)))
1272
17
      print2buff("(", d);
1273
1.59k
        deparse2buff(CAR(s), d);
1274
1.59k
        if (parens)
1275
17
      print2buff(")", d);
1276
1.59k
        if (PRIMVAL(SYMVALUE(op)) == 1)
1277
1.58k
      print2buff("[", d);
1278
10
        else
1279
10
      print2buff("[[", d);
1280
1.59k
        args2buff(CDR(s), 0, 0, d);
1281
1.59k
        if (PRIMVAL(SYMVALUE(op)) == 1)
1282
1.58k
      print2buff("]", d);
1283
10
        else
1284
10
      print2buff("]]", d);
1285
1.59k
        break;
1286
470
    case PP_FUNCALL:
1287
483
    case PP_RETURN:
1288
483
        if (d->backtick)
1289
483
      print2buff(quotify(PRINTNAME(op), '`'), d);
1290
0
        else
1291
0
      print2buff(quotify(PRINTNAME(op), '"'), d);
1292
483
        print2buff("(", d);
1293
483
        d->inlist++;
1294
483
        args2buff(s, 0, 0, d);
1295
483
        d->inlist--;
1296
483
        print2buff(")", d);
1297
483
        break;
1298
71
    case PP_FOREIGN:
1299
71
        print2buff(CHAR(PRINTNAME(op)), d); /* ASCII */
1300
71
        print2buff("(", d);
1301
71
        d->inlist++;
1302
71
        args2buff(s, 1, 0, d);
1303
71
        d->inlist--;
1304
71
        print2buff(")", d);
1305
71
        break;
1306
146
    case PP_FUNCTION:
1307
146
        if (!(d->opts & USESOURCE) || !isString(CADDR(s))) {
1308
146
      print2buff(CHAR(PRINTNAME(op)), d); /* ASCII */
1309
146
      print2buff("(", d);
1310
146
      args2buff(FORMALS(s), 0, 1, d);
1311
146
      print2buff(") ", d);
1312
146
      deparse2buff(CADR(s), d);
1313
146
        } else {
1314
0
      s = CADDR(s);
1315
0
      n = length(s);
1316
0
      const void *vmax = vmaxget();
1317
0
      for(i = 0 ; i < n ; i++) {
1318
0
          print2buff(translateChar(STRING_ELT(s, i)), d);
1319
0
          writeline(d);
1320
0
      }
1321
0
      vmaxset(vmax);
1322
0
        }
1323
146
        break;
1324
5.50k
    case PP_ASSIGN:
1325
5.77k
    case PP_ASSIGN2: {
1326
5.77k
        bool outerparens = fnarg && !strcmp(CHAR(PRINTNAME(op)), "=");
1327
5.77k
        if (outerparens)
1328
1.13k
          print2buff("(", d);
1329
5.77k
        if ((parens = needsparens(fop, CAR(s), 1, prevLeft)))
1330
36
      print2buff("(", d);
1331
5.77k
        d->left = parens ? 0 : fop.precedence;
1332
5.77k
        deparse2buff(CAR(s), d);
1333
5.77k
        if (parens)
1334
36
      print2buff(")", d);
1335
5.77k
        print2buff(" ", d);
1336
5.77k
        print2buff(CHAR(PRINTNAME(op)), d); /* ASCII */
1337
5.77k
        print2buff(" ", d);
1338
5.77k
        if ((parens = needsparens(fop, CADR(s), 0, prevLeft)))
1339
0
      print2buff("(", d);
1340
5.77k
        d->left = parens ? 0 : prevLeft;
1341
5.77k
        deparse2buff(CADR(s), d);
1342
5.77k
        if (parens)
1343
0
      print2buff(")", d);
1344
5.77k
        if (outerparens)
1345
1.13k
          print2buff(")", d);
1346
5.77k
        d->left = 0;
1347
5.77k
        break;
1348
5.50k
    }
1349
3.35k
    case PP_DOLLAR:
1350
3.35k
        if ((parens = needsparens(fop, CAR(s), 1, prevLeft)))
1351
39
      print2buff("(", d);
1352
3.35k
        d->left = parens ? 0 : fop.precedence;
1353
3.35k
        deparse2buff(CAR(s), d);
1354
3.35k
        if (parens)
1355
39
      print2buff(")", d);
1356
3.35k
        print2buff(CHAR(PRINTNAME(op)), d); /* ASCII */
1357
        /*temp fix to handle printing of x$a's */
1358
3.35k
        if( isString(CADR(s)) &&
1359
525
      isValidName(CHAR(STRING_ELT(CADR(s), 0))))
1360
30
      deparse2buff(STRING_ELT(CADR(s), 0), d);
1361
3.32k
        else {
1362
3.32k
      if ((parens = needsparens(fop, CADR(s), 0, prevLeft)))
1363
0
          print2buff("(", d);
1364
3.32k
      d->left = parens ? 0 : prevLeft;
1365
3.32k
      deparse2buff(CADR(s), d);
1366
3.32k
      if (parens)
1367
0
          print2buff(")", d);
1368
3.32k
        }
1369
3.35k
        d->left = 0;
1370
3.35k
        break;
1371
7.23k
    case PP_BINARY:
1372
7.23k
        if ((parens = needsparens(fop, CAR(s), 1, prevLeft)))
1373
12
      print2buff("(", d);
1374
7.23k
        d->left = parens ? 0 : fop.precedence;
1375
7.23k
        deparse2buff(CAR(s), d);
1376
7.23k
        if (parens)
1377
12
      print2buff(")", d);
1378
7.23k
        print2buff(" ", d);
1379
7.23k
        print2buff(CHAR(PRINTNAME(op)), d); /* ASCII */
1380
7.23k
        print2buff(" ", d);
1381
7.23k
        linebreak(&lbreak, d);
1382
1383
7.23k
        if ((parens = needsparens(fop, CADR(s), 0, prevLeft)))
1384
313
      print2buff("(", d);
1385
7.23k
        d->left = parens ? 0 : prevLeft;
1386
7.23k
        deparse2buff(CADR(s), d);
1387
7.23k
        if (parens)
1388
313
      print2buff(")", d);
1389
7.23k
        if (lbreak) {
1390
820
      d->indent--;
1391
820
      lbreak = false;
1392
820
        }
1393
7.23k
        d->left = 0;
1394
7.23k
        break;
1395
22.9k
    case PP_BINARY2:  /* no space between op and args */
1396
22.9k
        if ((parens = needsparens(fop, CAR(s), 1, prevLeft)))
1397
338
      print2buff("(", d);
1398
22.9k
        d->left = parens ? 0 : fop.precedence;
1399
22.9k
        deparse2buff(CAR(s), d);
1400
22.9k
        if (parens)
1401
338
      print2buff(")", d);
1402
1403
22.9k
        print2buff(CHAR(PRINTNAME(op)), d); /* ASCII */
1404
22.9k
        if ((parens = needsparens(fop, CADR(s), 0, prevLeft)))
1405
388
      print2buff("(", d);
1406
22.9k
        d->left = parens ? 0 : prevLeft;
1407
22.9k
        deparse2buff(CADR(s), d);
1408
22.9k
        if (parens)
1409
388
      print2buff(")", d);
1410
22.9k
        d->left = 0;
1411
22.9k
        break;
1412
14.9k
    case PP_UNARY:
1413
14.9k
        print2buff(CHAR(PRINTNAME(op)), d); /* ASCII */
1414
14.9k
        if ((parens = needsparens(fop, CAR(s), 0, prevLeft)))
1415
159
      print2buff("(", d);
1416
14.9k
        d->left = parens ? 0 : prevLeft;
1417
14.9k
        deparse2buff(CAR(s), d);
1418
14.9k
        if (parens)
1419
159
      print2buff(")", d);
1420
14.9k
        d->left = 0;
1421
14.9k
        break;
1422
21
    case PP_BREAK:
1423
21
        print2buff("break", d);
1424
21
        break;
1425
16
    case PP_NEXT:
1426
16
        print2buff("next", d);
1427
16
        break;
1428
0
    case PP_SUBASS:
1429
0
        if(d->opts & S_COMPAT) {
1430
0
      print2buff("\"", d);
1431
0
      print2buff(CHAR(PRINTNAME(op)), d); /* ASCII */
1432
0
      print2buff("\'(", d);
1433
0
        } else {
1434
0
      print2buff("`", d);
1435
0
      print2buff(CHAR(PRINTNAME(op)), d); /* ASCII */
1436
0
      print2buff("`(", d);
1437
0
        }
1438
0
        args2buff(s, 0, 0, d);
1439
0
        print2buff(")", d);
1440
0
        break;
1441
0
    default:
1442
0
        d->sourceable = false;
1443
0
        UNIMPLEMENTED("deparse2buff");
1444
58.4k
    }
1445
58.4k
      }
1446
198k
      else {
1447
198k
    SEXP val = R_NilValue; /* -Wall */
1448
198k
    if (isSymbol(CAR(s))) {
1449
198k
        val = SYMVALUE(CAR(s));
1450
198k
        if (TYPEOF(val) == PROMSXP)
1451
8.55k
      val = eval(val, R_BaseEnv);
1452
198k
    }
1453
198k
    if ( isSymbol(CAR(s))
1454
198k
      && TYPEOF(val) == CLOSXP
1455
8.55k
      && streql(CHAR(PRINTNAME(CAR(s))), "::") ) { //  :: is special case
1456
0
        deparse2buff(CADR(s), d);
1457
0
        print2buff("::", d);
1458
0
        deparse2buff(CADDR(s), d);
1459
0
    }
1460
198k
    else if ( isSymbol(CAR(s))
1461
198k
      && TYPEOF(val) == CLOSXP
1462
8.55k
      && streql(CHAR(PRINTNAME(CAR(s))), ":::") ) { // ::: is special case
1463
0
        deparse2buff(CADR(s), d);
1464
0
        print2buff(":::", d);
1465
0
        deparse2buff(CADDR(s), d);
1466
0
    }
1467
198k
    else {
1468
198k
        if ( isSymbol(CAR(s)) ){
1469
198k
      if(d->opts & S_COMPAT)
1470
0
          print2buff(quotify(PRINTNAME(CAR(s)), '\''), d);
1471
198k
      else
1472
198k
          print2buff(quotify(PRINTNAME(CAR(s)), '`'), d);
1473
198k
        }
1474
0
        else
1475
0
      deparse2buff(CAR(s), d);
1476
198k
        print2buff("(", d);
1477
198k
        args2buff(CDR(s), 0, 0, d);
1478
198k
        print2buff(")", d);
1479
198k
    }
1480
198k
      }
1481
257k
  } // end{op : SYMSXP }
1482
5.39k
  else if (TYPEOF(op) == CLOSXP || TYPEOF(op) == SPECIALSXP
1483
5.39k
     || TYPEOF(op) == BUILTINSXP) {
1484
0
      if (parenthesizeCaller(op)) {
1485
0
    print2buff("(", d);
1486
0
    deparse2buff(op, d);
1487
0
    print2buff(")", d);
1488
0
      } else
1489
0
    deparse2buff(op, d);
1490
0
      print2buff("(", d);
1491
0
      args2buff(CDR(s), 0, 0, d);
1492
0
      print2buff(")", d);
1493
0
  }
1494
5.39k
  else { /* we have a lambda expression */
1495
5.39k
      if (parenthesizeCaller(op)) {
1496
3.69k
    print2buff("(", d);
1497
3.69k
    deparse2buff(op, d);
1498
3.69k
    print2buff(")", d);
1499
3.69k
      } else
1500
1.70k
    deparse2buff(op, d);
1501
5.39k
      print2buff("(", d);
1502
5.39k
      args2buff(CDR(s), 0, 0, d);
1503
5.39k
      print2buff(")", d);
1504
5.39k
  }
1505
262k
  if (maybe_quote) {
1506
0
      d->opts = d_opts_in;
1507
0
      if(doquote)
1508
0
    print2buff(")", d);
1509
0
  }
1510
262k
  break; // end{case LANGSXP} ---------------------------------------------
1511
7.53k
    case STRSXP:
1512
9.90k
    case LGLSXP:
1513
11.1k
    case INTSXP:
1514
33.3k
    case REALSXP:
1515
35.0k
    case CPLXSXP:
1516
38.8k
    case RAWSXP:
1517
38.8k
  vector2buff(s, d);
1518
38.8k
  break;
1519
0
    case EXTPTRSXP:
1520
0
    {
1521
0
  char tpb[32]; /* need 12+2+2*sizeof(void*) */
1522
0
  d->sourceable = false;
1523
0
  snprintf(tpb, 32, "<pointer: %p>", R_ExternalPtrAddr(s));
1524
0
  tpb[31] = '\0';
1525
0
  print2buff(tpb, d);
1526
0
    }
1527
0
  break;
1528
0
    case BCODESXP:
1529
0
  d->sourceable = false;
1530
0
  print2buff("<bytecode>", d);
1531
0
  break;
1532
0
    case WEAKREFSXP:
1533
0
  d->sourceable = false;
1534
0
  print2buff("<weak reference>", d);
1535
0
  break;
1536
0
    case OBJSXP:
1537
  /* a bare OBJSXP, e.g. from S7; objects with the S4 bit
1538
     are dealt with above.  Deparse to  .OBJSXP() or  structure(.OBJSXP(), <attrs>)  */
1539
0
  if(d_opts_in & SHOW_ATTR_OR_NMS) {
1540
0
      SEXP a = ATTRIB(s);
1541
0
      print2buff("structure(.OBJSXP()", d);
1542
0
      for( ; !isNull(a); a = CDR(a)) {
1543
0
    if(TAG(a) != R_SrcrefSymbol) {
1544
0
        print2buff(", ", d);
1545
0
        attrEntry(a, d);
1546
0
    }
1547
0
      }
1548
0
  }
1549
0
  print2buff(")", d);
1550
0
  break;
1551
0
    default:
1552
0
  d->sourceable = false;
1553
0
  UNIMPLEMENTED_TYPE("deparse2buff", s);
1554
332k
    }
1555
1556
332k
    d->left = prevLeft;
1557
332k
}
1558
1559
1560
/* If there is a string array active point to that, and */
1561
/* otherwise we are counting lines so don't do anything. */
1562
1563
static void writeline(LocalParseData *d)
1564
35.4k
{
1565
35.4k
    if (d->strvec != R_NilValue && d->linenumber < d->maxlines)
1566
19.3k
  SET_STRING_ELT(d->strvec, d->linenumber, mkChar(d->buffer.data));
1567
35.4k
    d->linenumber++;
1568
35.4k
    if (d->linenumber >= d->maxlines) d->active = false;
1569
    /* reset */
1570
35.4k
    d->len = 0;
1571
35.4k
    d->buffer.data[0] = '\0';
1572
35.4k
    d->startline = true;
1573
35.4k
}
1574
1575
static void print2buff(const char *strng, LocalParseData *d)
1576
905k
{
1577
905k
    size_t tlen, bufflen;
1578
1579
905k
    if (d->startline) {
1580
35.2k
  d->startline = false;
1581
35.2k
  printtab2buff(d->indent, d);  /*if at the start of a line tab over */
1582
35.2k
    }
1583
905k
    tlen = strlen(strng);
1584
905k
    R_AllocStringBuffer(0, &(d->buffer));
1585
905k
    bufflen = strlen(d->buffer.data);
1586
905k
    R_AllocStringBuffer(bufflen + tlen, &(d->buffer));
1587
905k
    strcat(d->buffer.data, strng);
1588
905k
    d->len += (int) tlen;
1589
905k
}
1590
1591
/*
1592
 * Encodes a complex value as a syntactically correct
1593
 * string that can be reparsed by R. This is required
1594
 * because by default strings like '1+Infi' or '3+NaNi'
1595
 * are produced which are not valid complex literals.
1596
 */
1597
1598
398
#define NB 1000  /* Same as printutils.c */
1599
398
#define NB2 2*NB+25
1600
static const char *EncodeNonFiniteComplexElement(Rcomplex x, char* buff)
1601
199
{
1602
199
    int w, d, e, wi, di, ei;
1603
1604
    // format a first time to get width/decimals
1605
199
    formatComplex(&x, 1, &w, &d, &e, &wi, &di, &ei, 0);
1606
1607
199
    char Re[NB];
1608
199
    char Im[NB];
1609
1610
199
    strcpy(Re, EncodeReal0(x.r, w, d, e, "."));
1611
199
    strcpy(Im, EncodeReal0(x.i, wi, di, ei, "."));
1612
1613
199
    snprintf(buff, NB2, "complex(real=%s, imaginary=%s)", Re, Im);
1614
199
    buff[NB2-1] = '\0';
1615
199
    return buff;
1616
199
}
1617
1618
0
static void deparse2buf_name(SEXP nv, int i, LocalParseData *d) {
1619
0
    if (!isNull(nv) && !isNull(STRING_ELT(nv, i))
1620
0
  && *CHAR(STRING_ELT(nv, i))) { /* length test */
1621
  /* d->opts = SIMPLEDEPARSE; This seems pointless */
1622
0
  if(isValidName(translateChar(STRING_ELT(nv, i))))
1623
0
      deparse2buff(STRING_ELT(nv, i), d);
1624
0
  else if(d->backtick) {
1625
0
      print2buff("`", d);
1626
0
      deparse2buff(STRING_ELT(nv, i), d);
1627
0
      print2buff("`", d);
1628
0
  } else {
1629
0
      print2buff("\"", d);
1630
0
      deparse2buff(STRING_ELT(nv, i), d);
1631
0
      print2buff("\"", d);
1632
0
  }
1633
  /* d->opts = d_opts_in; */
1634
0
  print2buff(" = ", d);
1635
0
    }
1636
0
}
1637
1638
// deparse atomic vectors :
1639
static void vector2buff(SEXP vector, LocalParseData *d)
1640
38.8k
{
1641
    // Known here:  TYPEOF(vector)  is one of the 6 atomic *SXPs
1642
38.8k
    const char *strp;
1643
38.8k
    char *buff = 0, hex[64]; // 64 is more than enough
1644
38.8k
    int i, d_opts_in = d->opts,
1645
38.8k
  tlen = length(vector),
1646
38.8k
  quote = isString(vector) ? '"' : 0;
1647
38.8k
    bool surround = false, allNA,
1648
38.8k
  intSeq = false; // := true iff integer sequence 'm:n' (up *or* down)
1649
38.8k
    if(TYPEOF(vector) == INTSXP && tlen > 1) {
1650
0
  int *vec = INTEGER(vector);
1651
  // vec[1] - vec[0] could overflow, and does in package Rmpfr
1652
0
  double d_i = (double) vec[1] - (double)vec[0];
1653
0
  intSeq = (vec[0] != NA_INTEGER &&
1654
0
      vec[1] != NA_INTEGER &&
1655
0
      fabs(d_i) == 1);
1656
0
  if(intSeq) for(i = 2; i < tlen; i++) {
1657
0
      if((vec[i] == NA_INTEGER) ||
1658
0
         ((double)vec[i] - (double)vec[i-1]) != d_i) {
1659
0
    intSeq = false;
1660
0
    break;
1661
0
      }
1662
0
  }
1663
0
    }
1664
1665
38.8k
    SEXP nv = R_NilValue;
1666
38.8k
    bool do_names = (bool)(d_opts_in & SHOW_ATTR_OR_NMS);// iff true use '<tag_i> = <comp_i>'
1667
38.8k
    if(do_names) {
1668
38.8k
  nv = getAttrib(vector, R_NamesSymbol); // only "do names" if have names:
1669
38.8k
  if(isNull(nv))
1670
38.8k
      do_names = false;
1671
38.8k
    }
1672
38.8k
    PROTECT(nv);
1673
38.8k
    bool
1674
38.8k
  STR_names, // if true, use structure(.,*) for names even if(nice_names)
1675
38.8k
  need_c = tlen > 1; // (?) only true iff SHOW_ATTR_OR_NMS
1676
38.8k
    STR_names = do_names && (intSeq || tlen == 0);
1677
#ifdef DEBUG_DEPARSE
1678
    REprintf("vector2buff(v): length(v) = %d; initial (do|STR)_names) = (%s,%s)\n",
1679
       tlen, ChTF(do_names), ChTF(STR_names));
1680
#endif
1681
38.8k
    if (STR_names) // use structure(.,*) for names even if(nice_names)
1682
0
  d->opts &= ~NICE_NAMES;
1683
38.8k
    attr_type attr = (d_opts_in & SHOW_ATTR_OR_NMS) ? attr1(vector, d) : SIMPLE;
1684
38.8k
    if(do_names) do_names = (attr == OK_NAMES || attr == STRUC_ATTR);
1685
38.8k
    if(!need_c) need_c = do_names; // c(a = *) but not c(1)
1686
#ifdef DEBUG_DEPARSE
1687
    REprintf(" -> final (do|STR)_names) = (%s,%s), attr = %s\n",
1688
       ChTF(do_names), ChTF(STR_names), attrT2char(attr));
1689
#endif
1690
38.8k
    if (tlen == 0) {
1691
0
  switch(TYPEOF(vector)) {
1692
0
  case LGLSXP: print2buff("logical(0)", d); break;
1693
0
  case INTSXP: print2buff("integer(0)", d); break;
1694
0
  case REALSXP: print2buff("numeric(0)", d); break;
1695
0
  case CPLXSXP: print2buff("complex(0)", d); break;
1696
0
  case STRSXP: print2buff("character(0)", d); break;
1697
0
  case RAWSXP: print2buff("raw(0)", d); break;
1698
0
  default: UNIMPLEMENTED_TYPE("vector2buff", vector);
1699
0
  }
1700
0
    }
1701
38.8k
    else if(TYPEOF(vector) == INTSXP) {
1702
  /* We treat integer separately, as S_compatible is relevant.
1703
1704
     Also, it is neat to deparse m:n in that form,
1705
     so we do so as from 2.5.0, and for m > n, from 3.5.0
1706
   */
1707
1.28k
  if(intSeq) { // m:n
1708
0
    strp = EncodeElement(vector, 0, '"', '.');
1709
0
    print2buff(strp, d);
1710
0
    print2buff(":", d);
1711
0
    strp = EncodeElement(vector, tlen - 1, '"', '.');
1712
0
    print2buff(strp, d);
1713
1.28k
  } else {
1714
1.28k
      int *vec = INTEGER(vector);
1715
1.28k
      bool addL = d->opts & KEEPINTEGER & !(d->opts & S_COMPAT);
1716
1.28k
      allNA = (d->opts & KEEPNA) || addL;
1717
1.57k
      for(i = 0; i < tlen; i++)
1718
1.28k
    if(vec[i] != NA_INTEGER) {
1719
985
        allNA = false;
1720
985
        break;
1721
985
    }
1722
1.28k
      if((d->opts & KEEPINTEGER && (d->opts & S_COMPAT))) {
1723
0
    print2buff("as.integer(", d); surround = true;
1724
0
      }
1725
1.28k
      allNA = allNA && !(d->opts & S_COMPAT);
1726
1.28k
      if(need_c) print2buff("c(", d);
1727
2.56k
      for (i = 0; i < tlen; i++) {
1728
1.28k
    if(do_names) // put '<tag> = '
1729
0
        deparse2buf_name(nv, i, d);
1730
1.28k
    if(allNA && vec[i] == NA_INTEGER) {
1731
295
        print2buff("NA_integer_", d);
1732
985
    } else {
1733
985
        strp = EncodeElement(vector, i, quote, '.');
1734
985
        print2buff(strp, d);
1735
985
        if(addL && vec[i] != NA_INTEGER) print2buff("L", d);
1736
985
    }
1737
1.28k
    if (i < (tlen - 1)) print2buff(", ", d);
1738
1.28k
    if (tlen > 1 && d->len > d->cutoff) writeline(d);
1739
1.28k
    if (!d->active) break;
1740
1.28k
      }
1741
1.28k
      if(need_c)   print2buff(")", d);
1742
1.28k
      if(surround) print2buff(")", d);
1743
1.28k
  }
1744
37.5k
    } else { // tlen > 0;  _not_ INTSXP
1745
37.5k
  allNA = d->opts & KEEPNA;
1746
37.5k
  if((d->opts & KEEPNA) && TYPEOF(vector) == REALSXP) {
1747
22.2k
      for(i = 0; i < tlen; i++)
1748
22.1k
    if(!ISNA(REAL(vector)[i])) {
1749
22.1k
        allNA = false;
1750
22.1k
        break;
1751
22.1k
    }
1752
22.1k
      if(allNA && (d->opts & S_COMPAT)) {
1753
0
    print2buff("as.double(", d); surround = true;
1754
0
      }
1755
22.1k
  } else if((d->opts & KEEPNA) && TYPEOF(vector) == CPLXSXP) {
1756
1.63k
      Rcomplex *vec = COMPLEX(vector);
1757
2.30k
      for(i = 0; i < tlen; i++) {
1758
1.63k
    if( !ISNA(vec[i].r) && !ISNA(vec[i].i) ) {
1759
963
        allNA = false;
1760
963
        break;
1761
963
    }
1762
1.63k
      }
1763
1.63k
      if(allNA && (d->opts & S_COMPAT)) {
1764
0
    print2buff("as.complex(", d); surround = true;
1765
1766
0
      }
1767
13.7k
  } else if((d->opts & KEEPNA) && TYPEOF(vector) == STRSXP) {
1768
7.69k
      for(i = 0; i < tlen; i++)
1769
7.53k
    if(STRING_ELT(vector, i) != NA_STRING) {
1770
7.37k
        allNA = false;
1771
7.37k
        break;
1772
7.37k
    }
1773
7.53k
      if(allNA && (d->opts & S_COMPAT)) {
1774
0
    print2buff("as.character(", d); surround = true;
1775
0
      }
1776
7.53k
  } else if(TYPEOF(vector) == RAWSXP) {
1777
3.86k
      print2buff("as.raw(", d); surround = true;
1778
3.86k
  }
1779
37.5k
  if(need_c) print2buff("c(", d);
1780
37.5k
  allNA = allNA && !(d->opts & S_COMPAT);
1781
94.0k
  for (i = 0; i < tlen; i++) {
1782
60.1k
      if(do_names) // put '<tag> = '
1783
0
    deparse2buf_name(nv, i, d);
1784
60.1k
      if(allNA && TYPEOF(vector) == REALSXP &&
1785
12
         ISNA(REAL(vector)[i])) {
1786
12
    strp = "NA_real_";
1787
60.1k
      } else if (TYPEOF(vector) == CPLXSXP &&
1788
1.63k
           (ISNA(COMPLEX(vector)[i].r)
1789
672
      && ISNA(COMPLEX(vector)[i].i)) ) {
1790
672
    strp = allNA ? "NA_complex_" : EncodeElement(vector, i, quote, '.');
1791
59.4k
      } else if(TYPEOF(vector) == CPLXSXP &&
1792
963
          (ISNAN(COMPLEX(vector)[i].r) || !R_FINITE(COMPLEX(vector)[i].i)) ) {
1793
199
    if (!buff)
1794
199
        buff = alloca(NB2);
1795
199
    strp = EncodeNonFiniteComplexElement(COMPLEX(vector)[i], buff);
1796
59.2k
      } else if (allNA && TYPEOF(vector) == STRSXP &&
1797
158
           STRING_ELT(vector, i) == NA_STRING) {
1798
158
    strp = "NA_character_";
1799
59.1k
      } else if (TYPEOF(vector) == REALSXP && (d->opts & S_COMPAT)) {
1800
0
    int w, d, e;
1801
0
    formatReal(&REAL(vector)[i], 1, &w, &d, &e, 0);
1802
0
    strp = EncodeReal2(REAL(vector)[i], w, d, e);
1803
59.1k
      } else if (TYPEOF(vector) == STRSXP) {
1804
7.37k
    const void *vmax = vmaxget();
1805
#ifdef longstring_WARN
1806
    const char *ts = translateChar(STRING_ELT(vector, i));
1807
    /* versions of R < 2.7.0 cannot parse strings longer than 8192 chars */
1808
    if(strlen(ts) >= 8192) d->longstring = true;
1809
#endif
1810
7.37k
    strp = EncodeElement(vector, i, quote, '.');
1811
7.37k
    vmaxset(vmax);
1812
51.7k
      } else if (TYPEOF(vector) == RAWSXP) {
1813
26.4k
    strp = EncodeRaw(RAW(vector)[i], "0x");
1814
26.4k
      } else if (TYPEOF(vector) == REALSXP && (d->opts & HEXNUMERIC)) {
1815
0
    double x = REAL(vector)[i];
1816
    // Windows warns here, but incorrectly as this is C99
1817
    // and the snprintf used from trio is compliant.
1818
0
    if (R_FINITE(x)) {
1819
0
        snprintf(hex, 32, "%a", x);
1820
0
        strp = hex;
1821
0
    } else
1822
0
        strp = EncodeElement(vector, i, quote, '.');
1823
25.3k
      } else if (TYPEOF(vector) == REALSXP && (d->opts & DIGITS17)) {
1824
0
    double x = REAL(vector)[i];
1825
0
    if (R_FINITE(x)) {
1826
0
        snprintf(hex, 32, "%.17g", x);
1827
0
        strp = hex;
1828
0
    } else
1829
0
        strp = EncodeElement(vector, i, quote, '.');
1830
25.3k
      } else if (TYPEOF(vector) == CPLXSXP && (d->opts & HEXNUMERIC)) {
1831
0
    Rcomplex z =  COMPLEX(vector)[i];
1832
0
    if (R_FINITE(z.r) && R_FINITE(z.i)) {
1833
0
        snprintf(hex, 64, "%a + %ai", z.r, z.i);
1834
0
        strp = hex;
1835
0
    } else
1836
0
        strp = EncodeElement(vector, i, quote, '.');
1837
25.3k
      } else if (TYPEOF(vector) == CPLXSXP && (d->opts & DIGITS17)) {
1838
0
    Rcomplex z =  COMPLEX(vector)[i];
1839
0
    if (R_FINITE(z.r) && R_FINITE(z.i)) {
1840
0
        snprintf(hex, 64, "%.17g%+.17gi", z.r, z.i);
1841
0
        strp = hex;
1842
0
    } else
1843
0
        strp = EncodeElement(vector, i, quote, '.');
1844
0
      } else
1845
25.3k
    strp = EncodeElement(vector, i, quote, '.');
1846
60.1k
      print2buff(strp, d);
1847
60.1k
      if (i < (tlen - 1)) print2buff(", ", d);
1848
60.1k
      if (tlen > 1 && d->len > d->cutoff) writeline(d);
1849
60.1k
      if (!d->active) break;
1850
60.1k
  } // for(i in 1:tlen)
1851
37.5k
  if(need_c  ) print2buff(")", d);
1852
37.5k
  if(surround) print2buff(")", d);
1853
37.5k
    }
1854
38.8k
    if(attr >= STRUC_ATTR) attr2(vector, d, (attr == STRUC_ATTR));
1855
38.8k
    if (STR_names) d->opts = d_opts_in;
1856
38.8k
    UNPROTECT(1); /* nv */
1857
38.8k
} // vector2buff()
1858
1859
1860
/* src2buff1: Deparse one source ref to buffer */
1861
1862
static void src2buff1(SEXP srcref, LocalParseData *d)
1863
0
{
1864
0
    int i,n;
1865
0
    const void *vmax = vmaxget();
1866
0
    PROTECT(srcref);
1867
1868
0
    PROTECT(srcref = lang2(R_AsCharacterSymbol, srcref));
1869
0
    PROTECT(srcref = eval(srcref, R_BaseEnv));
1870
0
    n = length(srcref);
1871
0
    for(i = 0 ; i < n ; i++) {
1872
  /* FIXME: does not embed UTF-8 for RGui */
1873
0
  print2buff(translateChar(STRING_ELT(srcref, i)), d);
1874
0
  if(i < n-1) writeline(d);
1875
0
    }
1876
0
    UNPROTECT(3);
1877
0
    vmaxset(vmax);
1878
0
}
1879
1880
/* src2buff : Deparse source element k to buffer, if possible; return false on failure */
1881
1882
static bool src2buff(SEXP sv, int k, LocalParseData *d)
1883
0
{
1884
0
    SEXP t;
1885
1886
0
    if (TYPEOF(sv) == VECSXP && length(sv) > k && !isNull(t = VECTOR_ELT(sv, k))) {
1887
0
  src2buff1(t, d);
1888
0
  return true;
1889
0
    }
1890
0
    else return false;
1891
0
}
1892
1893
/* Deparse vectors of S-expressions, i.e., list() and expression() objects.
1894
   In particular, this deparses objects of mode expression. */
1895
static void vec2buff(SEXP v, LocalParseData *d,
1896
         bool do_names) // iff true use '<tag_i> = <comp_i>'
1897
0
{
1898
0
    bool lbreak = false;
1899
0
    const void *vmax = vmaxget();
1900
0
    int n = length(v);
1901
0
    SEXP nv = R_NilValue;
1902
0
    if(do_names) {
1903
0
  nv = getAttrib(v, R_NamesSymbol); // only "do names" if have names:
1904
0
  if (isNull(nv))
1905
0
      do_names = false;
1906
0
    }
1907
0
    PROTECT(nv);
1908
0
    SEXP sv; // Srcref or NULL
1909
0
    if (d->opts & USESOURCE) {
1910
0
  sv = getAttrib(v, R_SrcrefSymbol);
1911
0
  if (TYPEOF(sv) != VECSXP)
1912
0
      sv = R_NilValue;
1913
0
    } else
1914
0
  sv = R_NilValue;
1915
1916
0
    for(int i = 0 ; i < n ; i++) {
1917
0
  if (i > 0)
1918
0
      print2buff(", ", d);
1919
0
  linebreak(&lbreak, d);
1920
0
  if(do_names) // put '<tag> = '
1921
0
      deparse2buf_name(nv, i, d);
1922
0
  if (!src2buff(sv, i, d))
1923
0
      deparse2buff(VECTOR_ELT(v, i), d);
1924
0
    }
1925
0
    if (lbreak)
1926
0
  d->indent--;
1927
0
    vmaxset(vmax);
1928
0
    UNPROTECT(1); /* nv */
1929
0
}
1930
1931
static void args2buff(SEXP arglist, int lineb, int formals, LocalParseData *d)
1932
206k
{
1933
206k
    bool lbreak = false;
1934
1935
429k
    while (arglist != R_NilValue) {
1936
223k
  if (TYPEOF(arglist) != LISTSXP && TYPEOF(arglist) != LANGSXP)
1937
0
      error(_("badly formed function expression"));
1938
223k
  if (TAG(arglist) != R_NilValue) {
1939
9.02k
      SEXP s = TAG(arglist);
1940
1941
9.02k
      if( s == R_DotsSymbol )
1942
1
    print2buff(CHAR(PRINTNAME(s)), d);
1943
9.02k
      else if(d->backtick)
1944
9.02k
    print2buff(quotify(PRINTNAME(s), '`'), d);
1945
0
      else
1946
0
    print2buff(quotify(PRINTNAME(s), '"'), d);
1947
1948
9.02k
      if(formals) {
1949
41
    if (CAR(arglist) != R_MissingArg) {
1950
10
        print2buff(" = ", d);
1951
10
        d->fnarg = true;
1952
10
        deparse2buff(CAR(arglist), d);
1953
10
    }
1954
41
      }
1955
8.98k
      else {
1956
8.98k
    print2buff(" = ", d);
1957
8.98k
    if (CAR(arglist) != R_MissingArg) {
1958
8.62k
        d->fnarg = true;
1959
8.62k
        deparse2buff(CAR(arglist), d);
1960
8.62k
    }
1961
8.98k
      }
1962
9.02k
  }
1963
214k
  else {
1964
214k
    d->fnarg = true;
1965
214k
    deparse2buff(CAR(arglist), d);
1966
214k
  }
1967
223k
  arglist = CDR(arglist);
1968
223k
  if (arglist != R_NilValue) {
1969
21.6k
      print2buff(", ", d);
1970
21.6k
      linebreak(&lbreak, d);
1971
21.6k
  }
1972
223k
    }
1973
206k
    if (lbreak)
1974
2.36k
  d->indent--;
1975
206k
}
1976
1977
/* This code controls indentation.  Used to follow the S style, */
1978
/* (print 4 tabs and then start printing spaces only) but I */
1979
/* modified it to be closer to emacs style (RI). */
1980
1981
static void printtab2buff(int ntab, LocalParseData *d)
1982
35.2k
{
1983
35.2k
    int i;
1984
1985
37.6k
    for (i = 1; i <= ntab; i++)
1986
2.36k
  if (i <= 4)
1987
2.36k
      print2buff("    ", d);
1988
0
  else
1989
0
      print2buff("  ", d);
1990
35.2k
}