diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java index ca5a98df978e07a5cbfb2019a7da2c16b8f8332d..a0e56cb066f756ff4fc053633336045b14e550f1 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/FileFunctions.java @@ -38,6 +38,7 @@ import com.oracle.truffle.r.nodes.builtin.*; import com.oracle.truffle.r.runtime.*; import com.oracle.truffle.r.runtime.data.*; import com.oracle.truffle.r.runtime.data.model.*; +import com.oracle.truffle.r.runtime.ffi.*; public class FileFunctions { @@ -487,4 +488,31 @@ public class FileFunctions { return doXyzName(vec, basePathFunction); } } + + @RBuiltin(name = "dir.create", kind = INTERNAL, parameterNames = {"path", "showWarnings", "recursive", "mode"}) + public abstract static class DirCreate extends RInvisibleBuiltinNode { + @TruffleBoundary + @Specialization + protected byte dirCreate(RAbstractStringVector pathVec, byte showWarnings, byte recursive, RIntVector octMode) { + controlVisibility(); + boolean ok = true; + if (pathVec.getLength() != 1) { + throw RError.error(getEncapsulatingSourceSection(), RError.Message.INVALID_ARGUMENT, "path"); + } + String path = Utils.tildeExpand(pathVec.getDataAt(0)); + if (RRuntime.fromLogical(recursive)) { + throw RError.nyi(getEncapsulatingSourceSection(), "recursive create"); + } else { + try { + RFFIFactory.getRFFI().getBaseRFFI().mkdir(path, octMode.getDataAt(0)); + } catch (IOException ex) { + if (RRuntime.fromLogical(showWarnings)) { + RContext.getInstance().setEvalWarning("cannot create dir '" + pathVec.getDataAt(0) + "'"); + } + ok = false; + } + } + return RRuntime.asLogical(ok); + } + } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/R/character.R b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/R/character.R index b49ea5aac52f51310ba616bd1848d281f187c88b..c5f6904a3440d1f0b8a6956f7b10916dc888da9a 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/R/character.R +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/R/character.R @@ -189,6 +189,6 @@ sQuote <- function(x) # paste0(before, x, after) #} # -#strtoi <- -# function(x, base = 0L) -# .Internal(strtoi(as.character(x), as.integer(base))) +strtoi <- + function(x, base = 0L) + .Internal(strtoi(as.character(x), as.integer(base))) diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/R/octhex.R b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/R/octhex.R new file mode 100644 index 0000000000000000000000000000000000000000..bf4f3b8b14bcf485e19685f4d8957b7a0e5a4a15 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/R/octhex.R @@ -0,0 +1,127 @@ +# File src/library/base/R/octhex.R +# Part of the R package, http://www.R-project.org +# +# Copyright (C) 1995-2012 The R 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. +# +# A copy of the GNU General Public License is available at +# http://www.r-project.org/Licenses/ + +format.octmode <- function(x, width = NULL, ...) +{ + isna <- is.na(x) + y <- as.integer(x[!isna]) + fmt <- if(!is.null(width)) paste0("%0", width, "o") else "%o" + ans <- rep.int(NA_character_, length(x)) + ans0 <- sprintf(fmt, y) + if(is.null(width) && length(y) > 1L) { + ## previous version padded with zeroes to a common field width + nc <- max(nchar(ans0)) + ans0 <- sprintf(paste0("%0", nc, "o"), y) + } + ans[!isna] <- ans0 + dim(ans) <- dim(x) + dimnames(ans) <- dimnames(x) + names(ans) <- names(x) + ans +} + +as.character.octmode <- function(x, ...) format.octmode(x, ...) + +print.octmode <- function(x, ...) +{ + print(format(x), ...) + invisible(x) +} + +`[.octmode` <- function (x, i) +{ + cl <- oldClass(x) + y <- NextMethod("[") + oldClass(y) <- cl + y +} + +as.octmode <- function(x) +{ + if(inherits(x, "octmode")) return(x) + if(is.double(x) && x == as.integer(x)) x <- as.integer(x) + if(is.integer(x)) return(structure(x, class="octmode")) + if(is.character(x)) { + z <- strtoi(x, 8L) + if(!any(is.na(z) | z < 0)) return(structure(z, class="octmode")) + } + stop("'x' cannot be coerced to class \"octmode\"") +} + +## BioC packages cellHTS2 and flowCore misuse this for doubles, +## hence the as.integer() call +format.hexmode <- function(x, width = NULL, upper.case = FALSE, ...) +{ + isna <- is.na(x) + y <- as.integer(x[!isna]) + fmt0 <- if(upper.case) "X" else "x" + fmt <- if(!is.null(width)) paste0("%0", width, fmt0) else paste0("%", fmt0) + ans <- rep.int(NA_character_, length(x)) + ans0 <- sprintf(fmt, y) + if(is.null(width) && length(y) > 1L) { + ## previous version padded with zeroes to a common field width + nc <- max(nchar(ans0)) + ans0 <- sprintf(paste0("%0", nc, fmt0), y) + } + ans[!isna] <- ans0 + dim(ans) <- dim(x) + dimnames(ans) <- dimnames(x) + names(ans) <- names(x) + ans +} + +as.character.hexmode <- function(x, ...) format.hexmode(x, ...) + +print.hexmode <- function(x, ...) +{ + print(format(x), ...) + invisible(x) +} + +`[.hexmode` <- function (x, i) +{ + cl <- oldClass(x) + y <- NextMethod("[") + oldClass(y) <- cl + y +} + +as.hexmode <- function(x) +{ + if(inherits(x, "hexmode")) return(x) + if(is.double(x) && (x == as.integer(x))) x <- as.integer(x) + if(is.integer(x)) return(structure(x, class = "hexmode")) + if(is.character(x)) { + z <- strtoi(x, 16L) + if(!any(is.na(z) | z < 0)) return(structure(z, class = "hexmode")) + } + stop("'x' cannot be coerced to class \"hexmode\"") +} + + +`!.octmode` <- function(a) as.octmode(bitwNot(as.octmode(a))) + +`&.octmode` <- function(a, b) as.octmode(bitwAnd(as.octmode(a), as.octmode(b))) +`|.octmode` <- function(a, b) as.octmode(bitwOr(as.octmode(a), as.octmode(b))) +xor.octmode <- function(a, b) as.octmode(bitwXor(as.octmode(a), as.octmode(b))) + +`!.hexmode` <- function(a) as.hexmode(bitwNot(as.hexmode(a))) + +`&.hexmode` <- function(a, b) as.hexmode(bitwAnd(as.hexmode(a), as.hexmode(b))) +`|.hexmode` <- function(a, b) as.hexmode(bitwOr(as.hexmode(a), as.hexmode(b))) +xor.hexmode <- function(a, b) as.hexmode(bitwXor(as.hexmode(a), as.hexmode(b))) diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtoi.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtoi.java new file mode 100644 index 0000000000000000000000000000000000000000..968f323d7cb2f34e0e36318408029478a5a3aacb --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Strtoi.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.nodes.builtin.base; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.r.nodes.builtin.*; +import com.oracle.truffle.r.runtime.*; +import com.oracle.truffle.r.runtime.data.*; +import com.oracle.truffle.r.runtime.data.model.*; +import com.oracle.truffle.r.runtime.ffi.*; + +@RBuiltin(name = "strtoi", kind = RBuiltinKind.INTERNAL, parameterNames = {"x", "base"}) +public abstract class Strtoi extends RBuiltinNode { + @TruffleBoundary + @Specialization + protected RIntVector doStrtoi(RAbstractStringVector vec, int baseArg) { + int base = baseArg; + int[] data = new int[vec.getLength()]; + boolean complete = RDataFactory.COMPLETE_VECTOR; + for (int i = 0; i < data.length; i++) { + int dataValue = RRuntime.INT_NA; + try { + String s = vec.getDataAt(i); + if (s.length() == 0) { + complete = RDataFactory.INCOMPLETE_VECTOR; + } else { + if (base == 0) { + char ch0 = s.charAt(0); + if (ch0 == '0') { + if (s.length() > 1 && (s.charAt(1) == 'x' || s.charAt(1) == 'X')) { + base = 16; + } else { + base = 8; + } + } else { + base = 10; + } + } + long value = RFFIFactory.getRFFI().getBaseRFFI().strtol(s, base); + if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) { + complete = RDataFactory.INCOMPLETE_VECTOR; + } else { + dataValue = (int) value; + } + } + } catch (IllegalArgumentException ex) { + complete = RDataFactory.INCOMPLETE_VECTOR; + } + data[i] = dataValue; + } + return RDataFactory.createIntVector(data, complete); + } + +} diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/gnfi/GNFI_RFFIFactory.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/gnfi/GNFI_RFFIFactory.java index b574ed3fc36ba76e177bdf187226e88d9a67cc49..bc5608771aa4dd316533880c0257e2b16828da16 100644 --- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/gnfi/GNFI_RFFIFactory.java +++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/gnfi/GNFI_RFFIFactory.java @@ -139,7 +139,7 @@ public class GNFI_RFFIFactory extends RFFIFactory implements RFFI, BaseRFFI { return null; } else { // some other error - throw ioex(); + throw ioex(null); } } else { return CString.create(resultBuf.address, length, false); @@ -187,4 +187,13 @@ public class GNFI_RFFIFactory extends RFFIFactory implements RFFI, BaseRFFI { return 0; } + public void mkdir(String dir, int mode) throws IOException { + Utils.fail("mkdir not implemented"); + } + + public long strtol(String s, int base) throws IllegalArgumentException { + Utils.fail("strtol not implemented"); + return 0; + } + } diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java index c706d3175516eada57c038384cf3c66d66c8dffa..6af93ea3926be667bee2cfb1fd44b78f13f63071 100644 --- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java +++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/JNR_RFFIFactory.java @@ -61,6 +61,8 @@ public class JNR_RFFIFactory extends RFFIFactory implements RFFI, BaseRFFI, RDer int getcwd(@Out byte[] path); long mkdtemp(@In @Out ByteBuffer template); + + long strtol(@In String dir, @In String end, int base); } private static class LibCXProvider { @@ -127,7 +129,7 @@ public class JNR_RFFIFactory extends RFFIFactory implements RFFI, BaseRFFI, RDer // not a link } else { // some other error - throw ioex(); + throw ioex(Errno.valueOf(n).description()); } } return s; @@ -143,6 +145,25 @@ public class JNR_RFFIFactory extends RFFIFactory implements RFFI, BaseRFFI, RDer } } + public void mkdir(String dir, int mode) throws IOException { + try { + posix().mkdir(dir, mode); + } catch (RuntimeException ex) { + throw ioex(Errno.valueOf(posix().errno()).description()); + } + } + + public long strtol(String s, int base) throws IllegalArgumentException { + posix().errno(0); + long result = libcx().strtol(s, null, base); + int e = posix().errno(); + if (e != 0) { + throw new IllegalArgumentException(Errno.valueOf(e).description()); + } else { + return result; + } + } + public Object dlopen(String path, boolean local, boolean now) { int flags = (local ? com.kenai.jffi.Library.LOCAL : com.kenai.jffi.Library.GLOBAL) | (now ? com.kenai.jffi.Library.NOW : com.kenai.jffi.Library.LAZY); return com.kenai.jffi.Library.getCachedInstance(path, flags); @@ -631,4 +652,5 @@ public class JNR_RFFIFactory extends RFFIFactory implements RFFI, BaseRFFI, RDer public int uncompress(byte[] dest, long[] destlen, byte[] source) { return zip().uncompress(dest, destlen, source, source.length); } + } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java index 01d255ec9f3bda6a3576941602261859e71f019a..9773ffb566b7d0310194ddd3f6346172a4607793 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/BaseRFFI.java @@ -44,6 +44,11 @@ public interface BaseRFFI { */ int setwd(String dir); + /** + * Create directory with given mode. Exception is thrown omn error. + */ + void mkdir(String dir, int mode) throws IOException; + /** * Try to convert a symbolic link to it's target. * @@ -94,4 +99,9 @@ public interface BaseRFFI { */ int uncompress(byte[] dest, long[] destlen, byte[] source); + /** + * Convert string to long. + */ + long strtol(String s, int base) throws IllegalArgumentException; + } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java index be62aad8b1c6b78fde58a9d57bf678535eed5fd7..260708527272070f6ad9222020015118fde0ed41 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java @@ -82,8 +82,8 @@ public abstract class RFFIFactory { } @TruffleBoundary - protected static IOException ioex() throws IOException { - throw new IOException(); + protected static IOException ioex(String errMsg) throws IOException { + throw new IOException(errMsg); } }