Rev 57128 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
/** R : A Computer Language for Statistical Data Analysis* Copyright (C) 1995-1996 Robert Gentleman and Ross Ihaka* Copyright (C) 1997-2011 The R Development Core Team** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, a copy is available at* http://www.r-project.org/Licenses/*/#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdlib.h> /* for putenv */#include <Defn.h>#include <R_ext/Riconv.h>#include <Rinterface.h>#include <errno.h>/*See ../unix/system.txt for a description of some of these functions.Formally part of ../unix/sys-common.c.*//* The __APPLE__ and __APPLE_CC__ defines are for OS X *//** FILESYSTEM INTERACTION*//** This call provides a simple interface to the "stat" system call.*/#ifdef HAVE_SYS_TYPES_H# include <sys/types.h>#endif#ifdef HAVE_SYS_STAT_H# include <sys/stat.h>#endif#ifdef HAVE_AQUAint (*ptr_CocoaSystem)(char*);extern Rboolean useaqua;#endif#ifdef Win32Rboolean attribute_hidden R_FileExists(const char *path){struct _stati64 sb;return _stati64(R_ExpandFileName(path), &sb) == 0;}double attribute_hidden R_FileMtime(const char *path){struct _stati64 sb;if (_stati64(R_ExpandFileName(path), &sb) != 0)error(_("cannot determine file modification time of '%s'"), path);return sb.st_mtime;}#elseRboolean attribute_hidden R_FileExists(const char *path){struct stat sb;return stat(R_ExpandFileName(path), &sb) == 0;}double attribute_hidden R_FileMtime(const char *path){struct stat sb;if (stat(R_ExpandFileName(path), &sb) != 0)error(_("cannot determine file modification time of '%s'"), path);return sb.st_mtime;}#endif/** Unix file names which begin with "." are invisible.*/Rboolean attribute_hidden R_HiddenFile(const char *name){if (name && name[0] != '.') return 0;else return 1;}/* The MSVC runtime has a global to determine whether an unspecifiedfile open is in text or binary mode. We force explicit text modehere to avoid depending on that global, which may have been changedby user code (most likely in embedded applications of R).*/#ifdef Win32static char * fixmode(const char *mode){/* Rconnection can have a mode of 4 chars plus a null; we might* add one char */static char fixedmode[6];fixedmode[4] = '\0';strncpy(fixedmode, mode, 4);if (!strpbrk(fixedmode, "bt")) {strcat(fixedmode, "t");}return fixedmode;}static wchar_t * wcfixmode(const wchar_t *mode){static wchar_t wcfixedmode[6];wcfixedmode[4] = L'\0';wcsncpy(wcfixedmode, mode, 4);if (!wcspbrk(wcfixedmode, L"bt")) {wcscat(wcfixedmode, L"t");}return wcfixedmode;}#else#define fixmode(mode) (mode)#define wcfixmode(mode) (mode)#endifFILE *R_fopen(const char *filename, const char *mode){return(filename ? fopen(filename, fixmode(mode)) : NULL );}/* The point of this function is to allow file names in foreigncharacter sets. On Unix-alikes in a UTF-8 locale all that isneeded is to convert file names to UTF-8, since they will be storedin UTF-8. For other locales, it seems that there is no way to specifya file name in UTF-8.On NT-based versions of Windows, file names are stored in 'Unicode'(UCS-2), and _wfopen is provided to access them by UCS-2 names.*/#if defined(Win32)#define BSIZE 100000wchar_t *filenameToWchar(const SEXP fn, const Rboolean expand){static wchar_t filename[BSIZE+1];void *obj;const char *from = "", *inbuf;char *outbuf;size_t inb, outb, res;if(!strlen(CHAR(fn))) {wcscpy(filename, L"");return filename;}if(IS_LATIN1(fn)) from = "latin1";if(IS_UTF8(fn)) from = "UTF-8";if(IS_BYTES(fn)) error(_("encoding of a filename cannot be 'bytes'"));obj = Riconv_open("UCS-2LE", from);if(obj == (void *)(-1))error(_("unsupported conversion from '%s' in codepage %d"),from, localeCP);if(expand) inbuf = R_ExpandFileName(CHAR(fn)); else inbuf = CHAR(fn);inb = strlen(inbuf)+1; outb = 2*BSIZE;outbuf = (char *) filename;res = Riconv(obj, &inbuf , &inb, &outbuf, &outb);Riconv_close(obj);if(inb > 0) error(_("file name conversion problem -- name too long?"));if(res == -1) error(_("file name conversion problem"));return filename;}FILE *R_wfopen(const wchar_t *filename, const wchar_t *mode){return filename ? _wfopen(filename, wcfixmode(mode)) : NULL;}FILE *RC_fopen(const SEXP fn, const char *mode, const Rboolean expand){wchar_t wmode[10];if(fn == NA_STRING) return NULL;mbstowcs(wmode, fixmode(mode), 10);return _wfopen(filenameToWchar(fn, expand), wmode);}#elseFILE *RC_fopen(const SEXP fn, const char *mode, const Rboolean expand){const char *filename = translateChar(fn);if(fn == NA_STRING || !filename) return NULL;if(expand) return fopen(R_ExpandFileName(filename), mode);else return fopen(filename, mode);}#endif/** SYSTEM INFORMATION*//* The location of the R system files */char *R_HomeDir(void){return getenv("R_HOME");}/* This is a primitive (with no arguments) */SEXP attribute_hidden do_interactive(SEXP call, SEXP op, SEXP args, SEXP rho){checkArity(op, args);return ScalarLogical( (R_Interactive) ? 1 : 0 );}SEXP attribute_hidden do_tempdir(SEXP call, SEXP op, SEXP args, SEXP env){checkArity(op, args);return mkString(R_TempDir);}SEXP attribute_hidden do_tempfile(SEXP call, SEXP op, SEXP args, SEXP env){SEXP ans, pattern, fileext, tempdir;const char *tn, *td, *te;char *tm;int i, n1, n2, n3, slen;checkArity(op, args);pattern = CAR(args); n1 = length(pattern); args = CDR(args);tempdir = CAR(args); n2 = length(tempdir); args = CDR(args);fileext = CAR(args); n3 = length(fileext);if (!isString(pattern))error(_("invalid filename pattern"));if (!isString(tempdir))error(_("invalid '%s' value"), "tempdir");if (!isString(fileext))error(_("invalid file extension"));if (n1 < 1)error(_("no 'pattern'"));if (n2 < 1)error(_("no 'tempdir'"));if (n3 < 1)error(_("no 'fileext'"));slen = (n1 > n2) ? n1 : n2;slen = (n3 > slen) ? n3 : slen;PROTECT(ans = allocVector(STRSXP, slen));for(i = 0; i < slen; i++) {tn = translateChar( STRING_ELT( pattern , i%n1 ) );td = translateChar( STRING_ELT( tempdir , i%n2 ) );te = translateChar( STRING_ELT( fileext , i%n3 ) );/* try to get a new file name */tm = R_tmpnam2(tn, td, te);SET_STRING_ELT(ans, i, mkChar(tm));if(tm) free(tm);}UNPROTECT(1);return (ans);}FILE *R_popen(const char *command, const char *type){FILE *fp;#ifdef __APPLE_CC__/* Luke recommends this to fix PR#1140 */sigset_t ss;sigemptyset(&ss);sigaddset(&ss, SIGPROF);sigprocmask(SIG_BLOCK, &ss, NULL);fp = popen(command, type);sigprocmask(SIG_UNBLOCK, &ss, NULL);#elsefp = popen(command, type);#endifreturn fp;}#ifdef HAVE_SYS_WAIT_H# include <sys/wait.h>#endifint R_system(const char *command){int res;#ifdef __APPLE_CC__/* Luke recommends this to fix PR#1140 */sigset_t ss;sigemptyset(&ss);sigaddset(&ss, SIGPROF);sigprocmask(SIG_BLOCK, &ss, NULL);#ifdef HAVE_AQUAchar *cmdcpy;if(useaqua) {/* FIXME, is Cocoa's interface not const char*? */cmdcpy = acopy_string(command);res = ptr_CocoaSystem(cmdcpy);}else#endifres = system(command);sigprocmask(SIG_UNBLOCK, &ss, NULL);#elseres = system(command);#endif#ifdef HAVE_SYS_WAIT_Hif (WIFEXITED(res)) res = WEXITSTATUS(res);else res = 0;#else/* assume that this is shifted if a multiple of 256 */if ((res % 256) == 0) res = res/256;#endifreturn res;}#if defined(__APPLE__)# include <crt_externs.h># define environ (*_NSGetEnviron())#elseextern char ** environ;#endif#ifdef Win32/* _wenviron is declared in stdlib.h */# define WIN32_LEAN_AND_MEAN 1# include <windows.h> /* _wgetenv etc */#endifSEXP attribute_hidden do_getenv(SEXP call, SEXP op, SEXP args, SEXP env){int i, j;SEXP ans;checkArity(op, args);if (!isString(CAR(args)))error(_("wrong type for argument"));if (!isString(CADR(args)) || LENGTH(CADR(args)) != 1)error(_("wrong type for argument"));i = LENGTH(CAR(args));if (i == 0) {#ifdef Win32int n = 0, N;wchar_t **w;for (i = 0, w = _wenviron; *w != NULL; i++, w++)n = max(n, wcslen(*w));N = 3*n+1;char buf[N];PROTECT(ans = allocVector(STRSXP, i));for (i = 0, w = _wenviron; *w != NULL; i++, w++) {wcstoutf8(buf, *w, N); buf[N-1] = '\0';SET_STRING_ELT(ans, i, mkCharCE(buf, CE_UTF8));}#elsechar **e;for (i = 0, e = environ; *e != NULL; i++, e++);PROTECT(ans = allocVector(STRSXP, i));for (i = 0, e = environ; *e != NULL; i++, e++)SET_STRING_ELT(ans, i, mkChar(*e));#endif} else {PROTECT(ans = allocVector(STRSXP, i));for (j = 0; j < i; j++) {#ifdef Win32const wchar_t *wnm = wtransChar(STRING_ELT(CAR(args), j));wchar_t *w = _wgetenv(wnm);if (w == NULL)SET_STRING_ELT(ans, j, STRING_ELT(CADR(args), 0));else {int n = wcslen(w), N = 3*n+1; /* UCS-2 maps to <=3 UTF-8 */char buf[N];R_CheckStack();wcstoutf8(buf, w, N); buf[N-1] = '\0'; /* safety */SET_STRING_ELT(ans, j, mkCharCE(buf, CE_UTF8));}#elsechar *s = getenv(translateChar(STRING_ELT(CAR(args), j)));if (s == NULL)SET_STRING_ELT(ans, j, STRING_ELT(CADR(args), 0));else {SEXP tmp;if(known_to_be_latin1) tmp = mkCharCE(s, CE_LATIN1);else if(known_to_be_utf8) tmp = mkCharCE(s, CE_UTF8);else tmp = mkChar(s);SET_STRING_ELT(ans, j, tmp);}#endif}}UNPROTECT(1);return (ans);}#ifdef Win32static int Rwputenv(const wchar_t *nm, const wchar_t *val){wchar_t *buf;buf = (wchar_t *) malloc((wcslen(nm) + wcslen(val) + 2) * sizeof(wchar_t));if(!buf) return 1;/* previously wsprintfW, which had a limit of 1024 chars */wcscpy(buf, nm); wcscat(buf, L"="); wcscat(buf, val);if(_wputenv(buf)) return 1;/* no free here: storage remains in use */return 0;}#elif !defined(HAVE_SETENV) && defined(HAVE_PUTENV)static int Rputenv(const char *nm, const char *val){char *buf;buf = (char *) malloc((strlen(nm) + strlen(val) + 2) * sizeof(char));if(!buf) return 1;sprintf(buf, "%s=%s", nm, val);if(putenv(buf)) return 1;/* no free here: storage remains in use */return 0;}#endifSEXP attribute_hidden do_setenv(SEXP call, SEXP op, SEXP args, SEXP env){#if defined(HAVE_PUTENV) || defined(HAVE_SETENV)int i, n;SEXP ans, nm, vars;checkArity(op, args);if (!isString(nm = CAR(args)))error(_("wrong type for argument"));if (!isString(vars = CADR(args)))error(_("wrong type for argument"));if(LENGTH(nm) != LENGTH(vars))error(_("wrong length for argument"));n = LENGTH(vars);PROTECT(ans = allocVector(LGLSXP, n));#ifdef HAVE_SETENVfor (i = 0; i < n; i++)LOGICAL(ans)[i] = setenv(translateChar(STRING_ELT(nm, i)),translateChar(STRING_ELT(vars, i)),1) == 0;#elif defined(Win32)for (i = 0; i < n; i++)LOGICAL(ans)[i] = Rwputenv(wtransChar(STRING_ELT(nm, i)),wtransChar(STRING_ELT(vars, i))) == 0;#elsefor (i = 0; i < n; i++)LOGICAL(ans)[i] = Rputenv(translateChar(STRING_ELT(nm, i)),translateChar(STRING_ELT(vars, i))) == 0;#endifUNPROTECT(1);return ans;#elseerror(_("'Sys.setenv' is not available on this system"));return R_NilValue; /* -Wall */#endif}SEXP attribute_hidden do_unsetenv(SEXP call, SEXP op, SEXP args, SEXP env){int i, n;SEXP ans, vars;checkArity(op, args);if (!isString(vars = CAR(args)))error(_("wrong type for argument"));n = LENGTH(vars);#if defined(HAVE_UNSETENV) || defined(HAVE_PUTENV_UNSET) || defined(HAVE_PUTENV_UNSET2)#ifdef HAVE_UNSETENVfor (i = 0; i < n; i++) unsetenv(translateChar(STRING_ELT(vars, i)));#elif defined(HAVE_PUTENV_UNSET)for (i = 0; i < n; i++) {char buf[1000];snprintf(buf, 1000, "%s", translateChar(STRING_ELT(vars, i)));putenv(buf);}#elif defined(HAVE_PUTENV_UNSET2)# ifdef Win32for (i = 0; i < n; i++) {const wchar_t *w = wtransChar(STRING_ELT(vars, i));wchar_t buf[2*wcslen(w)];wcscpy(buf, w);wcscat(buf, L"=");_wputenv(buf);}# elsefor (i = 0; i < n; i++) {char buf[1000];snprintf(buf, 1000, "%s=", translateChar(STRING_ELT(vars, i)));putenv(buf);}# endif#endif#elif defined(HAVE_PUTENV) || defined(HAVE_SETENV)warning(_("this system cannot unset environment variables: setting to \"\""));n = LENGTH(vars);for (i = 0; i < n; i++) {#ifdef HAVE_SETENVsetenv(translateChar(STRING_ELT(vars, i)), "", 1);#elseRputenv(translateChar(STRING_ELT(vars, i)), "");#endif}#elsewarning(_("'Sys.unsetenv' is not available on this system"));#endifPROTECT(ans = allocVector(LGLSXP, n));for (i = 0; i < n; i++)LOGICAL(ans)[i] = !getenv(translateChar(STRING_ELT(vars, i)));UNPROTECT(1);return ans;}#include <iconv.h>#ifdef HAVE_ICONVLISTstatic unsigned int cnt;static intcount_one (unsigned int namescount, const char * const *names, void *data){cnt += namescount;return 0;}static intwrite_one (unsigned int namescount, const char * const *names, void *data){unsigned int i;SEXP ans = (SEXP) data;for (i = 0; i < namescount; i++)SET_STRING_ELT(ans, cnt++, mkChar(names[i]));return 0;}#endif#include "RBufferUtils.h"/* iconv(x, from, to, sub, mark) */SEXP attribute_hidden do_iconv(SEXP call, SEXP op, SEXP args, SEXP env){SEXP ans, x = CAR(args), si;void * obj;int i, j, nout;const char *inbuf;char *outbuf;const char *sub;size_t inb, outb, res;R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};Rboolean isRawlist = FALSE;checkArity(op, args);if(isNull(x)) { /* list locales */#ifdef HAVE_ICONVLISTcnt = 0;iconvlist(count_one, NULL);PROTECT(ans = allocVector(STRSXP, cnt));cnt = 0;iconvlist(write_one, (void *)ans);#elsePROTECT(ans = R_NilValue);#endif} else {int mark, toRaw;const char *from, *to;Rboolean isLatin1 = FALSE, isUTF8 = FALSE;args = CDR(args);if(!isString(CAR(args)) || length(CAR(args)) != 1)error(_("invalid '%s' argument"), "from");from = CHAR(STRING_ELT(CAR(args), 0)); /* ASCII */args = CDR(args);if(!isString(CAR(args)) || length(CAR(args)) != 1)error(_("invalid '%s' argument"), "to");to = CHAR(STRING_ELT(CAR(args), 0));args = CDR(args);if(!isString(CAR(args)) || length(CAR(args)) != 1)error(_("invalid '%s' argument"), "sub");if(STRING_ELT(CAR(args), 0) == NA_STRING) sub = NULL;else sub = translateChar(STRING_ELT(CAR(args), 0));args = CDR(args);mark = asLogical(CAR(args));if(mark == NA_LOGICAL)error(_("invalid '%s' argument"), "mark");args = CDR(args);toRaw = asLogical(CAR(args));if(toRaw == NA_LOGICAL)error(_("invalid '%s' argument"), "toRaw");/* some iconv's allow "UTF8", but libiconv does not */if(streql(from, "UTF8") || streql(from, "utf8") ) from = "UTF-8";if(streql(to, "UTF8") || streql(from, "utf8") ) to = "UTF-8";/* Should we do something about marked CHARSXPs in 'from = ""'? */if(streql(to, "UTF-8")) isUTF8 = TRUE;if(streql(to, "latin1") || streql(to, "ISO_8859-1")|| streql(to, "CP1252")) isLatin1 = TRUE;if(streql(to, "") && known_to_be_latin1) isLatin1 = TRUE;if(streql(to, "") && known_to_be_utf8) isUTF8 = TRUE;obj = Riconv_open(to, from);if(obj == (iconv_t)(-1))#ifdef Win32error(_("unsupported conversion from '%s' to '%s' in codepage %d"),from, to, localeCP);#elseerror(_("unsupported conversion from '%s' to '%s'"), from, to);#endifisRawlist = (TYPEOF(x) == VECSXP);if(isRawlist) {if(toRaw)PROTECT(ans = duplicate(x));else {PROTECT(ans = allocVector(STRSXP, LENGTH(x)));DUPLICATE_ATTRIB(ans, x);}} else {if(TYPEOF(x) != STRSXP)error(_("'x' must be a character vector"));if(toRaw) {PROTECT(ans = allocVector(VECSXP, LENGTH(x)));DUPLICATE_ATTRIB(ans, x);} elsePROTECT(ans = duplicate(x));}R_AllocStringBuffer(0, &cbuff); /* 0 -> default */for(i = 0; i < LENGTH(x); i++) {if (isRawlist) {si = VECTOR_ELT(x, i);if (TYPEOF(si) == NILSXP) {if (!toRaw) SET_STRING_ELT(ans, i, NA_STRING);continue;} else if (TYPEOF(si) != RAWSXP)error(_("'x' must be a list of NULL or raw vectors"));} else {si = STRING_ELT(x, i);if (si == NA_STRING) {if(!toRaw) SET_STRING_ELT(ans, i, NA_STRING);continue;}}top_of_loop:inbuf = isRawlist ? (const char *) RAW(si) : CHAR(si);inb = LENGTH(si);outbuf = cbuff.data; outb = cbuff.bufsize - 1;/* First initialize output */Riconv (obj, NULL, NULL, &outbuf, &outb);next_char:/* Then convert input */res = Riconv(obj, &inbuf , &inb, &outbuf, &outb);*outbuf = '\0';/* other possible error conditions are incompleteand invalid multibyte chars */if(res == -1 && errno == E2BIG) {R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);goto top_of_loop;} else if(res == -1 && sub &&(errno == EILSEQ || errno == EINVAL)) {/* it seems this gets thrown for non-convertible input too */if(strcmp(sub, "byte") == 0) {if(outb < 5) {R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);goto top_of_loop;}snprintf(outbuf, 5, "<%02x>", (unsigned char)*inbuf);outbuf += 4; outb -= 4;} else {if(outb < strlen(sub)) {R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);goto top_of_loop;}memcpy(outbuf, sub, j = strlen(sub));outbuf += j;outb -= j;}inbuf++; inb--;goto next_char;}if(toRaw) {if(res != -1 && inb == 0) {nout = cbuff.bufsize - 1 - outb;SEXP el = allocVector(RAWSXP, nout);memcpy(RAW(el), cbuff.data, nout);SET_VECTOR_ELT(ans, i, el);} /* otherwise is already NULL */} else {if(res != -1 && inb == 0) {cetype_t ienc = CE_NATIVE;nout = cbuff.bufsize - 1 - outb;if(mark) {if(isLatin1) ienc = CE_LATIN1;else if(isUTF8) ienc = CE_UTF8;}SET_STRING_ELT(ans, i, mkCharLenCE(cbuff.data, nout, ienc));} else SET_STRING_ELT(ans, i, NA_STRING);}}Riconv_close(obj);R_FreeStringBuffer(&cbuff);}UNPROTECT(1);return ans;}cetype_t getCharCE(SEXP x){if(TYPEOF(x) != CHARSXP)error(_("'%s' must be called on a CHARSXP"), "getCharCE");if(IS_UTF8(x)) return CE_UTF8;else if(IS_LATIN1(x)) return CE_LATIN1;else if(IS_BYTES(x)) return CE_BYTES;else return CE_NATIVE;}void * Riconv_open (const char* tocode, const char* fromcode){#if defined Win32 || __APPLE__# ifdef Win32const char *cp = "ASCII";# ifndef SUPPORT_UTF8_WIN32 /* Always, at present */char to[20] = "";if (localeCP > 0) {snprintf(to, 20, "CP%d", localeCP); cp = to;}# endif# else /* __APPLE__ */const char *cp = "UTF-8";if (latin1locale) cp = "ISO-8859-1";else if (!utf8locale) cp = locale2charset(NULL);# endifif (!*tocode && !*fromcode) return iconv_open(cp, cp);if(!*tocode) return iconv_open(cp, fromcode);else if(!*fromcode) return iconv_open(tocode, cp);else return iconv_open(tocode, fromcode);#elsereturn iconv_open(tocode, fromcode);#endif}/* Should be defined in config.h, but prior to 2.13.0 was only checkedif the NLS was enabled */#ifndef ICONV_CONST# define ICONV_CONST#endifsize_t Riconv (void *cd, const char **inbuf, size_t *inbytesleft,char **outbuf, size_t *outbytesleft){/* here libiconv has const char **, glibc has char ** for inbuf */return iconv((iconv_t) cd, (ICONV_CONST char **) inbuf, inbytesleft,outbuf, outbytesleft);}int Riconv_close (void *cd){return iconv_close((iconv_t) cd);}static void *latin1_obj = NULL, *utf8_obj=NULL, *ucsmb_obj=NULL,*ucsutf8_obj=NULL;const char *translateChar(SEXP x){void * obj;const char *inbuf, *ans = CHAR(x);char *outbuf, *p;size_t inb, outb, res;cetype_t ienc = getCharCE(x);R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};if(TYPEOF(x) != CHARSXP)error(_("'%s' must be called on a CHARSXP"), "translateChar");if(x == NA_STRING || !(ENC_KNOWN(x))) return ans;if(IS_BYTES(x))error(_("translating strings with \"bytes\" encoding is not allowed"));if(utf8locale && IS_UTF8(x)) return ans;if(latin1locale && IS_LATIN1(x)) return ans;if(strIsASCII(CHAR(x))) return ans;if(IS_LATIN1(x)) {if(!latin1_obj) {obj = Riconv_open("", "latin1");/* should never happen */if(obj == (void *)(-1))#ifdef Win32error(_("unsupported conversion from '%s' in codepage %d"),"latin1", localeCP);#elseerror(_("unsupported conversion from '%s' to '%s'"),"latin1", "");#endiflatin1_obj = obj;}obj = latin1_obj;} else {if(!utf8_obj) {obj = Riconv_open("", "UTF-8");/* should never happen */if(obj == (void *)(-1))#ifdef Win32error(_("unsupported conversion from '%s' in codepage %d"),"latin1", localeCP);#elseerror(_("unsupported conversion from '%s' to '%s'"),"latin1", "");#endifutf8_obj = obj;}obj = utf8_obj;}R_AllocStringBuffer(0, &cbuff);top_of_loop:inbuf = ans; inb = strlen(inbuf);outbuf = cbuff.data; outb = cbuff.bufsize - 1;/* First initialize output */Riconv (obj, NULL, NULL, &outbuf, &outb);next_char:/* Then convert input */res = Riconv(obj, &inbuf , &inb, &outbuf, &outb);if(res == -1 && errno == E2BIG) {R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);goto top_of_loop;} else if(res == -1 && (errno == EILSEQ || errno == EINVAL)) {if(outb < 13) {R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);goto top_of_loop;}if (ienc == CE_UTF8) {/* if starting in UTF-8, use \uxxxx *//* This must be the first byte */int clen;wchar_t wc;clen = utf8toucs(&wc, inbuf);if(clen > 0 && inb >= clen) {inbuf += clen; inb -= clen;# ifndef Win32if((unsigned int) wc < 65536) {# endifsnprintf(outbuf, 9, "<U+%04X>", (unsigned int) wc);outbuf += 8; outb -= 8;# ifndef Win32} else {snprintf(outbuf, 13, "<U+%08X>", (unsigned int) wc);outbuf += 12; outb -= 12;}# endif} else {snprintf(outbuf, 5, "<%02x>", (unsigned char)*inbuf);outbuf += 4; outb -= 4;inbuf++; inb--;}} else {snprintf(outbuf, 5, "<%02x>", (unsigned char)*inbuf);outbuf += 4; outb -= 4;inbuf++; inb--;}goto next_char;}*outbuf = '\0';res = strlen(cbuff.data) + 1;p = R_alloc(res, 1);memcpy(p, cbuff.data, res);R_FreeStringBuffer(&cbuff);return p;}const char *translateChar0(SEXP x){if(TYPEOF(x) != CHARSXP)error(_("'%s' must be called on a CHARSXP"), "translateChar0");if(IS_BYTES(x)) return CHAR(x);return translateChar(x);}const char *translateCharUTF8(SEXP x){void *obj;const char *inbuf, *ans = CHAR(x);char *outbuf, *p;size_t inb, outb, res;R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};if(TYPEOF(x) != CHARSXP)error(_("'%s' must be called on a CHARSXP"), "translateCharUTF8");if(x == NA_STRING) return ans;if(IS_UTF8(x)) return ans;if(strIsASCII(CHAR(x))) return ans;if(IS_BYTES(x))error(_("translating strings with \"bytes\" encoding is not allowed"));obj = Riconv_open("UTF-8", IS_LATIN1(x) ? "latin1" : "");if(obj == (void *)(-1))#ifdef Win32error(_("unsupported conversion from '%s' in codepage %d"),"latin1", localeCP);#elseerror(_("unsupported conversion from '%s' to '%s'"), "latin1", "UTF-8");#endifR_AllocStringBuffer(0, &cbuff);top_of_loop:inbuf = ans; inb = strlen(inbuf);outbuf = cbuff.data; outb = cbuff.bufsize - 1;/* First initialize output */Riconv (obj, NULL, NULL, &outbuf, &outb);next_char:/* Then convert input */res = Riconv(obj, &inbuf , &inb, &outbuf, &outb);if(res == -1 && errno == E2BIG) {R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);goto top_of_loop;} else if(res == -1 && (errno == EILSEQ || errno == EINVAL)) {if(outb < 5) {R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);goto top_of_loop;}snprintf(outbuf, 5, "<%02x>", (unsigned char)*inbuf);outbuf += 4; outb -= 4;inbuf++; inb--;goto next_char;}*outbuf = '\0';Riconv_close(obj);res = strlen(cbuff.data) + 1;p = R_alloc(res, 1);memcpy(p, cbuff.data, res);R_FreeStringBuffer(&cbuff);return p;}#ifdef Win32static const char TO_WCHAR[] = "UCS-2LE";#else# ifdef WORDS_BIGENDIANstatic const char TO_WCHAR[] = "UCS-4BE";# elsestatic const char TO_WCHAR[] = "UCS-4LE";# endif#endifstatic void *latin1_wobj = NULL, *utf8_wobj=NULL;/* Translate from current encoding to wchar_t = UCS-2/4NB: that wchar_t is UCS-4 is an assumption, but not easy to avoid.*/attribute_hidden /* but not hidden on Windows, where it was used in tcltk.c */const wchar_t *wtransChar(SEXP x){void * obj;const char *inbuf, *ans = CHAR(x);char *outbuf;wchar_t *p;size_t inb, outb, res, top;Rboolean knownEnc = FALSE;R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};if(TYPEOF(x) != CHARSXP)error(_("'%s' must be called on a CHARSXP"), "wtransChar");if(IS_BYTES(x))error(_("translating strings with \"bytes\" encoding is not allowed"));if(IS_LATIN1(x)) {if(!latin1_wobj) {obj = Riconv_open(TO_WCHAR, "latin1");if(obj == (void *)(-1))error(_("unsupported conversion from '%s' to '%s'"),"latin1", TO_WCHAR);latin1_wobj = obj;} elseobj = latin1_wobj;knownEnc = TRUE;} else if(IS_UTF8(x)) {if(!utf8_wobj) {obj = Riconv_open(TO_WCHAR, "UTF-8");if(obj == (void *)(-1))error(_("unsupported conversion from '%s' to '%s'"),"latin1", TO_WCHAR);utf8_wobj = obj;} elseobj = utf8_wobj;knownEnc = TRUE;} else {obj = Riconv_open(TO_WCHAR, "");if(obj == (void *)(-1))#ifdef Win32error(_("unsupported conversion to '%s' from codepage %d"),TO_WCHAR, localeCP);#elseerror(_("unsupported conversion from '%s' to '%s'"), "", TO_WCHAR);#endif}R_AllocStringBuffer(0, &cbuff);top_of_loop:inbuf = ans; inb = strlen(inbuf);outbuf = cbuff.data; top = outb = cbuff.bufsize - 1;/* First initialize output */Riconv (obj, NULL, NULL, &outbuf, &outb);next_char:/* Then convert input */res = Riconv(obj, &inbuf , &inb, &outbuf, &outb);if(res == -1 && errno == E2BIG) {R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);goto top_of_loop;} else if(res == -1 && (errno == EILSEQ || errno == EINVAL)) {if(outb < 5) {R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);goto top_of_loop;}snprintf(outbuf, 5, "<%02x>", (unsigned char)*inbuf);outbuf += 4; outb -= 4;inbuf++; inb--;goto next_char;/* if(!knownEnc) Riconv_close(obj);error(_("invalid input in wtransChar")); */}if(!knownEnc) Riconv_close(obj);res = (top - outb);/* terminator is 2 or 4 null bytes */p = (wchar_t *) R_alloc(res+4, 1);memset(p, 0, res+4);memcpy(p, cbuff.data, res);R_FreeStringBuffer(&cbuff);return p;}extern void *Rf_AdobeSymbol2utf8(char* work, const char *c0, int nwork); /* from util.c */const char *reEnc(const char *x, cetype_t ce_in, cetype_t ce_out, int subst){void * obj;const char *inbuf;char *outbuf, *p;size_t inb, outb, res, top;char *tocode = NULL, *fromcode = NULL;#ifdef Win32char buf[20];#endifR_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};/* We can only encode from Symbol to UTF-8 */if(ce_in == ce_out || ce_out == CE_SYMBOL ||ce_in == CE_ANY || ce_out == CE_ANY) return x;if(ce_in == CE_SYMBOL) {if(ce_out == CE_UTF8) {int nc = 3*strlen(x)+1; /* all in BMP */p = R_alloc(nc, 1);Rf_AdobeSymbol2utf8(p, x, nc);return p;} else return x;}if(utf8locale && ce_in == CE_NATIVE && ce_out == CE_UTF8) return x;if(utf8locale && ce_out == CE_NATIVE && ce_in == CE_UTF8) return x;if(latin1locale && ce_in == CE_NATIVE && ce_out == CE_LATIN1) return x;if(latin1locale && ce_out == CE_NATIVE && ce_in == CE_LATIN1) return x;if(strIsASCII(x)) return x;switch(ce_in) {#ifdef Win32case CE_NATIVE:{/* Looks like CP1252 is treated as Latin-1 by iconv */sprintf(buf, "CP%d", localeCP);fromcode = buf;break;}case CE_LATIN1: fromcode = "CP1252"; break;#elsecase CE_NATIVE: fromcode = ""; break;case CE_LATIN1: fromcode = "latin1"; break;#endifcase CE_UTF8: fromcode = "UTF-8"; break;default: return x;}switch(ce_out) {#ifdef Win32case CE_NATIVE:{/* avoid possible misidentification of CP1250 as LATIN-2 */sprintf(buf, "CP%d", localeCP);tocode = buf;break;}#elsecase CE_NATIVE: tocode = ""; break;#endifcase CE_LATIN1: tocode = "latin1"; break;case CE_UTF8: tocode = "UTF-8"; break;default: return x;}obj = Riconv_open(tocode, fromcode);if(obj == (void *)(-1)) return x;R_AllocStringBuffer(0, &cbuff);top_of_loop:inbuf = x; inb = strlen(inbuf);outbuf = cbuff.data; top = outb = cbuff.bufsize - 1;/* First initialize output */Riconv (obj, NULL, NULL, &outbuf, &outb);next_char:/* Then convert input */res = Riconv(obj, &inbuf , &inb, &outbuf, &outb);if(res == -1 && errno == E2BIG) {R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);goto top_of_loop;} else if(res == -1 && (errno == EILSEQ || errno == EINVAL)) {switch(subst) {case 1: /* substitute hex */if(outb < 5) {R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);goto top_of_loop;}snprintf(outbuf, 5, "<%02x>", (unsigned char)*inbuf);outbuf += 4; outb -= 4;inbuf++; inb--;goto next_char;break;case 2: /* substitute . */if(outb < 1) {R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);goto top_of_loop;}*outbuf++ = '.'; inbuf++; outb--; inb--;goto next_char;break;case 3: /* substitute ? */if(outb < 1) {R_AllocStringBuffer(2*cbuff.bufsize, &cbuff);goto top_of_loop;}*outbuf++ = '?'; inbuf++; outb--; inb--;goto next_char;break;default: /* skip byte */inbuf++; inb--;goto next_char;}}Riconv_close(obj);*outbuf = '\0';res = (top-outb)+1; /* strlen(cbuff.data) + 1; */p = R_alloc(res, 1);memcpy(p, cbuff.data, res);R_FreeStringBuffer(&cbuff);return p;}void attribute_hiddeninvalidate_cached_recodings(void){latin1_obj = NULL;utf8_obj = NULL;ucsmb_obj = NULL;#ifdef Win32latin1_wobj = NULL;utf8_wobj=NULL;#endif}#ifdef WORDS_BIGENDIANstatic const char UNICODE[] = "UCS-4BE";#elsestatic const char UNICODE[] = "UCS-4LE";#endif/* used in gram.c and devX11.c */size_t ucstomb(char *s, const unsigned int wc){char buf[MB_CUR_MAX+1];void *cd = NULL ;unsigned int wcs[2];const char *inbuf = (const char *) wcs;size_t inbytesleft = sizeof(unsigned int); /* better be 4 */char *outbuf = buf;size_t outbytesleft = sizeof(buf);size_t status;if(wc == 0) {*s = '\0'; return 1;}memset(buf, 0, sizeof(buf));memset(wcs, 0, sizeof(wcs));wcs[0] = wc;if(ucsmb_obj == NULL) {if((void *)(-1) == (cd = Riconv_open("", UNICODE))) {#ifndef Win32char tocode[128];/* locale set fuzzy case */strncpy(tocode, locale2charset(NULL), sizeof(tocode));if((void *)(-1) == (cd = Riconv_open(tocode, UNICODE)))return (size_t)(-1);#elsereturn (size_t)(-1);#endif}ucsmb_obj = cd;}status = Riconv(ucsmb_obj, &inbuf, &inbytesleft, &outbuf, &outbytesleft);if (status == (size_t) -1) {switch(errno){case EINVAL:return (size_t) -2;case EILSEQ:return (size_t) -1;case E2BIG:break;default:errno = EILSEQ;return (size_t) -1;}}buf[MB_CUR_MAX] = '\0'; /* safety measure */strcpy(s, buf);return strlen(buf);}/* used in plot.c for non-UTF-8 MBCS */size_t attribute_hiddenmbtoucs(unsigned int *wc, const char *s, size_t n){unsigned int wcs[2];char buf[16];void *cd;const char *inbuf = s;size_t inbytesleft = strlen(s);char *outbuf = (char *) wcs;size_t outbytesleft = sizeof(buf);size_t status;if(s[0] == 0) {*wc = 0; return 1;}if((void *)(-1) == (cd = Riconv_open(UNICODE, ""))) return (size_t)(-1);status = Riconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);if (status == (size_t) -1) {switch(errno){case EINVAL:return (size_t) -2;case EILSEQ:return (size_t) -1;case E2BIG:break;default:errno = EILSEQ;return (size_t) -1;}}Riconv_close(cd);*wc = wcs[0];return (size_t) 1;}/* made available for use in graphics devices */size_t ucstoutf8(char *s, const unsigned int wc){char buf[16];void *cd = NULL ;unsigned int wcs[2];const char *inbuf = (const char *) wcs;size_t inbytesleft = sizeof(unsigned int); /* better be 4 */char *outbuf = buf;size_t outbytesleft = sizeof(buf);size_t status;if(wc == 0) {*s = '\0'; return 1;}memset(buf, 0, sizeof(buf));wcs[0] = wc; wcs[1] = 0;if(ucsutf8_obj == NULL) {if((void *)(-1) == (cd = Riconv_open("UTF-8", UNICODE))) {error(_("unsupported conversion from '%s' to '%s'"),UNICODE, "UTF-8");return (size_t)(-1);}ucsutf8_obj = cd;}status = Riconv(ucsutf8_obj, &inbuf, &inbytesleft, &outbuf, &outbytesleft);if (status == (size_t) -1) {switch(errno){case EINVAL:return (size_t) -2;case EILSEQ:return (size_t) -1;case E2BIG:break;default:errno = EILSEQ;return (size_t) -1;}}*outbuf = '\0';strcpy(s, buf);return strlen(buf);}/* moved from src/unix/sys-unix.c and src/gnuwin32/extra.c */#ifdef HAVE_STAT# ifdef HAVE_ACCESS# ifdef HAVE_UNISTD_H# include <unistd.h># endif# endif#ifdef Win32# define WIN32_LEAN_AND_MEAN 1# include <windows.h> /* For GetShortPathName */#endif#if !defined(S_IFDIR) && defined(__S_IFDIR)# define S_IFDIR __S_IFDIR#endifstatic int isDir(char *path){#ifdef Win32struct _stati64 sb;#elsestruct stat sb;#endifint isdir = 0;if(!path) return 0;#ifdef Win32if(_stati64(path, &sb) == 0) {#elseif(stat(path, &sb) == 0) {#endifisdir = (sb.st_mode & S_IFDIR) > 0; /* is a directory */#ifdef HAVE_ACCESS/* We want to know if the directory is writable by this user,which mode does not tell us */isdir &= (access(path, W_OK) == 0);#endif}return isdir;}#elsestatic int isDir(char *path){return 1;}#endif /* HAVE_STAT */#if !HAVE_DECL_MKDTEMPextern char * mkdtemp (char *template);#endif#ifdef Win32# include <ctype.h>#endifvoid attribute_hidden InitTempDir(){char *tmp, *tm, tmp1[PATH_MAX+11], *p;int len;#ifdef Win32char tmp2[PATH_MAX];int hasspace = 0;#endifif(R_TempDir) return; /* someone else set it */tmp = NULL; /* getenv("R_SESSION_TMPDIR"); no longer set in R.sh */if (!tmp) {tm = getenv("TMPDIR");if (!isDir(tm)) {tm = getenv("TMP");if (!isDir(tm)) {tm = getenv("TEMP");if (!isDir(tm))#ifdef Win32tm = getenv("R_USER"); /* this one will succeed */#elsetm = "/tmp";#endif}}#ifdef Win32/* make sure no spaces in path */for (p = tm; *p; p++)if (isspace(*p)) { hasspace = 1; break; }if (hasspace) {GetShortPathName(tm, tmp2, MAX_PATH);tm = tmp2;}sprintf(tmp1, "%s\\RtmpXXXXXX", tm);#elsesprintf(tmp1, "%s/RtmpXXXXXX", tm);#endiftmp = mkdtemp(tmp1);if(!tmp) R_Suicide(_("cannot mkdir R_TempDir"));#ifndef Win32# ifdef HAVE_SETENVif(setenv("R_SESSION_TMPDIR", tmp, 1))errorcall(R_NilValue, _("unable to set R_SESSION_TMPDIR"));# elif defined(HAVE_PUTENV){char * buf = (char *) malloc((strlen(tmp) + 20) * sizeof(char));if(buf) {sprintf(buf, "R_SESSION_TMPDIR=%s", tmp);if(putenv(buf))errorcall(R_NilValue, _("unable to set R_SESSION_TMPDIR"));/* no free here: storage remains in use */} elseerrorcall(R_NilValue, _("unable to set R_SESSION_TMPDIR"));}# endif#endif}len = strlen(tmp) + 1;p = (char *) malloc(len);if(!p)R_Suicide(_("cannot allocate R_TempDir"));else {R_TempDir = p;strcpy(R_TempDir, tmp);Sys_TempDir = R_TempDir;}}char * R_tmpnam(const char * prefix, const char * tempdir){return R_tmpnam2(prefix, tempdir, "");}/* NB for use with multicore: parent and all children share the samesession directory and run in parallel.So as from 2.14.1, we make sure getpic() is part of the process.*/char * R_tmpnam2(const char *prefix, const char *tempdir, const char *fileext){char tm[PATH_MAX], *res;unsigned int n, done = 0, pid = getpid();#ifdef Win32char filesep[] = "\\";#elsechar filesep[] = "/";#endifif(!prefix) prefix = ""; /* NULL */if(!fileext) fileext = ""; /* " */#if RAND_MAX > 16777215#define RAND_WIDTH 8#else#define RAND_WIDTH 12#endifif(strlen(tempdir) + 1 + strlen(prefix) + RAND_WIDTH + strlen(fileext) >= PATH_MAX)error(_("temporary name too long"));for (n = 0; n < 100; n++) {/* try a random number at the end. Need at least 6 hex digits */#if RAND_MAX > 16777215snprintf(tm, PATH_MAX, "%s%s%s%x%x%s", tempdir, filesep, prefix, pid, rand(), fileext);#elsesnprintf(tm, PATH_MAX, "%s%s%s%x%x%x%s", tempdir, filesep, prefix, pid, rand(), rand(), fileext);#endifif(!R_FileExists(tm)) {done = 1;break;}}if(!done)error(_("cannot find unused tempfile name"));res = (char *) malloc((strlen(tm)+1) * sizeof(char));if(!res)error(_("allocation failed in R_tmpnam2"));strcpy(res, tm);return res;}SEXP attribute_hidden do_proctime(SEXP call, SEXP op, SEXP args, SEXP env){SEXP ans, nm;checkArity(op, args);PROTECT(ans = allocVector(REALSXP, 5));PROTECT(nm = allocVector(STRSXP, 5));R_getProcTime(REAL(ans));SET_STRING_ELT(nm, 0, mkChar("user.self"));SET_STRING_ELT(nm, 1, mkChar("sys.self"));SET_STRING_ELT(nm, 2, mkChar("elapsed"));SET_STRING_ELT(nm, 3, mkChar("user.child"));SET_STRING_ELT(nm, 4, mkChar("sys.child"));setAttrib(ans, R_NamesSymbol, nm);setAttrib(ans, R_ClassSymbol, mkString("proc_time"));UNPROTECT(2);return ans;}void attribute_hidden resetTimeLimits(){double data[5];R_getProcTime(data);elapsedLimit = (elapsedLimitValue > 0) ? data[2] + elapsedLimitValue : -1.0;if (elapsedLimit2 > 0.0 &&(elapsedLimit <= 0.0 || elapsedLimit2 < elapsedLimit))elapsedLimit = elapsedLimit2;#ifdef Win32cpuLimit = (cpuLimitValue > 0) ? data[0] + data[1] + cpuLimitValue : -1.0;#elsecpuLimit = (cpuLimitValue > 0) ? data[0] + data[1] + data[3] + data[4] + cpuLimitValue : -1.0;#endifif (cpuLimit2 > 0.0 && (cpuLimit <= 0.0 || cpuLimit2 < cpuLimit))cpuLimit = cpuLimit2;}SEXP attribute_hiddendo_setTimeLimit(SEXP call, SEXP op, SEXP args, SEXP rho){double cpu, elapsed, old_cpu = cpuLimitValue,old_elapsed = elapsedLimitValue;int transient;checkArity(op, args);cpu = asReal(CAR(args));elapsed = asReal(CADR(args));transient = asLogical(CADDR(args));if (R_FINITE(cpu) && cpu > 0) cpuLimitValue = cpu; else cpuLimitValue = -1;if (R_FINITE(elapsed) && elapsed > 0) elapsedLimitValue = elapsed;else elapsedLimitValue = -1;resetTimeLimits();if (transient == TRUE) {cpuLimitValue = old_cpu;elapsedLimitValue = old_elapsed;}return R_NilValue;}SEXP attribute_hiddendo_setSessionTimeLimit(SEXP call, SEXP op, SEXP args, SEXP rho){double cpu, elapsed, data[5];checkArity(op, args);cpu = asReal(CAR(args));elapsed = asReal(CADR(args));R_getProcTime(data);if (R_FINITE(cpu) && cpu > 0)#ifdef Win32cpuLimit2 = cpu + data[0] + data[1];#elsecpuLimit2 = cpu + data[0] + data[1] + data[3] + data[4];#endifelse cpuLimit2 = -1;if (R_FINITE(elapsed) && elapsed > 0) elapsedLimit2 = elapsed + data[2];else elapsedLimit2 = -1;return R_NilValue;}/* moved from character.c in 2.10.0: configure requires this */#ifdef HAVE_GLOB_H# include <glob.h>#endif#ifdef Win32# include <dos_wglob.h># define globfree dos_wglobfree# define glob_t wglob_t#else# ifndef GLOB_QUOTE# define GLOB_QUOTE 0# endif#endifSEXP attribute_hidden do_glob(SEXP call, SEXP op, SEXP args, SEXP env){SEXP x, ans;int i, n, res, dirmark;glob_t globbuf;#ifdef Win32R_StringBuffer cbuff = {NULL, 0, MAXELTSIZE};#endifcheckArity(op, args);if (!isString(x = CAR(args)))error(_("invalid '%s' argument"), "paths");if (!LENGTH(x)) return allocVector(STRSXP, 0);dirmark = asLogical(CADR(args));if (dirmark == NA_LOGICAL)error(_("invalid '%s' argument"), "dirmark");#ifndef GLOB_MARKif (dirmark)error(_("'dirmark = TRUE' is not supported on this platform"));#endiffor (i = 0; i < LENGTH(x); i++) {SEXP el = STRING_ELT(x, i);if (el == NA_STRING) continue;#ifdef Win32res = dos_wglob(filenameToWchar(el, FALSE),(dirmark ? GLOB_MARK : 0) |GLOB_QUOTE | (i ? GLOB_APPEND : 0),NULL, &globbuf);if (res == GLOB_NOSPACE)error(_("internal out-of-memory condition"));#elseres = glob(translateChar(el),# ifdef GLOB_MARK(dirmark ? GLOB_MARK : 0) |# endifGLOB_QUOTE | (i ? GLOB_APPEND : 0),NULL, &globbuf);# ifdef GLOB_ABORTEDif (res == GLOB_ABORTED)warning(_("read error on '%s'"), translateChar(el));# endif# ifdef GLOB_NOSPACEif (res == GLOB_NOSPACE)error(_("internal out-of-memory condition"));# endif#endif}n = globbuf.gl_pathc;PROTECT(ans = allocVector(STRSXP, n));for (i = 0; i < n; i++)#ifdef Win32{wchar_t *w = globbuf.gl_pathv[i];char *buf;int nb = wcstoutf8(NULL, w, 0);buf = R_AllocStringBuffer(nb+1, &cbuff);wcstoutf8(buf, w, nb+1); buf[nb] = '\0'; /* safety check */SET_STRING_ELT(ans, i, mkCharCE(buf, CE_UTF8));}#elseSET_STRING_ELT(ans, i, mkChar(globbuf.gl_pathv[i]));#endifUNPROTECT(1);#ifdef Win32R_FreeStringBufferL(&cbuff);#endifglobfree(&globbuf);return ans;}