blob: 411e23df7de5f91168ace7c0456ea71931807ea8 [file] [log] [blame]
# File src/library/base/R/attach.R
# Part of the R package, https://www.R-project.org
#
# Copyright (C) 1995-2017 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/
## Abstraction for "The fastest way" to do this [no if(), no substr(), ...],
## to be used in many places:
.rmpkg <- function(pkg) sub("package:", "", pkg, fixed=TRUE)
## also used by library() :
.maskedMsg <- function(same, pkg, by) {
objs <- strwrap(paste(same, collapse=", "), indent = 4L, exdent = 4L)
txt <- if(by) {
ngettext(length(same),
"The following object is masked _by_ %s:\n\n%s\n",
"The following objects are masked _by_ %s:\n\n%s\n")
} else {
ngettext(length(same),
"The following object is masked from %s:\n\n%s\n",
"The following objects are masked from %s:\n\n%s\n")
}
sprintf(txt, pkg, paste(objs, collapse="\n"))
}
attach <- function(what, pos = 2L, name = deparse(substitute(what), backtick=FALSE),
warn.conflicts = TRUE)
{
## FIXME: ./library.R 's library() has *very* similar checkConflicts(), keep in sync
checkConflicts <- function(env)
{
dont.mind <- c("last.dump", "last.warning", ".Last.value",
".Random.seed", ".Last.lib", ".onDetach",
".packageName", ".noGenerics", ".required",
".no_S3_generics", ".requireCachedGenerics")
sp <- search()
for (i in seq_along(sp)) {
if (identical(env, as.environment(i))) {
db.pos <- i
break
}
}
ob <- names(as.environment(db.pos))
if(.isMethodsDispatchOn()) { ## {see note in library() about this}
these <- ob[startsWith(ob,".__T__")]
gen <- gsub(".__T__(.*):([^:]+)", "\\1", these)
from <- gsub(".__T__(.*):([^:]+)", "\\2", these)
gen <- gen[from != ".GlobalEnv"]
ob <- ob[!(ob %in% gen)]
}
ipos <- seq_along(sp)[-c(db.pos, match(c("Autoloads", "CheckExEnv"), sp, 0L))]
for (i in ipos) {
obj.same <- match(names(as.environment(i)), ob, nomatch = 0L)
if (any(obj.same > 0L)) {
same <- ob[obj.same]
same <- same[!(same %in% dont.mind)]
Classobjs <- which(startsWith(same,".__"))
if(length(Classobjs)) same <- same[-Classobjs]
## report only objects which are both functions or
## both non-functions.
same.isFn <- function(where)
vapply(same, exists, NA,
where = where, mode = "function", inherits = FALSE)
same <- same[same.isFn(i) == same.isFn(db.pos)]
if(length(same)) {
pkg <- if (sum(sp == sp[i]) > 1L) # 'pos = *' needs no translation
sprintf("%s (pos = %d)", sp[i], i) else sp[i]
message(.maskedMsg(sort(same), pkg, by = i < db.pos),
domain = NA)
}
}
}
}
if(pos == 1L)
stop("'pos=1' is not possible and has been warned about for years")
if (is.character(what) && (length(what) == 1L)){
if (!file.exists(what))
stop(gettextf("file '%s' not found", what), domain = NA)
if(missing(name)) name <- paste0("file:", what)
value <- .Internal(attach(NULL, pos, name))
load(what, envir = as.environment(pos))
}
else
value <- .Internal(attach(what, pos, name))
if(warn.conflicts &&
!exists(".conflicts.OK", envir = value, inherits = FALSE)) {
checkConflicts(value)
}
if (length(names(value)) && .isMethodsDispatchOn() )
methods::cacheMetaData(value, TRUE)
invisible(value)
}
detach <- function(name, pos = 2L, unload = FALSE, character.only = FALSE,
force = FALSE)
{
if(!missing(name)) {
if(!character.only) name <- substitute(name)
pos <-
if(is.numeric(name)) name
else {
if (!is.character(name)) name <- deparse(name)
match(name, search())
}
if(is.na(pos)) stop("invalid 'name' argument")
}
packageName <- search()[[pos]]
## we need to treat packages differently from other objects, so get those
## out of the way now
if (!startsWith(packageName, "package:"))
return(invisible(.Internal(detach(pos))))
## From here down we are detaching a package.
pkgname <- .rmpkg(packageName)
for(pkg in search()[-1L]) {
if(startsWith(pkg, "package:") &&
exists(".Depends", pkg, inherits = FALSE) &&
pkgname %in% get(".Depends", pkg, inherits = FALSE))
if(force)
warning(gettextf("package %s is required by %s, which may no longer work correctly",
sQuote(pkgname), sQuote(.rmpkg(pkg))),
call. = FALSE, domain = NA)
else
stop(gettextf("package %s is required by %s so will not be detached",
sQuote(pkgname), sQuote(.rmpkg(pkg))),
call. = FALSE, domain = NA)
}
env <- as.environment(pos)
libpath <- attr(env, "path")
hook <- getHook(packageEvent(pkgname, "detach")) # might be a list
for(fun in rev(hook)) try(fun(pkgname, libpath))
## some people, e.g. package g.data, have faked pakages without namespaces
ns <- .getNamespace(pkgname)
if(!is.null(ns) &&
exists(".onDetach", mode = "function", where = ns, inherits = FALSE)) {
.onDetach <- get(".onDetach", mode = "function", pos = ns,
inherits = FALSE)
if(!is.null(libpath)) {
res <- tryCatch(.onDetach(libpath), error = identity)
if (inherits(res, "error")) {
warning(gettextf("%s failed in %s() for '%s', details:\n call: %s\n error: %s",
".onDetach", "detach", pkgname,
deparse(conditionCall(res))[1L],
conditionMessage(res)),
call. = FALSE, domain = NA)
}
}
}
else if(exists(".Last.lib", mode = "function", where = pos, inherits = FALSE)) {
.Last.lib <- get(".Last.lib", mode = "function", pos = pos,
inherits = FALSE)
if(!is.null(libpath)) {
res <- tryCatch(.Last.lib(libpath), error = identity)
if (inherits(res, "error")) {
warning(gettextf("%s failed in %s() for '%s', details:\n call: %s\n error: %s",
".Last.lib", "detach", pkgname,
deparse(conditionCall(res))[1L],
conditionMessage(res)),
call. = FALSE, domain = NA)
}
}
}
.Internal(detach(pos))
if(isNamespaceLoaded(pkgname)) {
## the lazyload DB is flushed when the namespace is unloaded
if(unload) {
tryCatch(unloadNamespace(pkgname),
error = function(e)
warning(gettextf("%s namespace cannot be unloaded:\n ",
sQuote(pkgname)),
conditionMessage(e),
call. = FALSE, domain = NA))
}
} else {
if(.isMethodsDispatchOn() && methods:::.hasS4MetaData(env))
methods::cacheMetaData(env, FALSE)
.Internal(lazyLoadDBflush(paste0(libpath, "/R/", pkgname, ".rdb")))
}
invisible()
}
.detach <- function(pos) .Internal(detach(pos))
ls <- objects <-
function (name, pos = -1L, envir = as.environment(pos), all.names = FALSE,
pattern, sorted = TRUE)
{
if (!missing(name)) {
pos <- tryCatch(name, error = function(e)e)
if(inherits(pos, "error")) {
name <- substitute(name)
if (!is.character(name))
name <- deparse(name)
warning(gettextf("%s converted to character string", sQuote(name)),
domain = NA)
pos <- name
}
}
all.names <- .Internal(ls(envir, all.names, sorted))
if (!missing(pattern)) {
if ((ll <- length(grep("[", pattern, fixed = TRUE))) &&
ll != length(grep("]", pattern, fixed = TRUE))) {
if (pattern == "[") {
pattern <- "\\["
warning("replaced regular expression pattern '[' by '\\\\['")
}
else if (length(grep("[^\\\\]\\[<-", pattern))) {
pattern <- sub("\\[<-", "\\\\\\[<-", pattern)
warning("replaced '[<-' by '\\\\[<-' in regular expression pattern")
}
}
grep(pattern, all.names, value = TRUE)
}
else all.names
}