Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@

4. `rowwiseDT()` now provides a helpful error message when a complex object that is not a list (e.g., a function) is provided as a cell value, instructing the user to wrap it in `list()`, [#7219](https://github.com/Rdatatable/data.table/issues/7219). Thanks @kylebutts for the report and @venom1204 for the fix.

5. `fread()` now recognizes Windows clipboard tokens such as `clipboard`, avoiding shell execution failures, [#1292](https://github.com/Rdatatable/data.table/issues/1292). Thanks @mbacou for the report and @AmanKashyap0807 for the fix.

### Notes

1. {data.table} now depends on R 3.5.0 (2018).
Expand Down
15 changes: 15 additions & 0 deletions R/fread.R
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,21 @@ yaml=FALSE, tmpdir=tempdir(), tz="UTC")
# input is data itself containing at least one \n or \r
} else if (startsWith(input, " ")) {
stopf("input= contains no \\n or \\r, but starts with a space. Please remove the leading space, or use text=, file= or cmd=")
} else if (grepl("^clipboard(-[0-9]+)?$", tolower(input))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we use grepl here and not simply only read from clipboard when the input is clipboard?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used regex to consider both 'clipboard' and 'clipboard-128' because original issue #1292 shows the user trying fread('clipboard-128').
However your point is valid, since readClipboard() takes no argument and only read clipboard regardless of any suffix so we can use simple string matching.
but the user who are used to base R's read.delim('clipboard-128') syntax would have to use 'clipboard'. let me know if u want the change I will do it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Windows, R's own clipboard connections can be opened with the description clipboard-<buffer size> in order to set the size limit for writing. It's not needed to read the clipboard. On Unix, X11_primary, X11_secondary, X11_clipboard are also supported. We don't have to support anything except clipboard.

is_windows = identical(.Platform$OS.type, "windows")
if (is_windows) {
# for errors due to permissions, clipboard locked or system errors
clip = tryCatch(utils::readClipboard(),
error = function(e) stopf("Reading clipboard failed on Windows: %s", conditionMessage(e))
)
if (!length(clip) || !any(nzchar(trimws(clip)))) {
stopf("Clipboard is empty.")
}
input = paste(clip, collapse="\n")
} else {
# Note: macOS (pbpaste) and Linux (xclip/xsel) support discussed in #1292
stopf("Clipboard reading is supported on Windows only.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder if we must stopf here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the explicit error to avoid this potentially confusing behavior on non-Windows systems.
I tested this by commenting out else-stopf() block on Ubuntu 20.04 (WSL). In that case, fread("clipboard") falls through and returns:

> temp <- fread("clipboard")
> print(temp)
Empty data.table (0 rows and 1 cols): clipboard

That said, if preserving the current fallback behavior is preferred for compatibility, I’m happy to remove the stopf() and let the normal control flow continue.

}
} else if (length(grep(' ', input, fixed=TRUE)) && !file.exists(gsub("^file://", "", input))) { # file name or path containing spaces is not a command. file.exists() doesn't understand file:// (#7550)
cmd = input
if (input_has_vars && getOption("datatable.fread.input.cmd.message", TRUE)) {
Expand Down
8 changes: 8 additions & 0 deletions inst/tests/tests.Rraw
Original file line number Diff line number Diff line change
Expand Up @@ -21515,3 +21515,11 @@ test(2365.1, melt(df_melt, id.vars=1:2), melt(dt_melt, id.vars=1:2))
df_dcast = data.frame(a = c("x", "y"), b = 1:2, v = 3:4)
dt_dcast = data.table(a = c("x", "y"), b = 1:2, v = 3:4)
test(2365.2, dcast(df_dcast, a ~ b, value.var = "v"), dcast(dt_dcast, a ~ b, value.var = "v"))

# Test fread clipboard input on Windows (issue #1292)
if (.Platform$OS.type == "windows") local({
temp <- c("a\tb", "1\t2")
utils::writeClipboard(temp)
on.exit(utils::writeClipboard(""), add = TRUE)
test(2366, fread("clipboard-128"), data.table(a = 1L, b = 2L))
})
Loading