blob: 4aa1ac7136a83829e90620835689acf3751ffd02 [file] [log] [blame]
# File src/library/utils/R/write.table.R
# Part of the R package, https://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
# https://www.R-project.org/Licenses/
write.table <-
function (x, file = "", append = FALSE, quote = TRUE, sep = " ",
eol = "\n", na = "NA", dec = ".", row.names = TRUE,
col.names = TRUE, qmethod = c("escape", "double"),
fileEncoding = "")
{
qmethod <- match.arg(qmethod)
if(is.logical(quote) && (length(quote) != 1L || is.na(quote)))
stop("'quote' must be 'TRUE', 'FALSE' or numeric")
## quote column names unless quote == FALSE (see help).
quoteC <- if(is.logical(quote)) quote else TRUE
qset <- is.logical(quote) && quote
if(!is.data.frame(x) && !is.matrix(x)) x <- data.frame(x)
makeRownames <- isTRUE(row.names)
## need col names if col.names is TRUE or NA
makeColnames <- is.logical(col.names) && !identical(FALSE, col.names)
if(is.matrix(x)) {
## fix up dimnames as as.data.frame would
p <- ncol(x)
d <- dimnames(x)
if(is.null(d)) d <- list(NULL, NULL)
if(is.null(d[[1L]]) && makeRownames) d[[1L]] <- seq_len(nrow(x))
if(is.null(d[[2L]]) && makeColnames && p > 0L)
d[[2L]] <- paste0("V", 1L:p)
if(qset)
quote <- if(is.character(x)) seq_len(p) else numeric()
} else { ## data.frame
if(qset)
quote <- if(length(x))
which(unlist(lapply(x, function(x)
is.character(x) || is.factor(x))))
else numeric()
## fix up embedded matrix columns into separate cols:
if(any(vapply(x,
function(z)
length(dim(z)) == 2 && dim(z)[2L] > 1,
NA))) {
c1 <- names(x)
x <- as.matrix(x, rownames.force = makeRownames)
d <- dimnames(x)
if(qset) {
ord <- match(c1, d[[2L]], 0L)
quote <- ord[quote]; quote <- quote[quote > 0L]
}
}
else
d <- list(if(makeRownames) row.names(x),
if(makeColnames) names(x))
p <- ncol(x)
}
nocols <- p == 0L
if(is.logical(quote)) # must be false
quote <- NULL
else if(is.numeric(quote)) {
if(any(quote < 1L | quote > p))
stop("invalid numbers in 'quote'")
} else
stop("invalid 'quote' specification")
rn <- FALSE
rnames <- NULL
if(is.logical(row.names)) {
if(row.names) {rnames <- as.character(d[[1L]]); rn <- TRUE}
} else {
rnames <- as.character(row.names)
rn <- TRUE
if(length(rnames) != nrow(x))
stop("invalid 'row.names' specification")
}
if(!is.null(quote) && rn) # quote the row names
quote <- c(0, quote)
if(is.logical(col.names)) {
if(!rn && is.na(col.names))
stop("'col.names = NA' makes no sense when 'row.names = FALSE'")
col.names <- if(is.na(col.names) && rn) c("", d[[2L]])
else if(col.names) d[[2L]] else NULL
} else {
col.names <- as.character(col.names)
if(length(col.names) != p)
stop("invalid 'col.names' specification")
}
if(file == "") file <- stdout()
else if(is.character(file)) {
file <- if(nzchar(fileEncoding))
file(file, ifelse(append, "a", "w"), encoding = fileEncoding)
else file(file, ifelse(append, "a", "w"))
on.exit(close(file))
} else if(!isOpen(file, "w")) {
open(file, "w")
on.exit(close(file))
}
if(!inherits(file, "connection"))
stop("'file' must be a character string or connection")
qstring <- # quoted embedded quote string
switch(qmethod,
"escape" = '\\\\"',
"double" = '""')
if(!is.null(col.names)) {
if(append)
warning("appending column names to file")
if(quoteC)
col.names <- paste0("\"", gsub('"', qstring, col.names),
"\"")
writeLines(paste(col.names, collapse = sep), file, sep = eol)
}
if (nrow(x) == 0L) return(invisible())
if (nocols && !rn) return(cat(rep.int(eol, NROW(x)), file=file, sep=""))
## convert list matrices to character - maybe not much use?
if(is.matrix(x) && !is.atomic(x)) mode(x) <- "character"
if(is.data.frame(x)) {
## convert columns we can't handle in C code
x[] <- lapply(x, function(z) {
if(is.object(z) && !is.factor(z)) as.character(z) else z
})
}
invisible(.External2(C_writetable, x, file, nrow(x), p, rnames, sep, eol,
na, dec, as.integer(quote), qmethod != "double"))
}
write.csv <- function(...)
{
Call <- match.call(expand.dots = TRUE)
for(argname in c("append", "col.names", "sep", "dec", "qmethod"))
if(!is.null(Call[[argname]]))
warning(gettextf("attempt to set '%s' ignored", argname),
domain = NA)
rn <- eval.parent(Call$row.names)
Call$append <- NULL
Call$col.names <- if(is.logical(rn) && !rn) TRUE else NA
Call$sep <- ","
Call$dec <- "."
Call$qmethod <- "double"
Call[[1L]] <- as.name("write.table")
eval.parent(Call)
}
write.csv2 <- function(...)
{
Call <- match.call(expand.dots = TRUE)
for(argname in c("append", "col.names", "sep", "dec", "qmethod"))
if(!is.null(Call[[argname]]))
warning(gettextf("attempt to set '%s' ignored", argname),
domain = NA)
rn <- eval.parent(Call$row.names)
Call$append <- NULL
Call$col.names <- if(is.logical(rn) && !rn) TRUE else NA
Call$sep <- ";"
Call$dec <- ","
Call$qmethod <- "double"
Call[[1L]] <- as.name("write.table")
eval.parent(Call)
}