### This file is part of the 'foreign' package for R. ### Copyright 2000-2001 (c) Nicholas Lewin-Koh ### Changes for foreign package (C) 2004 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. # # A copy of the GNU General Public License is available at # http://www.r-project.org/Licenses/ read.dbf <- function(file, as.is = FALSE) { df <- .Call(Rdbfread, as.character(path.expand(file))) onames <- names(df) inames <- make.names(onames, unique = TRUE) names(df) <- inames if (!(identical(onames, inames))) { for (i in seq_along(onames)) if (!(identical(onames[i], inames[i]))) message(gettextf("Field name: %s changed to: %s", sQuote(onames[i]), sQuote(inames[i])), domain = NA) } data_types <- attr(df, "data_types") for(i in seq_along(onames)) if(data_types[i] == "D") df[[i]] <- as.Date(df[[i]], format="%Y%m%d") if(!as.is) { df <- data.frame(lapply(df, function(x) if(is.character(x)) factor(x) else x)) attr(df, "data_types") <- data_types } df } ### assumes that all chars are single-byte write.dbf <- function(dataframe, file, factor2char = TRUE, max_nchar = 254) { ### need to check precision allowed_classes <- c("logical", "integer", "numeric", "character", "factor", "Date") if (!is.data.frame(dataframe)) dataframe <- as.data.frame(dataframe) if (any(vapply(dataframe, function(x) !is.null(dim(x)), NA))) stop("cannot handle matrix/array columns") cl <- vapply(dataframe, function(x) class(x[1L]), "") asis <- cl == "AsIs" cl[asis & vapply(dataframe, mode, '') == "character"] <- "character" if(length(cl0 <- setdiff(cl, allowed_classes))) stop(sprintf(ngettext(length(cl0), "data frame contains columns of unsupported class %s", "data frame contains columns of unsupported classes %s"), paste(dQuote(cl0), collapse = ",")), domain = NA) m <- ncol(dataframe) DataTypes <- c(logical="L", integer="N", numeric="F", character="C", factor=if(factor2char) "C" else "N", Date="D")[cl] for(i in seq_len(m)) { x <- dataframe[[i]] if(is.factor(x)) dataframe[[i]] <- if(factor2char) as.character(x) else as.integer(x) else if (inherits(x, "Date")) dataframe[[i]] <- format(x, "%Y%m%d") } precision <- integer(m) scale <- integer(m) dfnames <- names(dataframe) for (i in seq_len(m)) { nlen <- nchar(dfnames[i], "b") x <- dataframe[, i] if (is.logical(x)) { precision[i] <- 1L scale[i] <- 0L } else if (is.integer(x)) { rx <- range(x, na.rm = TRUE) rx[!is.finite(rx)] <- 0 # added RSB 2005-04-17 if (any(rx == 0)) rx <- rx + 1 # added RSB 2005-03-10 mrx <- as.integer(max(ceiling(log10(abs(rx))))+3L) precision[i] <- min(max(nlen, mrx), 19L) scale[i] <- 0L } else if (is.double(x)) { precision[i] <- 19L rx <- range(x, na.rm = TRUE) rx[!is.finite(rx)] <- 0 # added RSB 2005-04-17 mrx <- max(ceiling(log10(abs(rx)))) scale[i] <- min(precision[i] - ifelse(mrx > 0L, mrx+3L, 3L), 15L) # modified RSB 2005-03-10 and 2005-04-17 } else if (is.character(x)) { mf <- max(nchar(x[!is.na(x)], "b")) p <- max(nlen, mf) if(p > max_nchar) warning(gettextf("character column %d will be truncated to %d bytes", i, max_nchar), domain = NA) precision[i] <- min(p, max_nchar) scale[i] <- 0L } else stop("unknown column type in data frame") } if (anyNA(precision)) stop("NA in precision") # added RSB 2005-04-17 if (anyNA(scale)) stop("NA in scale") # added RSB 2005-04-17 invisible( .Call(DoWritedbf, as.character(file), dataframe, as.integer(precision), as.integer(scale), as.character(DataTypes))) }