The R Project SVN R

Rev

Rev 77083 | Rev 78021 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
29747 ripley 1
/*
42307 ripley 2
 *  R : A Computer Language for Statistical Data Analysis
76905 kalibera 3
 *  Copyright (C) 1997-2019   The R Core Team
42307 ripley 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
68947 ripley 18
 *  https://www.R-project.org/Licenses/
29747 ripley 19
 */
20
 
21
#ifdef HAVE_CONFIG_H
22
#include <config.h>
23
#endif
36612 ripley 24
 
36622 ripley 25
#include <stdlib.h> /* for putenv */
57538 ripley 26
#define R_USE_SIGNALS 1
29747 ripley 27
#include <Defn.h>
60667 ripley 28
#include <Internal.h>
32670 ripley 29
#include <R_ext/Riconv.h>
39866 duncan 30
#include <Rinterface.h>
42398 ripley 31
#include <errno.h>
72707 murdoch 32
#include <rlocale.h>
29747 ripley 33
 
34
/*
35
  See ../unix/system.txt for a description of some of these functions.
36
  Formally part of ../unix/sys-common.c.
37
 */
38
 
39
/*
40
 * FILESYSTEM INTERACTION
41
 */
42
 
43
/*
44
 * This call provides a simple interface to the "stat" system call.
45
 */
46
 
41349 ripley 47
#ifdef HAVE_SYS_TYPES_H
48
# include <sys/types.h>
49
#endif
50
#ifdef HAVE_SYS_STAT_H
51
# include <sys/stat.h>
52
#endif
29747 ripley 53
 
72621 maechler 54
static int isDir(char *path);
55
 
51388 ripley 56
#ifdef HAVE_AQUA
61483 ripley 57
int (*ptr_CocoaSystem)(const char*);
31157 iacus 58
#endif
59
 
54797 ripley 60
#ifdef Win32
60699 ripley 61
Rboolean R_FileExists(const char *path)
29747 ripley 62
{
54797 ripley 63
    struct _stati64 sb;
64
    return _stati64(R_ExpandFileName(path), &sb) == 0;
65
}
66
 
67
double attribute_hidden R_FileMtime(const char *path)
68
{
69
    struct _stati64 sb;
70
    if (_stati64(R_ExpandFileName(path), &sb) != 0)
71
	error(_("cannot determine file modification time of '%s'"), path);
72
    return sb.st_mtime;
73
}
74
#else
60699 ripley 75
Rboolean R_FileExists(const char *path)
54797 ripley 76
{
29747 ripley 77
    struct stat sb;
78
    return stat(R_ExpandFileName(path), &sb) == 0;
79
}
80
 
41784 ripley 81
double attribute_hidden R_FileMtime(const char *path)
29747 ripley 82
{
83
    struct stat sb;
84
    if (stat(R_ExpandFileName(path), &sb) != 0)
33297 ripley 85
	error(_("cannot determine file modification time of '%s'"), path);
59101 ripley 86
    return (double) sb.st_mtime;
29747 ripley 87
}
54797 ripley 88
#endif
29747 ripley 89
 
90
    /*
91
     *  Unix file names which begin with "." are invisible.
92
     */
93
 
41784 ripley 94
Rboolean attribute_hidden R_HiddenFile(const char *name)
29747 ripley 95
{
96
    if (name && name[0] != '.') return 0;
97
    else return 1;
98
}
99
 
44165 ripley 100
/* The MSVC runtime has a global to determine whether an unspecified
101
   file open is in text or binary mode.  We force explicit text mode
102
   here to avoid depending on that global, which may have been changed
103
   by user code (most likely in embedded applications of R).
44052 murdoch 104
*/
29747 ripley 105
 
44052 murdoch 106
#ifdef Win32
107
 
108
static char * fixmode(const char *mode)
109
{
72650 murdoch 110
    /* Rconnection can have a mode of 4 chars plus a ccs= setting plus a null; we might
111
     * add one char if neither b nor t is specified. */
112
    static char fixedmode[20];
113
    fixedmode[19] = '\0';
114
    strncpy(fixedmode, mode, 19);
44052 murdoch 115
    if (!strpbrk(fixedmode, "bt")) {
45446 ripley 116
	strcat(fixedmode, "t");
44052 murdoch 117
    }
118
    return fixedmode;
119
}
120
 
121
static wchar_t * wcfixmode(const wchar_t *mode)
122
{
72650 murdoch 123
    static wchar_t wcfixedmode[20];
124
    wcfixedmode[19] = L'\0';
125
    wcsncpy(wcfixedmode, mode, 19);
44052 murdoch 126
    if (!wcspbrk(wcfixedmode, L"bt")) {
45446 ripley 127
	wcscat(wcfixedmode, L"t");
44052 murdoch 128
    }
129
    return wcfixedmode;
130
}
131
 
132
#else
133
#define fixmode(mode) (mode)
134
#define wcfixmode(mode) (mode)
135
#endif
136
 
29747 ripley 137
FILE *R_fopen(const char *filename, const char *mode)
138
{
44052 murdoch 139
    return(filename ? fopen(filename, fixmode(mode)) : NULL );
29747 ripley 140
}
141
 
40700 ripley 142
/* The point of this function is to allow file names in foreign
143
   character sets.  On Unix-alikes in a UTF-8 locale all that is
144
   needed is to convert file names to UTF-8, since they will be stored
145
   in UTF-8.  For other locales, it seems that there is no way to specify
146
   a file name in UTF-8.
147
 
148
   On NT-based versions of Windows, file names are stored in 'Unicode'
149
   (UCS-2), and _wfopen is provided to access them by UCS-2 names.
150
*/
151
 
44008 ripley 152
#if defined(Win32)
153
 
70047 ripley 154
#define BSIZE 100000
44008 ripley 155
wchar_t *filenameToWchar(const SEXP fn, const Rboolean expand)
40700 ripley 156
{
54524 ripley 157
    static wchar_t filename[BSIZE+1];
40700 ripley 158
    void *obj;
44008 ripley 159
    const char *from = "", *inbuf;
160
    char *outbuf;
40700 ripley 161
    size_t inb, outb, res;
44008 ripley 162
 
44761 ripley 163
    if(!strlen(CHAR(fn))) {
164
	wcscpy(filename, L"");
165
	return filename;
166
    }
73786 kalibera 167
    if(IS_LATIN1(fn))
168
#ifdef HAVE_ICONV_CP1252
169
	from = "CP1252";
170
#else
171
	from = "latin1";
172
#endif
44054 ripley 173
    if(IS_UTF8(fn)) from = "UTF-8";
54753 ripley 174
    if(IS_BYTES(fn)) error(_("encoding of a filename cannot be 'bytes'"));
40700 ripley 175
    obj = Riconv_open("UCS-2LE", from);
44008 ripley 176
    if(obj == (void *)(-1))
70047 ripley 177
	error(_("unsupported conversion from '%s' in codepage %d"),
45680 ripley 178
	      from, localeCP);
40700 ripley 179
 
180
    if(expand) inbuf = R_ExpandFileName(CHAR(fn)); else inbuf = CHAR(fn);
181
 
54524 ripley 182
    inb = strlen(inbuf)+1; outb = 2*BSIZE;
40700 ripley 183
    outbuf = (char *) filename;
184
    res = Riconv(obj, &inbuf , &inb, &outbuf, &outb);
185
    Riconv_close(obj);
54524 ripley 186
    if(inb > 0) error(_("file name conversion problem -- name too long?"));
44762 ripley 187
    if(res == -1) error(_("file name conversion problem"));
40700 ripley 188
 
44008 ripley 189
    return filename;
190
}
191
 
44016 ripley 192
FILE *R_wfopen(const wchar_t *filename, const wchar_t *mode)
193
{
44695 ripley 194
    return filename ? _wfopen(filename, wcfixmode(mode)) : NULL;
44016 ripley 195
}
196
 
197
 
44008 ripley 198
FILE *RC_fopen(const SEXP fn, const char *mode, const Rboolean expand)
199
{
200
    wchar_t wmode[10];
201
 
44695 ripley 202
    if(fn == NA_STRING) return NULL;
44052 murdoch 203
    mbstowcs(wmode, fixmode(mode), 10);
44008 ripley 204
    return _wfopen(filenameToWchar(fn, expand), wmode);
40700 ripley 205
}
206
#else
207
FILE *RC_fopen(const SEXP fn, const char *mode, const Rboolean expand)
208
{
63181 ripley 209
    const void *vmax = vmaxget();
76974 ripley 210
    const char *filename = translateCharFP(fn), *res;
44695 ripley 211
    if(fn == NA_STRING || !filename) return NULL;
63181 ripley 212
    if(expand) res = R_ExpandFileName(filename);
213
    else res = filename;
214
    vmaxset(vmax);
215
    return fopen(res, mode);
40700 ripley 216
}
217
#endif
218
 
29747 ripley 219
/*
220
 *  SYSTEM INFORMATION
221
 */
222
 
45446 ripley 223
	  /* The location of the R system files */
29747 ripley 224
 
44201 ripley 225
char *R_HomeDir(void)
29747 ripley 226
{
227
    return getenv("R_HOME");
228
}
229
 
51245 ripley 230
/* This is a primitive (with no arguments) */
36990 ripley 231
SEXP attribute_hidden do_interactive(SEXP call, SEXP op, SEXP args, SEXP rho)
29747 ripley 232
{
51245 ripley 233
    checkArity(op, args);
41894 ripley 234
    return ScalarLogical( (R_Interactive) ? 1 : 0 );
29747 ripley 235
}
236
 
36990 ripley 237
SEXP attribute_hidden do_tempdir(SEXP call, SEXP op, SEXP args, SEXP env)
29747 ripley 238
{
41894 ripley 239
    checkArity(op, args);
72621 maechler 240
    Rboolean check = asLogical(CAR(args));
241
    if(check && !isDir(R_TempDir)) {
242
	R_TempDir = NULL;
243
	R_reInitTempDir(/* die_on_fail = */ FALSE);
244
    }
41894 ripley 245
    return mkString(R_TempDir);
29747 ripley 246
}
247
 
248
 
36990 ripley 249
SEXP attribute_hidden do_tempfile(SEXP call, SEXP op, SEXP args, SEXP env)
29747 ripley 250
{
54876 murdoch 251
    SEXP  ans, pattern, fileext, tempdir;
252
    const char *tn, *td, *te;
41783 ripley 253
    char *tm;
54876 murdoch 254
    int i, n1, n2, n3, slen;
29747 ripley 255
 
256
    checkArity(op, args);
54876 murdoch 257
    pattern = CAR(args); n1 = length(pattern); args = CDR(args);
258
    tempdir = CAR(args); n2 = length(tempdir); args = CDR(args);
259
    fileext = CAR(args); n3 = length(fileext);
29747 ripley 260
    if (!isString(pattern))
45446 ripley 261
	error(_("invalid filename pattern"));
29747 ripley 262
    if (!isString(tempdir))
45446 ripley 263
	error(_("invalid '%s' value"), "tempdir");
54876 murdoch 264
    if (!isString(fileext))
265
	error(_("invalid file extension"));
29747 ripley 266
    if (n1 < 1)
41686 ripley 267
	error(_("no 'pattern'"));
29747 ripley 268
    if (n2 < 1)
41686 ripley 269
	error(_("no 'tempdir'"));
54876 murdoch 270
    if (n3 < 1)
70047 ripley 271
	error(_("no 'fileext'"));
29747 ripley 272
    slen = (n1 > n2) ? n1 : n2;
54876 murdoch 273
    slen = (n3 > slen) ? n3 : slen;
29747 ripley 274
    PROTECT(ans = allocVector(STRSXP, slen));
275
    for(i = 0; i < slen; i++) {
76974 ripley 276
	tn = translateCharFP( STRING_ELT( pattern , i%n1 ) );
277
	td = translateCharFP( STRING_ELT( tempdir , i%n2 ) );
278
	te = translateCharFP( STRING_ELT( fileext , i%n3 ) );
29747 ripley 279
	/* try to get a new file name */
54876 murdoch 280
	tm = R_tmpnam2(tn, td, te);
29747 ripley 281
	SET_STRING_ELT(ans, i, mkChar(tm));
282
	if(tm) free(tm);
283
    }
284
    UNPROTECT(1);
285
    return (ans);
286
}
287
 
41781 ripley 288
FILE *R_popen(const char *command, const char *type)
29747 ripley 289
{
290
    FILE *fp;
69881 luke 291
#ifdef OLD__APPLE__
29747 ripley 292
    /* Luke recommends this to fix PR#1140 */
69881 luke 293
    /* As of 2016-01-06 on El Capitan this may no longer be needed -- LT */
29747 ripley 294
    sigset_t ss;
39757 urbaneks 295
    sigemptyset(&ss);
29747 ripley 296
    sigaddset(&ss, SIGPROF);
297
    sigprocmask(SIG_BLOCK, &ss,  NULL);
298
    fp = popen(command, type);
299
    sigprocmask(SIG_UNBLOCK, &ss, NULL);
300
#else
301
    fp = popen(command, type);
302
#endif
303
    return fp;
304
}
305
 
53147 ripley 306
#ifdef HAVE_SYS_WAIT_H
307
# include <sys/wait.h>
308
#endif
309
 
41781 ripley 310
int R_system(const char *command)
29747 ripley 311
{
52799 ripley 312
    int res;
61027 ripley 313
#ifdef __APPLE__
69881 luke 314
# ifdef OLD__APPLE__
29747 ripley 315
    /* Luke recommends this to fix PR#1140 */
69881 luke 316
    /* As of 2016-01-06 on El Capitan this may no longer be needed -- LT */
29747 ripley 317
    sigset_t ss;
39754 urbaneks 318
    sigemptyset(&ss);
29747 ripley 319
    sigaddset(&ss, SIGPROF);
320
    sigprocmask(SIG_BLOCK, &ss,  NULL);
70047 ripley 321
# endif
31157 iacus 322
#ifdef HAVE_AQUA
61483 ripley 323
    if(ptr_CocoaSystem) res = ptr_CocoaSystem(command); else
40376 ripley 324
#endif
52799 ripley 325
    res = system(command);
69881 luke 326
# ifdef OLD__APPLE__
29747 ripley 327
    sigprocmask(SIG_UNBLOCK, &ss, NULL);
69881 luke 328
# endif
61472 ripley 329
#else // not APPLE
52799 ripley 330
    res = system(command);
29747 ripley 331
#endif
53147 ripley 332
#ifdef HAVE_SYS_WAIT_H
333
    if (WIFEXITED(res)) res = WEXITSTATUS(res);
52799 ripley 334
#else
53147 ripley 335
    /* assume that this is shifted if a multiple of 256 */
336
    if ((res % 256) == 0) res = res/256;
52799 ripley 337
#endif
65710 urbaneks 338
    if (res == -1) {
339
	/* this means that system() failed badly - it didn't
340
	   even get to try to run the shell */
341
	warning(_("system call failed: %s"), strerror(errno));
342
	/* R system() is documented to return 127 on failure, and a lot of
343
	   code relies on that - it will misinterpret -1 as success */
344
	res = 127;
345
    }
52799 ripley 346
    return res;
29747 ripley 347
}
348
 
41344 ripley 349
#if defined(__APPLE__)
29747 ripley 350
# include <crt_externs.h>
351
# define environ (*_NSGetEnviron())
352
#else
353
extern char ** environ;
354
#endif
355
 
43997 ripley 356
#ifdef Win32
357
/* _wenviron is declared in stdlib.h */
358
# define WIN32_LEAN_AND_MEAN 1
47999 ripley 359
# include <windows.h> /* _wgetenv etc */
43997 ripley 360
#endif
361
 
36990 ripley 362
SEXP attribute_hidden do_getenv(SEXP call, SEXP op, SEXP args, SEXP env)
29747 ripley 363
{
364
    int i, j;
365
    SEXP ans;
366
 
367
    checkArity(op, args);
368
 
369
    if (!isString(CAR(args)))
41686 ripley 370
	error(_("wrong type for argument"));
29747 ripley 371
 
40376 ripley 372
    if (!isString(CADR(args)) || LENGTH(CADR(args)) != 1)
41686 ripley 373
	error(_("wrong type for argument"));
40376 ripley 374
 
29747 ripley 375
    i = LENGTH(CAR(args));
376
    if (i == 0) {
47460 ripley 377
#ifdef Win32
43997 ripley 378
	int n = 0, N;
47999 ripley 379
	wchar_t **w;
380
	for (i = 0, w = _wenviron; *w != NULL; i++, w++)
381
	    n = max(n, wcslen(*w));
72714 murdoch 382
	N = 4*n+1;
51444 ripley 383
	char buf[N];
43997 ripley 384
	PROTECT(ans = allocVector(STRSXP, i));
47999 ripley 385
	for (i = 0, w = _wenviron; *w != NULL; i++, w++) {
72714 murdoch 386
	    wcstoutf8(buf, *w, sizeof(buf));
44986 ripley 387
	    SET_STRING_ELT(ans, i, mkCharCE(buf, CE_UTF8));
43997 ripley 388
	}
389
#else
40392 ripley 390
	char **e;
29747 ripley 391
	for (i = 0, e = environ; *e != NULL; i++, e++);
392
	PROTECT(ans = allocVector(STRSXP, i));
393
	for (i = 0, e = environ; *e != NULL; i++, e++)
394
	    SET_STRING_ELT(ans, i, mkChar(*e));
43997 ripley 395
#endif
29747 ripley 396
    } else {
397
	PROTECT(ans = allocVector(STRSXP, i));
398
	for (j = 0; j < i; j++) {
47460 ripley 399
#ifdef Win32
43997 ripley 400
	    const wchar_t *wnm = wtransChar(STRING_ELT(CAR(args), j));
47999 ripley 401
	    wchar_t *w = _wgetenv(wnm);
402
	    if (w == NULL)
43997 ripley 403
		SET_STRING_ELT(ans, j, STRING_ELT(CADR(args), 0));
404
	    else {
72714 murdoch 405
		int n = wcslen(w), N = 4*n+1; /* UTF-16 maps to <= 4 UTF-8 */
59752 ripley 406
		R_CheckStack2(N);
51398 ripley 407
		char buf[N];
72714 murdoch 408
		wcstoutf8(buf, w, sizeof(buf));
47999 ripley 409
		SET_STRING_ELT(ans, j, mkCharCE(buf, CE_UTF8));
43997 ripley 410
	    }
411
#else
412
	    char *s = getenv(translateChar(STRING_ELT(CAR(args), j)));
29747 ripley 413
	    if (s == NULL)
40376 ripley 414
		SET_STRING_ELT(ans, j, STRING_ELT(CADR(args), 0));
40692 ripley 415
	    else {
43039 luke 416
		SEXP tmp;
44986 ripley 417
		if(known_to_be_latin1) tmp = mkCharCE(s, CE_LATIN1);
418
		else if(known_to_be_utf8) tmp = mkCharCE(s, CE_UTF8);
43039 luke 419
		else tmp = mkChar(s);
40692 ripley 420
		SET_STRING_ELT(ans, j, tmp);
421
	    }
43997 ripley 422
#endif
29747 ripley 423
	}
424
    }
425
    UNPROTECT(1);
426
    return (ans);
427
}
428
 
47460 ripley 429
#ifdef Win32
43997 ripley 430
static int Rwputenv(const wchar_t *nm, const wchar_t *val)
431
{
47999 ripley 432
    wchar_t *buf;
433
    buf = (wchar_t *) malloc((wcslen(nm) + wcslen(val) + 2) * sizeof(wchar_t));
434
    if(!buf) return 1;
48007 ripley 435
    /* previously wsprintfW, which had a limit of 1024 chars */
436
    wcscpy(buf, nm); wcscat(buf, L"="); wcscat(buf, val);
47999 ripley 437
    if(_wputenv(buf)) return 1;
438
    /* no free here: storage remains in use */
439
    return 0;
43997 ripley 440
}
441
#elif !defined(HAVE_SETENV) && defined(HAVE_PUTENV)
41783 ripley 442
static int Rputenv(const char *nm, const char *val)
29747 ripley 443
{
444
    char *buf;
40376 ripley 445
    buf = (char *) malloc((strlen(nm) + strlen(val) + 2) * sizeof(char));
29747 ripley 446
    if(!buf) return 1;
40376 ripley 447
    sprintf(buf, "%s=%s", nm, val);
40392 ripley 448
    if(putenv(buf)) return 1;
29747 ripley 449
    /* no free here: storage remains in use */
450
    return 0;
451
}
452
#endif
453
 
454
 
40473 ripley 455
SEXP attribute_hidden do_setenv(SEXP call, SEXP op, SEXP args, SEXP env)
29747 ripley 456
{
40376 ripley 457
#if defined(HAVE_PUTENV) || defined(HAVE_SETENV)
29747 ripley 458
    int i, n;
40376 ripley 459
    SEXP ans, nm, vars;
460
 
461
    checkArity(op, args);
462
 
463
    if (!isString(nm = CAR(args)))
41686 ripley 464
	error(_("wrong type for argument"));
40376 ripley 465
    if (!isString(vars = CADR(args)))
41686 ripley 466
	error(_("wrong type for argument"));
40376 ripley 467
    if(LENGTH(nm) != LENGTH(vars))
41686 ripley 468
	error(_("wrong length for argument"));
40376 ripley 469
 
470
    n = LENGTH(vars);
471
    PROTECT(ans = allocVector(LGLSXP, n));
472
#ifdef HAVE_SETENV
473
    for (i = 0; i < n; i++)
40692 ripley 474
	LOGICAL(ans)[i] = setenv(translateChar(STRING_ELT(nm, i)),
475
				 translateChar(STRING_ELT(vars, i)),
40376 ripley 476
				 1) == 0;
47460 ripley 477
#elif defined(Win32)
43997 ripley 478
    for (i = 0; i < n; i++)
479
	LOGICAL(ans)[i] = Rwputenv(wtransChar(STRING_ELT(nm, i)),
480
				   wtransChar(STRING_ELT(vars, i))) == 0;
40376 ripley 481
#else
482
    for (i = 0; i < n; i++)
40692 ripley 483
	LOGICAL(ans)[i] = Rputenv(translateChar(STRING_ELT(nm, i)),
484
				  translateChar(STRING_ELT(vars, i))) == 0;
40376 ripley 485
#endif
486
    UNPROTECT(1);
487
    return ans;
488
#else
41571 ripley 489
    error(_("'Sys.setenv' is not available on this system"));
40376 ripley 490
    return R_NilValue; /* -Wall */
491
#endif
492
}
493
 
494
SEXP attribute_hidden do_unsetenv(SEXP call, SEXP op, SEXP args, SEXP env)
495
{
496
    int i, n;
29747 ripley 497
    SEXP ans, vars;
498
 
499
    checkArity(op, args);
500
 
32415 ripley 501
    if (!isString(vars = CAR(args)))
45446 ripley 502
	error(_("wrong type for argument"));
29747 ripley 503
    n = LENGTH(vars);
41571 ripley 504
 
505
#if defined(HAVE_UNSETENV) || defined(HAVE_PUTENV_UNSET) || defined(HAVE_PUTENV_UNSET2)
40391 ripley 506
#ifdef HAVE_UNSETENV
40692 ripley 507
    for (i = 0; i < n; i++) unsetenv(translateChar(STRING_ELT(vars, i)));
40391 ripley 508
#elif defined(HAVE_PUTENV_UNSET)
42427 ripley 509
    for (i = 0; i < n; i++) {
510
	char buf[1000];
511
	snprintf(buf, 1000, "%s",  translateChar(STRING_ELT(vars, i)));
512
	putenv(buf);
513
    }
40391 ripley 514
#elif defined(HAVE_PUTENV_UNSET2)
47460 ripley 515
# ifdef Win32
41571 ripley 516
    for (i = 0; i < n; i++) {
43997 ripley 517
	const wchar_t *w = wtransChar(STRING_ELT(vars, i));
51398 ripley 518
	wchar_t buf[2*wcslen(w)];
47999 ripley 519
	wcscpy(buf, w);
520
	wcscat(buf, L"=");
521
	_wputenv(buf);
43997 ripley 522
    }
523
# else
524
    for (i = 0; i < n; i++) {
40376 ripley 525
	char buf[1000];
41571 ripley 526
	snprintf(buf, 1000, "%s=", translateChar(STRING_ELT(vars, i)));
527
	putenv(buf);
29747 ripley 528
    }
43997 ripley 529
# endif
40376 ripley 530
#endif
41571 ripley 531
 
532
#elif defined(HAVE_PUTENV) || defined(HAVE_SETENV)
533
    warning(_("this system cannot unset environment variables: setting to \"\""));
534
    n = LENGTH(vars);
535
    for (i = 0; i < n; i++) {
536
#ifdef HAVE_SETENV
42780 urbaneks 537
	setenv(translateChar(STRING_ELT(vars, i)), "", 1);
41571 ripley 538
#else
539
	Rputenv(translateChar(STRING_ELT(vars, i)), "");
540
#endif
541
    }
542
 
543
#else
544
    warning(_("'Sys.unsetenv' is not available on this system"));
545
#endif
546
 
547
    PROTECT(ans = allocVector(LGLSXP, n));
40403 ripley 548
    for (i = 0; i < n; i++)
45446 ripley 549
	LOGICAL(ans)[i] = !getenv(translateChar(STRING_ELT(vars, i)));
41571 ripley 550
    UNPROTECT(1);
29747 ripley 551
    return ans;
552
}
32415 ripley 553
 
48904 ripley 554
#include <iconv.h>
32415 ripley 555
 
32642 ripley 556
#ifdef HAVE_ICONVLIST
32482 ripley 557
static unsigned int cnt;
558
 
40376 ripley 559
static int
42623 ripley 560
count_one (unsigned int namescount, const char * const *names, void *data)
32482 ripley 561
{
562
    cnt += namescount;
563
    return 0;
564
}
565
 
40376 ripley 566
static int
42623 ripley 567
write_one (unsigned int namescount, const char * const *names, void *data)
32482 ripley 568
{
569
  unsigned int i;
570
  SEXP ans = (SEXP) data;
40376 ripley 571
 
32482 ripley 572
  for (i = 0; i < namescount; i++)
573
      SET_STRING_ELT(ans, cnt++, mkChar(names[i]));
574
  return 0;
575
}
32486 ripley 576
#endif
32482 ripley 577
 
32551 ripley 578
#include "RBufferUtils.h"
579
 
49095 ripley 580
/* iconv(x, from, to, sub, mark) */
36990 ripley 581
SEXP attribute_hidden do_iconv(SEXP call, SEXP op, SEXP args, SEXP env)
32415 ripley 582
{
43034 ripley 583
    SEXP ans, x = CAR(args), si;
36081 ripley 584
    void * obj;
42623 ripley 585
    const char *inbuf;
32551 ripley 586
    char *outbuf;
41783 ripley 587
    const char *sub;
32415 ripley 588
    size_t inb, outb, res;
32551 ripley 589
    R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};
55264 ripley 590
    Rboolean isRawlist = FALSE;
40376 ripley 591
 
32415 ripley 592
    checkArity(op, args);
32482 ripley 593
    if(isNull(x)) {  /* list locales */
32642 ripley 594
#ifdef HAVE_ICONVLIST
32482 ripley 595
	cnt = 0;
596
	iconvlist(count_one, NULL);
597
	PROTECT(ans = allocVector(STRSXP, cnt));
598
	cnt = 0;
599
	iconvlist(write_one, (void *)ans);
600
#else
42623 ripley 601
	PROTECT(ans = R_NilValue);
32482 ripley 602
#endif
603
    } else {
55260 ripley 604
	int mark, toRaw;
41783 ripley 605
	const char *from, *to;
77045 ripley 606
	Rboolean isLatin1 = FALSE, isUTF8 = FALSE, fromUTF8 = FALSE;
40672 ripley 607
 
55260 ripley 608
	args = CDR(args);
609
	if(!isString(CAR(args)) || length(CAR(args)) != 1)
41686 ripley 610
	    error(_("invalid '%s' argument"), "from");
55260 ripley 611
	from = CHAR(STRING_ELT(CAR(args), 0)); /* ASCII */
612
	args = CDR(args);
613
	if(!isString(CAR(args)) || length(CAR(args)) != 1)
41686 ripley 614
	    error(_("invalid '%s' argument"), "to");
55260 ripley 615
	to = CHAR(STRING_ELT(CAR(args), 0));
616
	args = CDR(args);
617
	if(!isString(CAR(args)) || length(CAR(args)) != 1)
41686 ripley 618
	    error(_("invalid '%s' argument"), "sub");
55260 ripley 619
	if(STRING_ELT(CAR(args), 0) == NA_STRING) sub = NULL;
620
	else sub = translateChar(STRING_ELT(CAR(args), 0));
621
	args = CDR(args);
622
	mark = asLogical(CAR(args));
49095 ripley 623
	if(mark == NA_LOGICAL)
70047 ripley 624
	    error(_("invalid '%s' argument"), "mark");
55260 ripley 625
	args = CDR(args);
626
	toRaw = asLogical(CAR(args));
627
	if(toRaw == NA_LOGICAL)
70047 ripley 628
	    error(_("invalid '%s' argument"), "toRaw");
44770 ripley 629
	/* some iconv's allow "UTF8", but libiconv does not */
45514 ripley 630
	if(streql(from, "UTF8") || streql(from, "utf8") ) from = "UTF-8";
77045 ripley 631
	if(streql(from, "UTF-8") || (streql(from, "") && known_to_be_utf8))
632
	    fromUTF8 = TRUE;
64962 ripley 633
	if(streql(to, "UTF8") || streql(to, "utf8") ) to = "UTF-8";
40672 ripley 634
	/* Should we do something about marked CHARSXPs in 'from = ""'? */
635
	if(streql(to, "UTF-8")) isUTF8 = TRUE;
44655 ripley 636
	if(streql(to, "latin1") || streql(to, "ISO_8859-1")
637
	    || streql(to, "CP1252")) isLatin1 = TRUE;
40672 ripley 638
	if(streql(to, "") && known_to_be_latin1) isLatin1 = TRUE;
639
	if(streql(to, "") && known_to_be_utf8) isUTF8 = TRUE;
640
	obj = Riconv_open(to, from);
32482 ripley 641
	if(obj == (iconv_t)(-1))
45703 ripley 642
#ifdef Win32
70047 ripley 643
	    error(_("unsupported conversion from '%s' to '%s' in codepage %d"),
45703 ripley 644
		  from, to, localeCP);
645
#else
46133 ripley 646
	    error(_("unsupported conversion from '%s' to '%s'"), from, to);
45703 ripley 647
#endif
55264 ripley 648
	isRawlist = (TYPEOF(x) == VECSXP);
649
	if(isRawlist) {
650
	    if(toRaw)
651
		PROTECT(ans = duplicate(x));
652
	    else {
653
		PROTECT(ans = allocVector(STRSXP, LENGTH(x)));
69108 luke 654
		SHALLOW_DUPLICATE_ATTRIB(ans, x);
55264 ripley 655
	    }
70047 ripley 656
	} else {
73116 kalibera 657
	    if(TYPEOF(x) != STRSXP) {
658
		Riconv_close(obj);
55264 ripley 659
		error(_("'x' must be a character vector"));
73116 kalibera 660
	    }
55264 ripley 661
	    if(toRaw) {
662
		PROTECT(ans = allocVector(VECSXP, LENGTH(x)));
69108 luke 663
		SHALLOW_DUPLICATE_ATTRIB(ans, x);
70047 ripley 664
	    } else
55264 ripley 665
		PROTECT(ans = duplicate(x));
666
	}
41899 ripley 667
	R_AllocStringBuffer(0, &cbuff);  /* 0 -> default */
59052 ripley 668
	for(R_xlen_t i = 0; i < XLENGTH(x); i++) {
55264 ripley 669
	    if (isRawlist) {
670
		si = VECTOR_ELT(x, i);
671
		if (TYPEOF(si) == NILSXP) {
672
		    if (!toRaw) SET_STRING_ELT(ans, i, NA_STRING);
673
		    continue;
73116 kalibera 674
		} else if (TYPEOF(si) != RAWSXP) {
675
		    Riconv_close(obj);
69444 ripley 676
		    error(_("'x' must be a character vector or a list of NULL or raw vectors"));
73116 kalibera 677
		}
55264 ripley 678
	    } else {
679
		si = STRING_ELT(x, i);
680
		if (si == NA_STRING) {
681
		    if(!toRaw) SET_STRING_ELT(ans, i, NA_STRING);
682
		    continue;
683
		}
55260 ripley 684
	    }
32551 ripley 685
	top_of_loop:
70047 ripley 686
	    inbuf = isRawlist ? (const char *) RAW(si) : CHAR(si);
55260 ripley 687
	    inb = LENGTH(si);
32551 ripley 688
	    outbuf = cbuff.data; outb = cbuff.bufsize - 1;
32482 ripley 689
	    /* First initialize output */
36081 ripley 690
	    Riconv (obj, NULL, NULL, &outbuf, &outb);
45446 ripley 691
	next_char:
32551 ripley 692
	    /* Then convert input  */
42623 ripley 693
	    res = Riconv(obj, &inbuf , &inb, &outbuf, &outb);
32482 ripley 694
	    *outbuf = '\0';
77045 ripley 695
	    /* other possible error conditions are
696
	       incomplete and invalid multibyte chars */
32551 ripley 697
	    if(res == -1 && errno == E2BIG) {
698
		R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
699
		goto top_of_loop;
70047 ripley 700
	    } else if(res == -1 && sub &&
51812 ripley 701
		      (errno == EILSEQ || errno == EINVAL)) {
32601 ripley 702
		/* it seems this gets thrown for non-convertible input too */
77045 ripley 703
		if(fromUTF8 && streql(sub, "Unicode")) {
704
		    if(outb < 13) {
705
			R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
706
			goto top_of_loop;
707
		    }
708
		    wchar_t wc;
709
		    size_t clen = utf8toucs(&wc, inbuf);
710
		    if(clen > 0 && inb >= clen) {
711
			Rwchar_t ucs;
712
			if (IS_HIGH_SURROGATE(wc))
713
			    ucs = utf8toucs32(wc, inbuf);
714
			else
715
			    ucs = (Rwchar_t) wc;
716
			inbuf += clen; inb -= clen;
717
			if(ucs < 65536) {
718
			    // gcc 7 objects to this with unsigned int
719
			    snprintf(outbuf, 9, "<U+%04X>", (unsigned short) ucs);
720
			    outbuf += 8; outb -= 8;
721
			} else {
722
			    /* Rwchar_t is unsigned int on Windows, 
723
			       otherwise wchar_t (usually int).
724
			       In any case Unicode points <= 0x10FFFF
725
			    */
726
			    snprintf(outbuf, 13, "<U+%08X>", (unsigned int) ucs);
727
			    outbuf += 12; outb -= 12;
728
			}
729
		    }
730
		    goto next_char;
731
		}  else if(strcmp(sub, "byte") == 0) {
32601 ripley 732
		    if(outb < 5) {
733
			R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
734
			goto top_of_loop;
735
		    }
32642 ripley 736
		    snprintf(outbuf, 5, "<%02x>", (unsigned char)*inbuf);
32601 ripley 737
		    outbuf += 4; outb -= 4;
738
		} else {
77045 ripley 739
		    size_t sub_len = strlen(sub);
740
		    if(outb < sub_len) {
32601 ripley 741
			R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
742
			goto top_of_loop;
743
		    }
77045 ripley 744
		    memcpy(outbuf, sub, sub_len);
745
		    outbuf += sub_len; outb -= sub_len;
32601 ripley 746
		}
747
		inbuf++; inb--;
748
		goto next_char;
749
	    }
40376 ripley 750
 
55260 ripley 751
	    if(toRaw) {
752
		if(res != -1 && inb == 0) {
59096 ripley 753
		    size_t nout = cbuff.bufsize - 1 - outb;
55260 ripley 754
		    SEXP el = allocVector(RAWSXP, nout);
755
		    memcpy(RAW(el), cbuff.data, nout);
756
		    SET_VECTOR_ELT(ans, i, el);
757
		} /* otherwise is already NULL */
758
	    } else {
759
		if(res != -1 && inb == 0) {
760
		    cetype_t ienc = CE_NATIVE;
70047 ripley 761
 
59096 ripley 762
		    size_t nout = cbuff.bufsize - 1 - outb;
55260 ripley 763
		    if(mark) {
764
			if(isLatin1) ienc = CE_LATIN1;
765
			else if(isUTF8) ienc = CE_UTF8;
766
		    }
70047 ripley 767
		    SET_STRING_ELT(ans, i,
59097 ripley 768
				   mkCharLenCE(cbuff.data, (int) nout, ienc));
55260 ripley 769
		} else SET_STRING_ELT(ans, i, NA_STRING);
40672 ripley 770
	    }
32482 ripley 771
	}
36081 ripley 772
	Riconv_close(obj);
32551 ripley 773
	R_FreeStringBuffer(&cbuff);
32415 ripley 774
    }
775
    UNPROTECT(1);
776
    return ans;
777
}
32492 ripley 778
 
44986 ripley 779
cetype_t getCharCE(SEXP x)
43932 ripley 780
{
781
    if(TYPEOF(x) != CHARSXP)
51206 falcon 782
	error(_("'%s' must be called on a CHARSXP"), "getCharCE");
43932 ripley 783
    if(IS_UTF8(x)) return CE_UTF8;
784
    else if(IS_LATIN1(x)) return CE_LATIN1;
54747 ripley 785
    else if(IS_BYTES(x)) return CE_BYTES;
43932 ripley 786
    else return CE_NATIVE;
787
}
788
 
789
 
41781 ripley 790
void * Riconv_open (const char* tocode, const char* fromcode)
32492 ripley 791
{
44490 urbaneks 792
#if defined Win32 || __APPLE__
72214 ripley 793
// These two support "utf8"
44495 ripley 794
# ifdef Win32
52753 ripley 795
    const char *cp = "ASCII";
46512 ripley 796
#  ifndef SUPPORT_UTF8_WIN32 /* Always, at present */
797
    char to[20] = "";
798
    if (localeCP > 0) {snprintf(to, 20, "CP%d", localeCP); cp = to;}
44495 ripley 799
#  endif
800
# else /* __APPLE__ */
52753 ripley 801
    const char *cp = "UTF-8";
44490 urbaneks 802
    if (latin1locale) cp = "ISO-8859-1";
44495 ripley 803
    else if (!utf8locale) cp = locale2charset(NULL);
804
# endif
76539 kalibera 805
    if (!*tocode && !*fromcode) return iconv_open(cp, cp);
806
    if(!*tocode)  return iconv_open(cp, fromcode);
807
    else if(!*fromcode) return iconv_open(tocode, cp);
808
    else return iconv_open(tocode, fromcode);
32720 ripley 809
#else
72214 ripley 810
// "utf8" is not valid but people keep on using it
811
    const char *to = tocode, *from = fromcode;
812
    if(strcasecmp(tocode, "utf8") == 0) to = "UTF-8";
813
    if(strcasecmp(fromcode, "utf8") == 0) from = "UTF-8";
76539 kalibera 814
    return iconv_open(to, from);
32720 ripley 815
#endif
32492 ripley 816
}
817
 
54764 ripley 818
/* Should be defined in config.h, but prior to 2.13.0 was only checked
819
   if the NLS was enabled  */
42627 ripley 820
#ifndef ICONV_CONST
821
# define ICONV_CONST
822
#endif
823
 
41807 rgentlem 824
size_t Riconv (void *cd, const char **inbuf, size_t *inbytesleft,
32493 ripley 825
	       char **outbuf, size_t *outbytesleft)
32492 ripley 826
{
44161 ripley 827
    /* here libiconv has const char **, glibc has char ** for inbuf */
45446 ripley 828
    return iconv((iconv_t) cd, (ICONV_CONST char **) inbuf, inbytesleft,
43034 ripley 829
		 outbuf, outbytesleft);
32492 ripley 830
}
831
 
32493 ripley 832
int Riconv_close (void *cd)
32492 ripley 833
{
834
    return iconv_close((iconv_t) cd);
835
}
40672 ripley 836
 
66479 luke 837
typedef enum {
838
    NT_NONE        = 0, /* no translation to native encoding is needed */
839
    NT_FROM_UTF8   = 1, /* need to translate from UTF8 */
73783 kalibera 840
    NT_FROM_LATIN1 = 2, /* need to translate from latin1 */
66479 luke 841
} nttype_t;
842
 
843
/* Decides whether translation to native encoding is needed. */
844
static R_INLINE nttype_t needsTranslation(SEXP x) {
845
 
846
    if (IS_ASCII(x)) return NT_NONE;
847
    if (IS_UTF8(x)) {
70047 ripley 848
	if (utf8locale || x == NA_STRING) return NT_NONE;
849
	return NT_FROM_UTF8;
66479 luke 850
    }
851
    if (IS_LATIN1(x)) {
70047 ripley 852
	if (x == NA_STRING || latin1locale) return NT_NONE;
853
	return NT_FROM_LATIN1;
66479 luke 854
    }
855
    if (IS_BYTES(x))
70047 ripley 856
	error(_("translating strings with \"bytes\" encoding is not allowed"));
66479 luke 857
    return NT_NONE;
858
}
859
 
46133 ripley 860
static void *latin1_obj = NULL, *utf8_obj=NULL, *ucsmb_obj=NULL,
861
    *ucsutf8_obj=NULL;
40712 ripley 862
 
76974 ripley 863
/* Translates string in "ans" to native encoding returning it in string
66479 luke 864
   buffer "cbuff" */
76994 ripley 865
static int translateToNative(const char *ans, R_StringBuffer *cbuff,
866
			     nttype_t ttype, int mustWork)
76974 ripley 867
{
66479 luke 868
 
869
    if (ttype == NT_NONE)
70047 ripley 870
	error(_("internal error: no translation needed"));
66479 luke 871
 
40672 ripley 872
    void * obj;
73786 kalibera 873
    const char *inbuf, *from;
63223 ripley 874
    char *outbuf;
40672 ripley 875
    size_t inb, outb, res;
76974 ripley 876
    Rboolean failed = FALSE;
40672 ripley 877
 
66479 luke 878
    if(ttype == NT_FROM_LATIN1) {
40712 ripley 879
	if(!latin1_obj) {
73786 kalibera 880
#ifdef HAVE_ICONV_CP1252
881
	    from = "CP1252";
882
#else
883
	    from = "latin1";
884
#endif
885
	    obj = Riconv_open("", from);
40712 ripley 886
	    /* should never happen */
45703 ripley 887
	    if(obj == (void *)(-1))
888
#ifdef Win32
54753 ripley 889
		error(_("unsupported conversion from '%s' in codepage %d"),
73786 kalibera 890
		      from, localeCP);
45703 ripley 891
#else
70047 ripley 892
		error(_("unsupported conversion from '%s' to '%s'"),
73786 kalibera 893
		      from, "");
45703 ripley 894
#endif
40712 ripley 895
	    latin1_obj = obj;
896
	}
897
	obj = latin1_obj;
898
    } else {
899
	if(!utf8_obj) {
900
	    obj = Riconv_open("", "UTF-8");
901
	    /* should never happen */
70047 ripley 902
	    if(obj == (void *)(-1))
45703 ripley 903
#ifdef Win32
54753 ripley 904
		error(_("unsupported conversion from '%s' in codepage %d"),
73132 kalibera 905
		      "UTF-8", localeCP);
45703 ripley 906
#else
70047 ripley 907
		error(_("unsupported conversion from '%s' to '%s'"),
73132 kalibera 908
		      "UTF-8", "");
45703 ripley 909
#endif
40712 ripley 910
	    utf8_obj = obj;
911
	}
45446 ripley 912
	obj = utf8_obj;
40712 ripley 913
    }
44054 ripley 914
 
66479 luke 915
    R_AllocStringBuffer(0, cbuff);
40672 ripley 916
top_of_loop:
45412 ripley 917
    inbuf = ans; inb = strlen(inbuf);
66479 luke 918
    outbuf = cbuff->data; outb = cbuff->bufsize - 1;
40672 ripley 919
    /* First initialize output */
920
    Riconv (obj, NULL, NULL, &outbuf, &outb);
921
next_char:
922
    /* Then convert input  */
41884 ripley 923
    res = Riconv(obj, &inbuf , &inb, &outbuf, &outb);
40672 ripley 924
    if(res == -1 && errno == E2BIG) {
66479 luke 925
	R_AllocStringBuffer(2*cbuff->bufsize, cbuff);
40672 ripley 926
	goto top_of_loop;
51812 ripley 927
    } else if(res == -1 && (errno == EILSEQ || errno == EINVAL)) {
44034 ripley 928
	if(outb < 13) {
66479 luke 929
	    R_AllocStringBuffer(2*cbuff->bufsize, cbuff);
40672 ripley 930
	    goto top_of_loop;
931
	}
76974 ripley 932
	failed = TRUE;
66479 luke 933
	if (ttype == NT_FROM_UTF8) {
44034 ripley 934
	    /* if starting in UTF-8, use \uxxxx */
935
	    /* This must be the first byte */
936
	    wchar_t wc;
77045 ripley 937
	    size_t clen = utf8toucs(&wc, inbuf);
44100 ripley 938
	    if(clen > 0 && inb >= clen) {
77045 ripley 939
		Rwchar_t ucs;
72707 murdoch 940
	    	if (IS_HIGH_SURROGATE(wc))
941
	    	    ucs = utf8toucs32(wc, inbuf);
942
	    	else
943
	    	    ucs = (Rwchar_t) wc;
44100 ripley 944
		inbuf += clen; inb -= clen;
72707 murdoch 945
		if(ucs < 65536) {
71586 ripley 946
		// gcc 7 objects to this with unsigned int
72707 murdoch 947
		    snprintf(outbuf, 9, "<U+%04X>", (unsigned short) ucs);
44100 ripley 948
		    outbuf += 8; outb -= 8;
949
		} else {
73787 ripley 950
		    // Rwchar_t is usually unsigned int, but wchar_t need not be
951
		    snprintf(outbuf, 13, "<U+%08X>", (unsigned int) ucs);
45446 ripley 952
		    outbuf += 12; outb -= 12;
44100 ripley 953
		}
44034 ripley 954
	    } else {
44100 ripley 955
		snprintf(outbuf, 5, "<%02x>", (unsigned char)*inbuf);
956
		outbuf += 4; outb -= 4;
957
		inbuf++; inb--;
44034 ripley 958
	    }
76974 ripley 959
	} else { // not from UTF-8
44034 ripley 960
	    snprintf(outbuf, 5, "<%02x>", (unsigned char)*inbuf);
961
	    outbuf += 4; outb -= 4;
962
	    inbuf++; inb--;
963
	}
40672 ripley 964
	goto next_char;
965
    }
966
    *outbuf = '\0';
76981 ripley 967
    if (mustWork && failed) {
76994 ripley 968
	if (mustWork == 2) {
969
	    warning(_("unable to translate '%s' to native encoding"), 
76981 ripley 970
		    cbuff->data);
76994 ripley 971
	    return 1;
972
	} else
76981 ripley 973
	    error(_("unable to translate '%s' to native encoding"),
974
		  cbuff->data);
975
    }
76994 ripley 976
    return 0;
66479 luke 977
}
978
 
979
 
980
/* This may return a R_alloc-ed result, so the caller has to manage the
981
   R_alloc stack */
982
const char *translateChar(SEXP x)
983
{
984
    if(TYPEOF(x) != CHARSXP)
73709 maechler 985
	error(_("'%s' must be called on a CHARSXP, but got '%s'"),
986
	      "translateChar", type2char(TYPEOF(x)));
66479 luke 987
    nttype_t t = needsTranslation(x);
988
    const char *ans = CHAR(x);
989
    if (t == NT_NONE) return ans;
990
 
991
    R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};
76974 ripley 992
    translateToNative(ans, &cbuff, t, 0);
66479 luke 993
 
994
    size_t res = strlen(cbuff.data) + 1;
63223 ripley 995
    char *p = R_alloc(res, 1);
40672 ripley 996
    memcpy(p, cbuff.data, res);
997
    R_FreeStringBuffer(&cbuff);
998
    return p;
999
}
43932 ripley 1000
 
77049 ripley 1001
/* Variant which must work, used for file paths, including devices */
76974 ripley 1002
const char *translateCharFP(SEXP x)
1003
{
1004
    if(TYPEOF(x) != CHARSXP)
1005
	error(_("'%s' must be called on a CHARSXP, but got '%s'"),
1006
	      "translateChar", type2char(TYPEOF(x)));
1007
    nttype_t t = needsTranslation(x);
1008
    const char *ans = CHAR(x);
1009
    if (t == NT_NONE) return ans;
1010
 
1011
    R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};
1012
    translateToNative(ans, &cbuff, t, 1);
1013
 
1014
    size_t res = strlen(cbuff.data) + 1;
1015
    char *p = R_alloc(res, 1);
1016
    memcpy(p, cbuff.data, res);
1017
    R_FreeStringBuffer(&cbuff);
1018
    return p;
1019
}
1020
 
76994 ripley 1021
/* Variant which may return NULL, used for file paths */
1022
attribute_hidden
1023
const char *translateCharFP2(SEXP x)
1024
{
1025
    if(TYPEOF(x) != CHARSXP)
1026
	error(_("'%s' must be called on a CHARSXP, but got '%s'"),
1027
	      "translateChar", type2char(TYPEOF(x)));
1028
    nttype_t t = needsTranslation(x);
1029
    const char *ans = CHAR(x);
1030
    if (t == NT_NONE) return ans;
1031
 
1032
    R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};
1033
    if (translateToNative(ans, &cbuff, t, 2)) return NULL;
1034
 
1035
    size_t res = strlen(cbuff.data) + 1;
1036
    char *p = R_alloc(res, 1);
1037
    memcpy(p, cbuff.data, res);
1038
    R_FreeStringBuffer(&cbuff);
1039
    return p;
1040
}
1041
 
63223 ripley 1042
SEXP installTrChar(SEXP x)
1043
{
1044
    if(TYPEOF(x) != CHARSXP)
73709 maechler 1045
	error(_("'%s' must be called on a CHARSXP, but got '%s'"),
1046
	      "installTrChar", type2char(TYPEOF(x)));
66479 luke 1047
    nttype_t t = needsTranslation(x);
74162 kalibera 1048
    if (t == NT_NONE) return installNoTrChar(x);
63223 ripley 1049
 
66479 luke 1050
    R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};
76980 ripley 1051
    // For back-compatibility this allows installing
76981 ripley 1052
    // symbols with escapes, with a warning.
1053
    translateToNative(CHAR(x), &cbuff, t, 2);
63223 ripley 1054
 
1055
    SEXP Sans = install(cbuff.data);
1056
    R_FreeStringBuffer(&cbuff);
1057
    return Sans;
1058
}
1059
 
76984 ripley 1060
/* Translates as from R 3.6.0.
77234 ripley 1061
   As from R 4.0.0 unused in newly installed code as installChar is
76984 ripley 1062
   remapped to Rf_installTrChar. 
1063
 */
1064
SEXP Rf_installChar(SEXP x)
74162 kalibera 1065
{
76984 ripley 1066
    return Rf_installTrChar(x);
74162 kalibera 1067
}
1068
 
63181 ripley 1069
/* This may return a R_alloc-ed result, so the caller has to manage the
76974 ripley 1070
   R_alloc stack.
1071
 
1072
   Use for writeLines/Bin/Char, the first only with useBytes = TRUE.
1073
 
1074
*/
54747 ripley 1075
const char *translateChar0(SEXP x)
1076
{
1077
    if(TYPEOF(x) != CHARSXP)
1078
	error(_("'%s' must be called on a CHARSXP"), "translateChar0");
1079
    if(IS_BYTES(x)) return CHAR(x);
1080
    return translateChar(x);
1081
}
1082
 
63181 ripley 1083
/* This may return a R_alloc-ed result, so the caller has to manage the
1084
   R_alloc stack */
44054 ripley 1085
const char *translateCharUTF8(SEXP x)
1086
{
1087
    void *obj;
1088
    const char *inbuf, *ans = CHAR(x);
73786 kalibera 1089
    char *outbuf, *p, *from = "";
44054 ripley 1090
    size_t inb, outb, res;
1091
    R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};
1092
 
1093
    if(TYPEOF(x) != CHARSXP)
73709 maechler 1094
	error(_("'%s' must be called on a CHARSXP, but got '%s'"),
1095
	      "translateCharUTF8", type2char(TYPEOF(x)));
44054 ripley 1096
    if(x == NA_STRING) return ans;
54747 ripley 1097
    if(IS_UTF8(x)) return ans;
58404 urbaneks 1098
    if(IS_ASCII(x)) return ans;
54747 ripley 1099
    if(IS_BYTES(x))
54753 ripley 1100
	error(_("translating strings with \"bytes\" encoding is not allowed"));
44054 ripley 1101
 
73786 kalibera 1102
    if (IS_LATIN1(x))
1103
#ifdef HAVE_ICONV_CP1252
1104
	from = "CP1252";
1105
#else
1106
	from = "latin1";
1107
#endif
1108
    obj = Riconv_open("UTF-8", from);
70047 ripley 1109
    if(obj == (void *)(-1))
45703 ripley 1110
#ifdef Win32
54753 ripley 1111
	error(_("unsupported conversion from '%s' in codepage %d"),
73786 kalibera 1112
	      from, localeCP);
45703 ripley 1113
#else
73132 kalibera 1114
	error(_("unsupported conversion from '%s' to '%s'"),
73786 kalibera 1115
	      from, "UTF-8");
45703 ripley 1116
#endif
44054 ripley 1117
    R_AllocStringBuffer(0, &cbuff);
1118
top_of_loop:
1119
    inbuf = ans; inb = strlen(inbuf);
1120
    outbuf = cbuff.data; outb = cbuff.bufsize - 1;
1121
    /* First initialize output */
1122
    Riconv (obj, NULL, NULL, &outbuf, &outb);
1123
next_char:
1124
    /* Then convert input  */
1125
    res = Riconv(obj, &inbuf , &inb, &outbuf, &outb);
1126
    if(res == -1 && errno == E2BIG) {
1127
	R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
1128
	goto top_of_loop;
51812 ripley 1129
    } else if(res == -1 && (errno == EILSEQ || errno == EINVAL)) {
44054 ripley 1130
	if(outb < 5) {
1131
	    R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
1132
	    goto top_of_loop;
1133
	}
1134
	snprintf(outbuf, 5, "<%02x>", (unsigned char)*inbuf);
1135
	outbuf += 4; outb -= 4;
1136
	inbuf++; inb--;
1137
	goto next_char;
1138
    }
1139
    *outbuf = '\0';
1140
    Riconv_close(obj);
1141
    res = strlen(cbuff.data) + 1;
1142
    p = R_alloc(res, 1);
1143
    memcpy(p, cbuff.data, res);
1144
    R_FreeStringBuffer(&cbuff);
1145
    return p;
1146
}
1147
 
76974 ripley 1148
/* Variant which does not return escaped string */
76986 ripley 1149
attribute_hidden
76974 ripley 1150
const char *trCharUTF8(SEXP x)
1151
{
1152
    void *obj;
1153
    const char *inbuf, *ans = CHAR(x);
1154
    char *outbuf, *p, *from = "";
1155
    size_t inb, outb, res;
1156
    R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};
1157
    Rboolean failed = FALSE;
49631 ripley 1158
 
76974 ripley 1159
    if(TYPEOF(x) != CHARSXP)
1160
	error(_("'%s' must be called on a CHARSXP, but got '%s'"),
1161
	      "translateCharUTF8", type2char(TYPEOF(x)));
1162
    if(x == NA_STRING) return ans;
1163
    if(IS_UTF8(x)) return ans;
1164
    if(IS_ASCII(x)) return ans;
1165
    if(IS_BYTES(x))
1166
	error(_("translating strings with \"bytes\" encoding is not allowed"));
1167
 
1168
    if (IS_LATIN1(x))
1169
#ifdef HAVE_ICONV_CP1252
1170
	from = "CP1252";
1171
#else
1172
	from = "latin1";
1173
#endif
1174
    obj = Riconv_open("UTF-8", from);
1175
    if(obj == (void *)(-1))
43997 ripley 1176
#ifdef Win32
76974 ripley 1177
	error(_("unsupported conversion from '%s' in codepage %d"),
1178
	      from, localeCP);
1179
#else
1180
	error(_("unsupported conversion from '%s' to '%s'"),
1181
	      from, "UTF-8");
1182
#endif
1183
    R_AllocStringBuffer(0, &cbuff);
1184
top_of_loop:
1185
    inbuf = ans; inb = strlen(inbuf);
1186
    outbuf = cbuff.data; outb = cbuff.bufsize - 1;
1187
    /* First initialize output */
1188
    Riconv (obj, NULL, NULL, &outbuf, &outb);
1189
next_char:
1190
    /* Then convert input  */
1191
    res = Riconv(obj, &inbuf , &inb, &outbuf, &outb);
1192
    if(res == -1 && errno == E2BIG) {
1193
	R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
1194
	goto top_of_loop;
1195
    } else if(res == -1 && (errno == EILSEQ || errno == EINVAL)) {
1196
	if(outb < 5) {
1197
	    R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
1198
	    goto top_of_loop;
1199
	}
1200
	failed = TRUE;
1201
	snprintf(outbuf, 5, "<%02x>", (unsigned char)*inbuf);
1202
	outbuf += 4; outb -= 4;
1203
	inbuf++; inb--;
1204
	goto next_char;
1205
    }
1206
    *outbuf = '\0';
1207
    Riconv_close(obj);
1208
    if (failed)
1209
	error(_("unable to translate '%s' to UTF-8"),  cbuff.data);
1210
    res = strlen(cbuff.data) + 1;
1211
    p = R_alloc(res, 1);
1212
    memcpy(p, cbuff.data, res);
1213
    R_FreeStringBuffer(&cbuff);
1214
    return p;
1215
}
1216
 
1217
 
1218
#ifdef Win32
49631 ripley 1219
static const char TO_WCHAR[] = "UCS-2LE";
1220
#else
1221
# ifdef WORDS_BIGENDIAN
1222
static const char TO_WCHAR[] = "UCS-4BE";
1223
# else
1224
static const char TO_WCHAR[] = "UCS-4LE";
1225
# endif
1226
#endif
1227
 
43997 ripley 1228
static void *latin1_wobj = NULL, *utf8_wobj=NULL;
1229
 
49631 ripley 1230
/* Translate from current encoding to wchar_t = UCS-2/4
50302 ripley 1231
   NB: that wchar_t is UCS-4 is an assumption, but not easy to avoid.
1232
*/
49631 ripley 1233
 
63181 ripley 1234
/* This may return a R_alloc-ed result, so the caller has to manage the
1235
   R_alloc stack */
50302 ripley 1236
attribute_hidden /* but not hidden on Windows, where it was used in tcltk.c */
43997 ripley 1237
const wchar_t *wtransChar(SEXP x)
1238
{
1239
    void * obj;
73786 kalibera 1240
    const char *inbuf, *ans = CHAR(x), *from;
43997 ripley 1241
    char *outbuf;
1242
    wchar_t *p;
1243
    size_t inb, outb, res, top;
1244
    Rboolean knownEnc = FALSE;
1245
    R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};
1246
 
1247
    if(TYPEOF(x) != CHARSXP)
1248
	error(_("'%s' must be called on a CHARSXP"), "wtransChar");
1249
 
54747 ripley 1250
    if(IS_BYTES(x))
54753 ripley 1251
	error(_("translating strings with \"bytes\" encoding is not allowed"));
54747 ripley 1252
 
43997 ripley 1253
    if(IS_LATIN1(x)) {
1254
	if(!latin1_wobj) {
73786 kalibera 1255
#ifdef HAVE_ICONV_CP1252
1256
	    from = "CP1252";
1257
#else
1258
	    from = "latin1";
1259
#endif
1260
	    obj = Riconv_open(TO_WCHAR, from);
45703 ripley 1261
	    if(obj == (void *)(-1))
46133 ripley 1262
		error(_("unsupported conversion from '%s' to '%s'"),
73786 kalibera 1263
		      from, TO_WCHAR);
43997 ripley 1264
	    latin1_wobj = obj;
1265
	} else
1266
	    obj = latin1_wobj;
1267
	knownEnc = TRUE;
1268
    } else if(IS_UTF8(x)) {
44161 ripley 1269
	if(!utf8_wobj) {
49631 ripley 1270
	    obj = Riconv_open(TO_WCHAR, "UTF-8");
70047 ripley 1271
	    if(obj == (void *)(-1))
46133 ripley 1272
		error(_("unsupported conversion from '%s' to '%s'"),
73132 kalibera 1273
		      "UTF-8", TO_WCHAR);
43997 ripley 1274
	    utf8_wobj = obj;
1275
	} else
1276
	    obj = utf8_wobj;
1277
	knownEnc = TRUE;
1278
    } else {
49631 ripley 1279
	obj = Riconv_open(TO_WCHAR, "");
45703 ripley 1280
	if(obj == (void *)(-1))
49631 ripley 1281
#ifdef Win32
54753 ripley 1282
	    error(_("unsupported conversion to '%s' from codepage %d"),
49631 ripley 1283
		  TO_WCHAR, localeCP);
1284
#else
1285
	    error(_("unsupported conversion from '%s' to '%s'"), "", TO_WCHAR);
1286
#endif
43997 ripley 1287
    }
1288
 
1289
    R_AllocStringBuffer(0, &cbuff);
1290
top_of_loop:
1291
    inbuf = ans; inb = strlen(inbuf);
1292
    outbuf = cbuff.data; top = outb = cbuff.bufsize - 1;
1293
    /* First initialize output */
1294
    Riconv (obj, NULL, NULL, &outbuf, &outb);
49635 ripley 1295
next_char:
1296
    /* Then convert input  */
43997 ripley 1297
    res = Riconv(obj, &inbuf , &inb, &outbuf, &outb);
1298
    if(res == -1 && errno == E2BIG) {
1299
	R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
1300
	goto top_of_loop;
51812 ripley 1301
    } else if(res == -1 && (errno == EILSEQ || errno == EINVAL)) {
49635 ripley 1302
	if(outb < 5) {
1303
	    R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
1304
	    goto top_of_loop;
1305
	}
1306
	snprintf(outbuf, 5, "<%02x>", (unsigned char)*inbuf);
1307
	outbuf += 4; outb -= 4;
1308
	inbuf++; inb--;
1309
	goto next_char;
1310
	/* if(!knownEnc) Riconv_close(obj);
1311
	   error(_("invalid input in wtransChar")); */
43997 ripley 1312
    }
1313
    if(!knownEnc) Riconv_close(obj);
1314
    res = (top - outb);
49631 ripley 1315
    /* terminator is 2 or 4 null bytes */
1316
    p = (wchar_t *) R_alloc(res+4, 1);
1317
    memset(p, 0, res+4);
43997 ripley 1318
    memcpy(p, cbuff.data, res);
1319
    R_FreeStringBuffer(&cbuff);
1320
    return p;
1321
}
1322
 
49631 ripley 1323
 
66104 ripley 1324
#include <R_ext/GraphicsEngine.h>
63181 ripley 1325
/* This may return a R_alloc-ed result, so the caller has to manage the
1326
   R_alloc stack */
44986 ripley 1327
const char *reEnc(const char *x, cetype_t ce_in, cetype_t ce_out, int subst)
43932 ripley 1328
{
1329
    void * obj;
1330
    const char *inbuf;
1331
    char *outbuf, *p;
43997 ripley 1332
    size_t inb, outb, res, top;
43932 ripley 1333
    char *tocode = NULL, *fromcode = NULL;
44329 ripley 1334
#ifdef Win32
1335
    char buf[20];
1336
#endif
43932 ripley 1337
    R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};
1338
 
44325 ripley 1339
    /* We can only encode from Symbol to UTF-8 */
45446 ripley 1340
    if(ce_in == ce_out || ce_out == CE_SYMBOL ||
43932 ripley 1341
       ce_in == CE_ANY || ce_out == CE_ANY) return x;
44326 ripley 1342
    if(ce_in == CE_SYMBOL) {
44330 ripley 1343
	if(ce_out == CE_UTF8) {
59096 ripley 1344
	    size_t nc = 3*strlen(x)+1; /* all in BMP */
44330 ripley 1345
	    p = R_alloc(nc, 1);
45446 ripley 1346
	    Rf_AdobeSymbol2utf8(p, x, nc);
44330 ripley 1347
	    return p;
1348
	} else return x;
44326 ripley 1349
    }
43932 ripley 1350
    if(utf8locale && ce_in == CE_NATIVE && ce_out == CE_UTF8) return x;
1351
    if(utf8locale && ce_out == CE_NATIVE && ce_in == CE_UTF8) return x;
1352
    if(latin1locale && ce_in == CE_NATIVE && ce_out == CE_LATIN1) return x;
1353
    if(latin1locale && ce_out == CE_NATIVE && ce_in == CE_LATIN1) return x;
1354
 
44094 ripley 1355
    if(strIsASCII(x)) return x;
45446 ripley 1356
 
43932 ripley 1357
    switch(ce_in) {
44329 ripley 1358
#ifdef Win32
45446 ripley 1359
    case CE_NATIVE:
44329 ripley 1360
	{
44655 ripley 1361
	    /* Looks like CP1252 is treated as Latin-1 by iconv */
62580 ripley 1362
	    snprintf(buf, 20, "CP%d", localeCP);
45446 ripley 1363
	    fromcode = buf;
44329 ripley 1364
	    break;
1365
	}
44655 ripley 1366
    case CE_LATIN1: fromcode = "CP1252"; break;
44329 ripley 1367
#else
43932 ripley 1368
    case CE_NATIVE: fromcode = ""; break;
73783 kalibera 1369
    case CE_LATIN1: fromcode = "latin1"; break; /* FIXME: allow CP1252? */
44329 ripley 1370
#endif
43932 ripley 1371
    case CE_UTF8:   fromcode = "UTF-8"; break;
1372
    default: return x;
1373
    }
1374
 
1375
    switch(ce_out) {
46506 ripley 1376
 #ifdef Win32
1377
    case CE_NATIVE:
1378
	{
1379
	    /* avoid possible misidentification of CP1250 as LATIN-2 */
62580 ripley 1380
	    snprintf(buf, 20, "CP%d", localeCP);
46506 ripley 1381
	    tocode = buf;
1382
	    break;
1383
	}
1384
#else
43932 ripley 1385
    case CE_NATIVE: tocode = ""; break;
46506 ripley 1386
#endif
43932 ripley 1387
    case CE_LATIN1: tocode = "latin1"; break;
1388
    case CE_UTF8:   tocode = "UTF-8"; break;
1389
    default: return x;
1390
    }
45446 ripley 1391
 
43932 ripley 1392
    obj = Riconv_open(tocode, fromcode);
1393
    if(obj == (void *)(-1)) return x;
1394
    R_AllocStringBuffer(0, &cbuff);
1395
top_of_loop:
1396
    inbuf = x; inb = strlen(inbuf);
43997 ripley 1397
    outbuf = cbuff.data; top = outb = cbuff.bufsize - 1;
43932 ripley 1398
    /* First initialize output */
1399
    Riconv (obj, NULL, NULL, &outbuf, &outb);
1400
next_char:
1401
    /* Then convert input  */
1402
    res = Riconv(obj, &inbuf , &inb, &outbuf, &outb);
1403
    if(res == -1 && errno == E2BIG) {
1404
	R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
1405
	goto top_of_loop;
51812 ripley 1406
    } else if(res == -1 && (errno == EILSEQ || errno == EINVAL)) {
43932 ripley 1407
	switch(subst) {
1408
	case 1: /* substitute hex */
1409
	    if(outb < 5) {
1410
		R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
1411
		goto top_of_loop;
1412
	    }
1413
	    snprintf(outbuf, 5, "<%02x>", (unsigned char)*inbuf);
1414
	    outbuf += 4; outb -= 4;
1415
	    inbuf++; inb--;
45446 ripley 1416
	    goto next_char;
43932 ripley 1417
	    break;
1418
	case 2: /* substitute . */
1419
	    if(outb < 1) {
1420
		R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
1421
		goto top_of_loop;
1422
	    }
43969 ripley 1423
	    *outbuf++ = '.'; inbuf++; outb--; inb--;
45446 ripley 1424
	    goto next_char;
43932 ripley 1425
	    break;
46843 ripley 1426
	case 3: /* substitute ? */
1427
	    if(outb < 1) {
1428
		R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
1429
		goto top_of_loop;
1430
	    }
1431
	    *outbuf++ = '?'; inbuf++; outb--; inb--;
1432
	    goto next_char;
1433
	    break;
43932 ripley 1434
	default: /* skip byte */
1435
	    inbuf++; inb--;
45446 ripley 1436
	    goto next_char;
43932 ripley 1437
	}
1438
    }
1439
    Riconv_close(obj);
1440
    *outbuf = '\0';
43997 ripley 1441
    res = (top-outb)+1; /* strlen(cbuff.data) + 1; */
43932 ripley 1442
    p = R_alloc(res, 1);
1443
    memcpy(p, cbuff.data, res);
1444
    R_FreeStringBuffer(&cbuff);
1445
    return p;
1446
}
43953 ripley 1447
 
63218 ripley 1448
#ifdef Win32
1449
/* A version avoiding R_alloc for use in the Rgui editor */
1450
void reEnc2(const char *x, char *y, int ny,
1451
	    cetype_t ce_in, cetype_t ce_out, int subst)
1452
{
1453
    void * obj;
1454
    const char *inbuf;
63219 ripley 1455
    char *outbuf;
63218 ripley 1456
    size_t inb, outb, res, top;
1457
    char *tocode = NULL, *fromcode = NULL;
1458
    char buf[20];
1459
    R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};
1460
 
63219 ripley 1461
    strncpy(y, x, ny);
66671 murdoch 1462
    y[ny - 1] = '\0';
63218 ripley 1463
 
63219 ripley 1464
    if(ce_in == ce_out || ce_in == CE_ANY || ce_out == CE_ANY) return;
1465
    if(utf8locale && ce_in == CE_NATIVE && ce_out == CE_UTF8) return;
1466
    if(utf8locale && ce_out == CE_NATIVE && ce_in == CE_UTF8) return;
1467
    if(latin1locale && ce_in == CE_NATIVE && ce_out == CE_LATIN1) return;
1468
    if(latin1locale && ce_out == CE_NATIVE && ce_in == CE_LATIN1) return;
63218 ripley 1469
 
63219 ripley 1470
    if(strIsASCII(x)) return;
1471
 
63218 ripley 1472
    switch(ce_in) {
1473
    case CE_NATIVE:
1474
	{
1475
	    /* Looks like CP1252 is treated as Latin-1 by iconv */
1476
	    snprintf(buf, 20, "CP%d", localeCP);
1477
	    fromcode = buf;
1478
	    break;
1479
	}
1480
    case CE_LATIN1: fromcode = "CP1252"; break;
1481
    case CE_UTF8:   fromcode = "UTF-8"; break;
63219 ripley 1482
    default: return;
63218 ripley 1483
    }
1484
 
1485
    switch(ce_out) {
1486
    case CE_NATIVE:
1487
	{
1488
	    /* avoid possible misidentification of CP1250 as LATIN-2 */
1489
	    snprintf(buf, 20, "CP%d", localeCP);
1490
	    tocode = buf;
1491
	    break;
1492
	}
1493
    case CE_LATIN1: tocode = "latin1"; break;
1494
    case CE_UTF8:   tocode = "UTF-8"; break;
63219 ripley 1495
    default: return;
63218 ripley 1496
    }
1497
 
1498
    obj = Riconv_open(tocode, fromcode);
63219 ripley 1499
    if(obj == (void *)(-1)) return;
63218 ripley 1500
    R_AllocStringBuffer(0, &cbuff);
1501
top_of_loop:
1502
    inbuf = x; inb = strlen(inbuf);
1503
    outbuf = cbuff.data; top = outb = cbuff.bufsize - 1;
1504
    /* First initialize output */
1505
    Riconv (obj, NULL, NULL, &outbuf, &outb);
1506
next_char:
1507
    /* Then convert input  */
1508
    res = Riconv(obj, &inbuf , &inb, &outbuf, &outb);
1509
    if(res == -1 && errno == E2BIG) {
1510
	R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
1511
	goto top_of_loop;
1512
    } else if(res == -1 && (errno == EILSEQ || errno == EINVAL)) {
1513
	switch(subst) {
1514
	case 1: /* substitute hex */
1515
	    if(outb < 5) {
1516
		R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
1517
		goto top_of_loop;
1518
	    }
1519
	    snprintf(outbuf, 5, "<%02x>", (unsigned char)*inbuf);
1520
	    outbuf += 4; outb -= 4;
1521
	    inbuf++; inb--;
1522
	    goto next_char;
1523
	    break;
1524
	case 2: /* substitute . */
1525
	    if(outb < 1) {
1526
		R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
1527
		goto top_of_loop;
1528
	    }
1529
	    *outbuf++ = '.'; inbuf++; outb--; inb--;
1530
	    goto next_char;
1531
	    break;
1532
	case 3: /* substitute ? */
1533
	    if(outb < 1) {
1534
		R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);
1535
		goto top_of_loop;
1536
	    }
1537
	    *outbuf++ = '?'; inbuf++; outb--; inb--;
1538
	    goto next_char;
1539
	    break;
1540
	default: /* skip byte */
1541
	    inbuf++; inb--;
1542
	    goto next_char;
1543
	}
1544
    }
1545
    Riconv_close(obj);
1546
    *outbuf = '\0';
1547
    res = (top-outb)+1; /* strlen(cbuff.data) + 1; */
1548
    if (res > ny) error("converted string too long for buffer");
63219 ripley 1549
    memcpy(y, cbuff.data, res);
63218 ripley 1550
    R_FreeStringBuffer(&cbuff);
1551
}
1552
#endif
1553
 
44161 ripley 1554
void attribute_hidden
1555
invalidate_cached_recodings(void)
1556
{
73116 kalibera 1557
    if (latin1_obj) {
1558
	Riconv_close(latin1_obj);
1559
	latin1_obj = NULL;
1560
    }
1561
    if (utf8_obj) {
1562
	Riconv_close(utf8_obj);
1563
	utf8_obj = NULL;
1564
    }
1565
    if (ucsmb_obj) {
1566
	Riconv_close(ucsmb_obj);
1567
	ucsmb_obj = NULL;
1568
    }
44161 ripley 1569
#ifdef Win32
73116 kalibera 1570
    if (latin1_wobj) {
1571
	Riconv_close(latin1_wobj);
1572
	latin1_wobj = NULL;
1573
    }
1574
    if (utf8_wobj) {
1575
	Riconv_close(utf8_wobj);
1576
	utf8_wobj = NULL;
1577
    }
45446 ripley 1578
#endif
44161 ripley 1579
}
1580
 
1581
 
64516 ripley 1582
/* in C11 these could use char32_t */
43953 ripley 1583
#ifdef WORDS_BIGENDIAN
1584
static const char UNICODE[] = "UCS-4BE";
32492 ripley 1585
#else
43953 ripley 1586
static const char UNICODE[] = "UCS-4LE";
1587
#endif
1588
 
44034 ripley 1589
/* used in gram.c and devX11.c */
44014 ripley 1590
size_t ucstomb(char *s, const unsigned int wc)
43953 ripley 1591
{
44178 ripley 1592
    char     buf[MB_CUR_MAX+1];
43953 ripley 1593
    void    *cd = NULL ;
1594
    unsigned int  wcs[2];
1595
    const char *inbuf = (const char *) wcs;
1596
    size_t   inbytesleft = sizeof(unsigned int); /* better be 4 */
1597
    char    *outbuf = buf;
1598
    size_t   outbytesleft = sizeof(buf);
1599
    size_t   status;
45446 ripley 1600
 
43953 ripley 1601
    if(wc == 0) {*s = '\0'; return 1;}
45446 ripley 1602
 
43953 ripley 1603
    memset(buf, 0, sizeof(buf));
1604
    memset(wcs, 0, sizeof(wcs));
1605
    wcs[0] = wc;
1606
 
1607
    if(ucsmb_obj == NULL) {
1608
	if((void *)(-1) == (cd = Riconv_open("", UNICODE))) {
1609
#ifndef  Win32
1610
	    char tocode[128];
1611
	    /* locale set fuzzy case */
74969 ripley 1612
	    strncpy(tocode, locale2charset(NULL), sizeof(tocode) - 1);
70047 ripley 1613
	    tocode[sizeof(tocode) - 1] = '\0';
43953 ripley 1614
	    if((void *)(-1) == (cd = Riconv_open(tocode, UNICODE)))
45446 ripley 1615
		return (size_t)(-1);
43953 ripley 1616
#else
1617
	    return (size_t)(-1);
1618
#endif
1619
	}
1620
	ucsmb_obj = cd;
1621
    }
45446 ripley 1622
 
43953 ripley 1623
    status = Riconv(ucsmb_obj, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
1624
 
1625
    if (status == (size_t) -1) {
45446 ripley 1626
	switch(errno){
1627
	case EINVAL:
1628
	    return (size_t) -2;
1629
	case EILSEQ:
1630
	    return (size_t) -1;
1631
	case E2BIG:
1632
	    break;
1633
	default:
1634
	    errno = EILSEQ;
1635
	    return (size_t) -1;
1636
	}
43953 ripley 1637
    }
44178 ripley 1638
    buf[MB_CUR_MAX] = '\0'; /* safety measure */
44170 ripley 1639
    strcpy(s, buf);
43953 ripley 1640
    return strlen(buf);
1641
}
1642
 
44034 ripley 1643
/* used in plot.c for non-UTF-8 MBCS */
43953 ripley 1644
size_t attribute_hidden
1645
mbtoucs(unsigned int *wc, const char *s, size_t n)
1646
{
1647
    unsigned int  wcs[2];
1648
    char     buf[16];
1649
    void    *cd;
1650
    const char *inbuf = s;
1651
    size_t   inbytesleft = strlen(s);
1652
    char    *outbuf = (char *) wcs;
1653
    size_t   outbytesleft = sizeof(buf);
1654
    size_t   status;
45446 ripley 1655
 
43953 ripley 1656
    if(s[0] == 0) {*wc = 0; return 1;}
45446 ripley 1657
 
43978 ripley 1658
    if((void *)(-1) == (cd = Riconv_open(UNICODE, ""))) return (size_t)(-1);
43953 ripley 1659
    status = Riconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
1660
 
43980 ripley 1661
    if (status == (size_t) -1) {
45446 ripley 1662
	switch(errno){
1663
	case EINVAL:
72952 murdoch 1664
	    Riconv_close(cd);
45446 ripley 1665
	    return (size_t) -2;
1666
	case EILSEQ:
72952 murdoch 1667
	    Riconv_close(cd);
45446 ripley 1668
	    return (size_t) -1;
1669
	case E2BIG:
1670
	    break;
1671
	default:
72952 murdoch 1672
	    Riconv_close(cd);
45446 ripley 1673
	    errno = EILSEQ;
1674
	    return (size_t) -1;
1675
	}
43980 ripley 1676
    }
46133 ripley 1677
    Riconv_close(cd);
43953 ripley 1678
    *wc = wcs[0];
1679
    return (size_t) 1;
1680
}
1681
 
44329 ripley 1682
/* made available for use in graphics devices */
1683
size_t ucstoutf8(char *s, const unsigned int wc)
43953 ripley 1684
{
1685
    char     buf[16];
1686
    void    *cd = NULL ;
1687
    unsigned int  wcs[2];
1688
    const char *inbuf = (const char *) wcs;
1689
    size_t   inbytesleft = sizeof(unsigned int); /* better be 4 */
1690
    char    *outbuf = buf;
1691
    size_t   outbytesleft = sizeof(buf);
1692
    size_t   status;
45446 ripley 1693
 
43953 ripley 1694
    if(wc == 0) {*s = '\0'; return 1;}
45446 ripley 1695
 
43953 ripley 1696
    memset(buf, 0, sizeof(buf));
1697
    wcs[0] = wc; wcs[1] = 0;
1698
 
46133 ripley 1699
    if(ucsutf8_obj == NULL) {
1700
	if((void *)(-1) == (cd = Riconv_open("UTF-8", UNICODE))) {
1701
	    error(_("unsupported conversion from '%s' to '%s'"),
1702
		  UNICODE, "UTF-8");
1703
	    return (size_t)(-1);
1704
	}
1705
	ucsutf8_obj = cd;
1706
    }
70047 ripley 1707
 
46133 ripley 1708
    status = Riconv(ucsutf8_obj, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
43953 ripley 1709
 
1710
    if (status == (size_t) -1) {
45446 ripley 1711
	switch(errno){
1712
	case E2BIG:
1713
	    break;
1714
	default:
64471 ripley 1715
	    error(_("invalid Unicode point %u"), wc);
1716
	    return (size_t) -1; // Not reached
45446 ripley 1717
	}
43953 ripley 1718
    }
44325 ripley 1719
    *outbuf = '\0';
1720
    strcpy(s, buf);
43953 ripley 1721
    return strlen(buf);
1722
}
1723
 
36601 ripley 1724
/* moved from src/unix/sys-unix.c and src/gnuwin32/extra.c */
1725
 
1726
#ifdef HAVE_STAT
1727
# ifdef HAVE_ACCESS
1728
#  ifdef HAVE_UNISTD_H
1729
#   include <unistd.h>
1730
#  endif
1731
# endif
1732
 
41344 ripley 1733
#ifdef Win32
1734
# define WIN32_LEAN_AND_MEAN 1
1735
# include <windows.h> /* For GetShortPathName */
1736
#endif
1737
 
36622 ripley 1738
#if !defined(S_IFDIR) && defined(__S_IFDIR)
1739
# define S_IFDIR __S_IFDIR
1740
#endif
1741
 
36601 ripley 1742
static int isDir(char *path)
1743
{
54797 ripley 1744
#ifdef Win32
1745
    struct _stati64 sb;
1746
#else
36601 ripley 1747
    struct stat sb;
54797 ripley 1748
#endif
36601 ripley 1749
    int isdir = 0;
1750
    if(!path) return 0;
54797 ripley 1751
#ifdef Win32
1752
    if(_stati64(path, &sb) == 0) {
1753
#else
36601 ripley 1754
    if(stat(path, &sb) == 0) {
54797 ripley 1755
#endif
36601 ripley 1756
	isdir = (sb.st_mode & S_IFDIR) > 0; /* is a directory */
1757
#ifdef HAVE_ACCESS
1758
	/* We want to know if the directory is writable by this user,
1759
	   which mode does not tell us */
1760
	isdir &= (access(path, W_OK) == 0);
1761
#endif
1762
    }
1763
    return isdir;
1764
}
1765
#else
1766
static int isDir(char *path)
1767
{
1768
    return 1;
1769
}
1770
#endif /* HAVE_STAT */
1771
 
1772
#if !HAVE_DECL_MKDTEMP
1773
extern char * mkdtemp (char *template);
1774
#endif
1775
 
52128 ripley 1776
#ifdef Win32
1777
# include <ctype.h>
1778
#endif
1779
 
72621 maechler 1780
void R_reInitTempDir(int die_on_fail)
36601 ripley 1781
{
1782
    char *tmp, *tm, tmp1[PATH_MAX+11], *p;
1783
#ifdef Win32
44720 ripley 1784
    char tmp2[PATH_MAX];
36601 ripley 1785
    int hasspace = 0;
1786
#endif
1787
 
72621 maechler 1788
#define ERROR_MAYBE_DIE(MSG_)			\
1789
    if(die_on_fail)				\
1790
	R_Suicide(MSG_);			\
1791
    else					\
1792
	errorcall(R_NilValue, MSG_)
1793
 
39181 ripley 1794
    if(R_TempDir) return; /* someone else set it */
36616 ripley 1795
    tmp = NULL; /* getenv("R_SESSION_TMPDIR");   no longer set in R.sh */
36601 ripley 1796
    if (!tmp) {
1797
	tm = getenv("TMPDIR");
1798
	if (!isDir(tm)) {
1799
	    tm = getenv("TMP");
40376 ripley 1800
	    if (!isDir(tm)) {
36601 ripley 1801
		tm = getenv("TEMP");
40376 ripley 1802
		if (!isDir(tm))
36601 ripley 1803
#ifdef Win32
1804
		    tm = getenv("R_USER"); /* this one will succeed */
1805
#else
1806
		    tm = "/tmp";
1807
#endif
1808
	    }
1809
	}
1810
#ifdef Win32
1811
	/* make sure no spaces in path */
1812
	for (p = tm; *p; p++)
1813
	    if (isspace(*p)) { hasspace = 1; break; }
1814
	if (hasspace) {
1815
	    GetShortPathName(tm, tmp2, MAX_PATH);
1816
	    tm = tmp2;
1817
	}
62580 ripley 1818
	snprintf(tmp1, PATH_MAX+11, "%s\\RtmpXXXXXX", tm);
37091 ripley 1819
#else
62580 ripley 1820
	snprintf(tmp1, PATH_MAX+11, "%s/RtmpXXXXXX", tm);
36601 ripley 1821
#endif
1822
	tmp = mkdtemp(tmp1);
72621 maechler 1823
	if(!tmp) {
1824
	    ERROR_MAYBE_DIE(_("cannot create 'R_TempDir'"));
1825
	}
40392 ripley 1826
#ifndef Win32
1827
# ifdef HAVE_SETENV
1828
	if(setenv("R_SESSION_TMPDIR", tmp, 1))
1829
	    errorcall(R_NilValue, _("unable to set R_SESSION_TMPDIR"));
1830
# elif defined(HAVE_PUTENV)
36601 ripley 1831
	{
62580 ripley 1832
	    size_t len = strlen(tmp) + 20;
1833
	    char * buf = (char *) malloc((len) * sizeof(char));
36601 ripley 1834
	    if(buf) {
62580 ripley 1835
		snprintf(buf, len, "R_SESSION_TMPDIR=%s", tmp);
45446 ripley 1836
		if(putenv(buf))
40392 ripley 1837
		    errorcall(R_NilValue, _("unable to set R_SESSION_TMPDIR"));
36601 ripley 1838
		/* no free here: storage remains in use */
45446 ripley 1839
	    } else
40392 ripley 1840
		errorcall(R_NilValue, _("unable to set R_SESSION_TMPDIR"));
36601 ripley 1841
	}
40392 ripley 1842
# endif
36601 ripley 1843
#endif
1844
    }
1845
 
59096 ripley 1846
    size_t len = strlen(tmp) + 1;
36601 ripley 1847
    p = (char *) malloc(len);
40376 ripley 1848
    if(!p)
72621 maechler 1849
	ERROR_MAYBE_DIE(_("cannot allocate 'R_TempDir'"));
36601 ripley 1850
    else {
1851
	R_TempDir = p;
1852
	strcpy(R_TempDir, tmp);
39181 ripley 1853
	Sys_TempDir = R_TempDir;
36601 ripley 1854
    }
1855
}
1856
 
72621 maechler 1857
void attribute_hidden InitTempDir() {
1858
    R_reInitTempDir(/* die_on_fail = */ TRUE);
1859
}
1860
 
36601 ripley 1861
char * R_tmpnam(const char * prefix, const char * tempdir)
1862
{
54876 murdoch 1863
    return R_tmpnam2(prefix, tempdir, "");
1864
}
1865
 
57745 ripley 1866
/* NB for use with multicore: parent and all children share the same
70047 ripley 1867
   session directory and run in parallel.
72621 maechler 1868
   So as from 2.14.1, we make sure getpid() is part of the process.
57745 ripley 1869
*/
1870
char * R_tmpnam2(const char *prefix, const char *tempdir, const char *fileext)
54876 murdoch 1871
{
1872
    char tm[PATH_MAX], *res;
57745 ripley 1873
    unsigned int n, done = 0, pid = getpid();
37091 ripley 1874
#ifdef Win32
1875
    char filesep[] = "\\";
1876
#else
1877
    char filesep[] = "/";
1878
#endif
36601 ripley 1879
 
1880
    if(!prefix) prefix = "";	/* NULL */
54876 murdoch 1881
    if(!fileext) fileext = "";  /*  "   */
70047 ripley 1882
 
54876 murdoch 1883
#if RAND_MAX > 16777215
1884
#define RAND_WIDTH 8
1885
#else
1886
#define RAND_WIDTH 12
1887
#endif
70047 ripley 1888
 
1889
    if(strlen(tempdir) + 1 + strlen(prefix) + RAND_WIDTH + strlen(fileext) >= PATH_MAX)
1890
	error(_("temporary name too long"));
1891
 
36601 ripley 1892
    for (n = 0; n < 100; n++) {
1893
	/* try a random number at the end.  Need at least 6 hex digits */
1894
#if RAND_MAX > 16777215
57745 ripley 1895
	snprintf(tm, PATH_MAX, "%s%s%s%x%x%s", tempdir, filesep, prefix, pid, rand(), fileext);
36601 ripley 1896
#else
57745 ripley 1897
	snprintf(tm, PATH_MAX, "%s%s%s%x%x%x%s", tempdir, filesep, prefix, pid, rand(), rand(), fileext);
36601 ripley 1898
#endif
45446 ripley 1899
	if(!R_FileExists(tm)) {
40376 ripley 1900
	    done = 1;
1901
	    break;
36601 ripley 1902
	}
1903
    }
1904
    if(!done)
1905
	error(_("cannot find unused tempfile name"));
1906
    res = (char *) malloc((strlen(tm)+1) * sizeof(char));
50871 ripley 1907
    if(!res)
54876 murdoch 1908
	error(_("allocation failed in R_tmpnam2"));
36601 ripley 1909
    strcpy(res, tm);
1910
    return res;
1911
}
39743 duncan 1912
 
77083 kalibera 1913
void R_free_tmpnam(char *name)
77059 kalibera 1914
{
1915
    if (name) free(name);
1916
}
1917
 
39948 ripley 1918
SEXP attribute_hidden do_proctime(SEXP call, SEXP op, SEXP args, SEXP env)
1919
{
44103 ripley 1920
    SEXP ans, nm;
51258 ripley 1921
 
1922
    checkArity(op, args);
44103 ripley 1923
    PROTECT(ans = allocVector(REALSXP, 5));
1924
    PROTECT(nm = allocVector(STRSXP, 5));
39948 ripley 1925
    R_getProcTime(REAL(ans));
40050 ripley 1926
    SET_STRING_ELT(nm, 0, mkChar("user.self"));
1927
    SET_STRING_ELT(nm, 1, mkChar("sys.self"));
40051 ripley 1928
    SET_STRING_ELT(nm, 2, mkChar("elapsed"));
40050 ripley 1929
    SET_STRING_ELT(nm, 3, mkChar("user.child"));
1930
    SET_STRING_ELT(nm, 4, mkChar("sys.child"));
1931
    setAttrib(ans, R_NamesSymbol, nm);
39948 ripley 1932
    setAttrib(ans, R_ClassSymbol, mkString("proc_time"));
44103 ripley 1933
    UNPROTECT(2);
39948 ripley 1934
    return ans;
1935
}
45074 ripley 1936
 
1937
void attribute_hidden resetTimeLimits()
1938
{
1939
    double data[5];
1940
    R_getProcTime(data);
1941
 
1942
    elapsedLimit = (elapsedLimitValue > 0) ? data[2] + elapsedLimitValue : -1.0;
45446 ripley 1943
    if (elapsedLimit2 > 0.0 &&
45074 ripley 1944
	(elapsedLimit <= 0.0 || elapsedLimit2 < elapsedLimit))
1945
	elapsedLimit = elapsedLimit2;
1946
 
1947
#ifdef Win32
1948
    cpuLimit = (cpuLimitValue > 0) ? data[0] + data[1] + cpuLimitValue : -1.0;
1949
#else
1950
    cpuLimit = (cpuLimitValue > 0) ? data[0] + data[1] + data[3] + data[4] + cpuLimitValue : -1.0;
1951
#endif
1952
    if (cpuLimit2 > 0.0 && (cpuLimit <= 0.0 || cpuLimit2 < cpuLimit))
1953
	cpuLimit = cpuLimit2;
1954
}
1955
 
1956
SEXP attribute_hidden
1957
do_setTimeLimit(SEXP call, SEXP op, SEXP args, SEXP rho)
1958
{
1959
    double cpu, elapsed, old_cpu = cpuLimitValue,
1960
	old_elapsed = elapsedLimitValue;
1961
    int transient;
1962
 
1963
    checkArity(op, args);
1964
    cpu = asReal(CAR(args));
1965
    elapsed = asReal(CADR(args));
1966
    transient = asLogical(CADDR(args));
1967
 
1968
    if (R_FINITE(cpu) && cpu > 0) cpuLimitValue = cpu; else cpuLimitValue = -1;
1969
 
1970
    if (R_FINITE(elapsed) && elapsed > 0) elapsedLimitValue = elapsed;
1971
    else elapsedLimitValue = -1;
1972
 
1973
    resetTimeLimits();
1974
 
1975
    if (transient == TRUE) {
1976
	cpuLimitValue = old_cpu;
1977
	elapsedLimitValue = old_elapsed;
1978
    }
1979
 
1980
    return R_NilValue;
1981
}
1982
 
1983
SEXP attribute_hidden
1984
do_setSessionTimeLimit(SEXP call, SEXP op, SEXP args, SEXP rho)
1985
{
1986
    double cpu, elapsed, data[5];
1987
 
1988
    checkArity(op, args);
1989
    cpu = asReal(CAR(args));
1990
    elapsed = asReal(CADR(args));
1991
    R_getProcTime(data);
1992
 
45446 ripley 1993
    if (R_FINITE(cpu) && cpu > 0)
45074 ripley 1994
#ifdef Win32
1995
	cpuLimit2 = cpu + data[0] + data[1];
1996
#else
45446 ripley 1997
	cpuLimit2 = cpu + data[0] + data[1] + data[3] + data[4];
45074 ripley 1998
#endif
1999
    else cpuLimit2 = -1;
2000
 
2001
    if (R_FINITE(elapsed) && elapsed > 0) elapsedLimit2 = elapsed + data[2];
2002
    else elapsedLimit2 = -1;
2003
 
2004
    return R_NilValue;
2005
}
49381 ripley 2006
 
49383 ripley 2007
/* moved from character.c in 2.10.0: configure requires this */
49381 ripley 2008
 
2009
#ifdef HAVE_GLOB_H
2010
# include <glob.h>
2011
#endif
2012
#ifdef Win32
2013
# include <dos_wglob.h>
2014
# define globfree dos_wglobfree
2015
# define glob_t wglob_t
2016
#else
2017
# ifndef GLOB_QUOTE
2018
#  define GLOB_QUOTE 0
2019
# endif
2020
#endif
2021
SEXP attribute_hidden do_glob(SEXP call, SEXP op, SEXP args, SEXP env)
2022
{
2023
    SEXP x, ans;
70047 ripley 2024
    R_xlen_t i, n;
59832 pd 2025
    int res, dirmark, initialized=FALSE;
49381 ripley 2026
    glob_t globbuf;
49392 ripley 2027
#ifdef Win32
49385 ripley 2028
    R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};
49392 ripley 2029
#endif
49381 ripley 2030
 
2031
    checkArity(op, args);
2032
    if (!isString(x = CAR(args)))
2033
	error(_("invalid '%s' argument"), "paths");
59052 ripley 2034
    if (!XLENGTH(x)) return allocVector(STRSXP, 0);
49381 ripley 2035
    dirmark = asLogical(CADR(args));
2036
    if (dirmark == NA_LOGICAL)
2037
	error(_("invalid '%s' argument"), "dirmark");
2038
#ifndef GLOB_MARK
2039
    if (dirmark)
2040
	error(_("'dirmark = TRUE' is not supported on this platform"));
2041
#endif
2042
 
59052 ripley 2043
    for (i = 0; i < XLENGTH(x); i++) {
49381 ripley 2044
	SEXP el = STRING_ELT(x, i);
2045
	if (el == NA_STRING) continue;
2046
#ifdef Win32
2047
	res = dos_wglob(filenameToWchar(el, FALSE),
2048
			(dirmark ? GLOB_MARK : 0) |
59832 pd 2049
			GLOB_QUOTE | (initialized ? GLOB_APPEND : 0),
49381 ripley 2050
			NULL, &globbuf);
2051
	if (res == GLOB_NOSPACE)
2052
	    error(_("internal out-of-memory condition"));
2053
#else
2054
	res = glob(translateChar(el),
2055
# ifdef GLOB_MARK
2056
		   (dirmark ? GLOB_MARK : 0) |
2057
# endif
59832 pd 2058
		   GLOB_QUOTE | (initialized ? GLOB_APPEND : 0),
49381 ripley 2059
		   NULL, &globbuf);
2060
# ifdef GLOB_ABORTED
2061
	if (res == GLOB_ABORTED)
2062
	    warning(_("read error on '%s'"), translateChar(el));
2063
# endif
2064
# ifdef GLOB_NOSPACE
2065
	if (res == GLOB_NOSPACE)
2066
	    error(_("internal out-of-memory condition"));
2067
# endif
2068
#endif
59832 pd 2069
	initialized = TRUE;
49381 ripley 2070
    }
59832 pd 2071
    n = initialized ? globbuf.gl_pathc : 0;
49381 ripley 2072
    PROTECT(ans = allocVector(STRSXP, n));
2073
    for (i = 0; i < n; i++)
2074
#ifdef Win32
2075
    {
2076
	wchar_t *w = globbuf.gl_pathv[i];
2077
	char *buf;
72714 murdoch 2078
	int nb = wcstoutf8(NULL, w, INT_MAX);
2079
	buf = R_AllocStringBuffer(nb, &cbuff);
2080
	wcstoutf8(buf, w, nb);
49381 ripley 2081
	SET_STRING_ELT(ans, i, mkCharCE(buf, CE_UTF8));
2082
    }
2083
#else
2084
	SET_STRING_ELT(ans, i, mkChar(globbuf.gl_pathv[i]));
2085
#endif
2086
    UNPROTECT(1);
2087
#ifdef Win32
2088
    R_FreeStringBufferL(&cbuff);
2089
#endif
59832 pd 2090
    if (initialized) globfree(&globbuf);
49381 ripley 2091
    return ans;
2092
}
76905 kalibera 2093
 
2094
/* isatty is in unistd.h, or io.h on Windows */
2095
#ifdef Win32
2096
# include <io.h>
2097
#endif
2098
 
2099
#ifdef Win32
2100
 
2101
#if _WIN32_WINNT < 0x0600
2102
/* available from Windows Vista */
2103
typedef enum _FILE_INFO_BY_HANDLE_CLASS {
2104
  FileBasicInfo,
2105
  FileStandardInfo,
2106
  FileNameInfo,
2107
  FileRenameInfo,
2108
  FileDispositionInfo,
2109
  FileAllocationInfo,
2110
  FileEndOfFileInfo,
2111
  FileStreamInfo,
2112
  FileCompressionInfo,
2113
  FileAttributeTagInfo,
2114
  FileIdBothDirectoryInfo,
2115
  FileIdBothDirectoryRestartInfo,
2116
  FileIoPriorityHintInfo,
2117
  FileRemoteProtocolInfo,
2118
  FileFullDirectoryInfo,
2119
  FileFullDirectoryRestartInfo,
2120
  FileStorageInfo,
2121
  FileAlignmentInfo,
2122
  FileIdInfo,
2123
  FileIdExtdDirectoryInfo,
2124
  FileIdExtdDirectoryRestartInfo,
2125
  FileDispositionInfoEx,
2126
  FileRenameInfoEx,
2127
  MaximumFileInfoByHandleClass,
2128
  FileCaseSensitiveInfo,
2129
  FileNormalizedNameInfo
2130
} FILE_INFO_BY_HANDLE_CLASS, *PFILE_INFO_BY_HANDLE_CLASS;
2131
 
2132
typedef struct _FILE_NAME_INFO {
2133
  DWORD FileNameLength;
2134
  WCHAR FileName[1];
2135
} FILE_NAME_INFO, *PFILE_NAME_INFO;
2136
#endif
2137
 
2138
typedef BOOL (WINAPI *LPFN_GFIBH_EX) (HANDLE, FILE_INFO_BY_HANDLE_CLASS,
2139
                                      LPVOID, DWORD);
2140
 
2141
int attribute_hidden R_is_redirection_tty(int fd)
2142
{
2143
    /* for now detects only msys/cygwin redirection tty */
2144
    static LPFN_GFIBH_EX gfibh = NULL;
2145
    static Rboolean initialized = FALSE;
2146
 
2147
    if (!initialized) {
2148
	initialized = TRUE;
2149
	gfibh = (LPFN_GFIBH_EX) GetProcAddress(
2150
	    GetModuleHandle(TEXT("kernel32")),
2151
	    "GetFileInformationByHandleEx");
2152
    }
2153
    if (gfibh == NULL)
2154
	return 0;
2155
 
2156
    HANDLE h = (HANDLE) _get_osfhandle(fd);
2157
    if (h == INVALID_HANDLE_VALUE || GetFileType(h) != FILE_TYPE_PIPE)
2158
	return 0;
2159
    FILE_NAME_INFO *fnInfo;
2160
    DWORD size = sizeof(FILE_NAME_INFO) + MAX_PATH*sizeof(WCHAR);
2161
    if (!(fnInfo = (FILE_NAME_INFO*)malloc(size)))
2162
	return 0;
2163
    int res = 0;
76998 kalibera 2164
    if (gfibh(h, FileNameInfo, fnInfo, size)) 
2165
	/* e.g. msys-1888ae32e00d56aa-pty0-from-master,
2166
	        cygwin-e022582115c10879-pty0-from-master */
76905 kalibera 2167
	/* test borrowed from git */
2168
	res = ((wcsstr(fnInfo->FileName, L"msys-") ||
2169
	        wcsstr(fnInfo->FileName, L"cygwin-")) &&
2170
		wcsstr(fnInfo->FileName, L"-pty"));
2171
    free(fnInfo);
2172
    return res;
2173
}
2174
#endif
2175
 
2176
int attribute_hidden R_isatty(int fd)
2177
{
2178
#ifdef Win32
2179
    if (R_is_redirection_tty(fd))
2180
	return 1;
2181
#endif
2182
    return isatty(fd);
2183
}
2184