brio/0000755000176200001440000000000014612255547011220 5ustar liggesusersbrio/NAMESPACE0000644000176200001440000000041414210502123012411 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(file_line_endings) export(readLines) export(read_file) export(read_file_raw) export(read_lines) export(writeLines) export(write_file) export(write_file_raw) export(write_lines) useDynLib(brio, .registration = TRUE) brio/LICENSE0000644000176200001440000000005214521176047012216 0ustar liggesusersYEAR: 2023 COPYRIGHT HOLDER: brio authors brio/README.md0000644000176200001440000000720114521176047012473 0ustar liggesusers # brio - Basic R Input Output [![Codecov test coverage](https://codecov.io/gh/r-lib/brio/branch/main/graph/badge.svg)](https://app.codecov.io/gh/r-lib/brio?branch=main) [![R-CMD-check](https://github.com/r-lib/brio/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-lib/brio/actions/workflows/R-CMD-check.yaml) Functions to handle basic input output, these functions always read and write UTF-8 files and provide more explicit control over line endings. ## Reading files ``` r library(brio) #> #> Attaching package: 'brio' #> The following objects are masked from 'package:base': #> #> readLines, writeLines write_lines(c("abc", "123"), "my-file") # Write with windows newlines write_lines(c("abc", "123"), "my-file-2", eol = "\r\n") file_line_endings("my-file") #> [1] "\n" file_line_endings("my-file-2") #> [1] "\r\n" read_lines("my-file") #> [1] "abc" "123" unlink(c("my-file", "my-file-2")) ``` ## Drop-ins brio also has `readLines()` and `writeLines()` functions drop-in replacements for `base::readLines()` and `base::writeLines()`. These functions are thin wrappers around `brio::read_lines()` and `brio::write_lines()`, with deliberately fewer features than the base equivalents. If you want to convert a package to using brio you can add the following line and re-document. ``` r #' @importFrom brio readLines writeLines ``` ## Benchmarks Speed is not necessarily a goal of brio, but it does end up being a nice side effect. ``` r gen_random <- function(characters, num_lines, min, max) { line_lengths <- sample.int(max - min, num_lines, replace = TRUE) + min vapply(line_lengths, function(len) paste(sample(characters, len, replace = TRUE), collapse = ""), character(1)) } set.seed(42) # generate 1000 random lines between 100-1000 characters long data <- gen_random(letters, 1000, min = 100, max = 1000) brio::write_lines(data, "benchmark") ``` ### Reading Reading speeds are a decent amount faster with brio, mainly due to larger block sizes and avoidance of extra copies. ``` r bench::mark( brio::read_lines("benchmark"), readr::read_lines("benchmark"), base::readLines("benchmark") ) #> # A tibble: 3 × 6 #> expression min median `itr/sec` mem_alloc `gc/sec` #> #> 1 brio::read_lines("benchmark") 886.62µs 891.11µs 1119. 8.05KB 0 #> 2 readr::read_lines("benchmark") 2.69ms 2.92ms 342. 12.72MB 19.7 #> 3 base::readLines("benchmark") 2.97ms 2.98ms 335. 31.39KB 0 ``` ### Writing Write speeds are basically the same regardless of method, though brio does avoid some extra memory allocations. ``` r bench::mark( brio::write_lines(data, "benchmark"), readr::write_lines(data, "benchmark"), base::writeLines(data, "benchmark"), check = FALSE ) #> # A tibble: 3 × 6 #> expression min median `itr/sec` mem_alloc #> #> 1 brio::write_lines(data, "benchmark") 496.02µs 518.1µs 1911. 0B #> 2 readr::write_lines(data, "benchmark") 7.16ms 7.61ms 111. 106KB #> 3 base::writeLines(data, "benchmark") 508.65µs 540.83µs 1809. 0B #> # … with 1 more variable: `gc/sec` unlink("benchmark") ``` ## Code of Conduct Please note that the brio project is released with a [Contributor Code of Conduct](https://brio.r-lib.org/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. brio/man/0000755000176200001440000000000014521176047011767 5ustar liggesusersbrio/man/readLines.Rd0000644000176200001440000000306114210415056014153 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/readLines.R \name{readLines} \alias{readLines} \title{Read text lines from a file} \usage{ readLines(con, n = -1, ok, warn, encoding, skipNul) } \arguments{ \item{con}{A character string of the path to a file. Throws an error if a connection object is passed.} \item{n}{integer. The number of lines to read. A negative number means read all the lines in the file.} \item{ok}{Ignored, with a warning.} \item{warn}{Ignored, with a warning.} \item{encoding}{Ignored, with a warning.} \item{skipNul}{Ignored, with a warning.} } \value{ A UTF-8 encoded character vector of the lines in the file. } \description{ This is a drop in replacement for \code{\link[base:readLines]{base::readLines()}} with restricted functionality. Compared to \code{\link[base:readLines]{base::readLines()}} it: \itemize{ \item Only works with file paths, not connections. \item Assumes the files are always UTF-8 encoded. \item Does not warn or skip embedded nulls, they will likely crash R. \item Does not warn if the file is missing the end of line character. \item The arguments \code{ok}, \code{warn}, \code{encoding} and \code{skipNul} are ignored, with a warning. } } \examples{ authors_file <- file.path(R.home("doc"), "AUTHORS") data <- readLines(authors_file) # Trying to use connections throws an error con <- file(authors_file) try(readLines(con)) close(con) # Trying to use unsupported args throws a warning data <- readLines(authors_file, encoding = "UTF-16") } \seealso{ \code{\link[=writeLines]{writeLines()}} } brio/man/brio-package.Rd0000644000176200001440000000154014521176047014602 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/brio-package.R \docType{package} \name{brio-package} \alias{brio} \alias{brio-package} \title{brio: Basic R Input Output} \description{ Functions to handle basic input output, these functions always read and write UTF-8 (8-bit Unicode Transformation Format) files and provide more explicit control over line endings. } \seealso{ Useful links: \itemize{ \item \url{https://brio.r-lib.org} \item \url{https://github.com/r-lib/brio} \item Report bugs at \url{https://github.com/r-lib/brio/issues} } } \author{ \strong{Maintainer}: Gábor Csárdi \email{csardi.gabor@gmail.com} Authors: \itemize{ \item Jim Hester (\href{https://orcid.org/0000-0002-2739-7082}{ORCID}) } Other contributors: \itemize{ \item Posit Software, PBC [copyright holder, funder] } } \keyword{internal} brio/man/writeLines.Rd0000644000176200001440000000251014210415056014370 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/writeLines.R \name{writeLines} \alias{writeLines} \title{Write lines to a file} \usage{ writeLines(text, con, sep = "\\n", useBytes) } \arguments{ \item{text}{A character vector to write} \item{con}{A character string of the path to a file. Throws an error if a connection object is passed.} \item{sep}{The end of line characters to use between lines.} \item{useBytes}{Ignored, with a warning.} } \value{ The UTF-8 encoded input text (invisibly). } \description{ This is a drop in replacement for \code{\link[base:writeLines]{base::writeLines()}} with restricted functionality. Compared to \code{\link[base:writeLines]{base::writeLines()}} it: \itemize{ \item Only works with file paths, not connections. \item Uses \code{\link[=enc2utf8]{enc2utf8()}} to convert \code{text()} to UTF-8 before writing. \item Uses \code{sep} unconditionally as the line ending, regardless of platform. \item The \code{useBytes} argument is ignored, with a warning. } } \examples{ tf <- tempfile() writeLines(rownames(mtcars), tf) # Trying to use connections throws an error con <- file(tf) try(writeLines(con)) close(con) # Trying to use unsupported args throws a warning writeLines(rownames(mtcars), tf, useBytes = TRUE) unlink(tf) } \seealso{ \code{\link[=readLines]{readLines()}} } brio/man/write_file_raw.Rd0000644000176200001440000000116314210415056015250 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/write_file_raw.R \name{write_file_raw} \alias{write_file_raw} \title{Write data to a file} \usage{ write_file_raw(raw, path) } \arguments{ \item{raw}{A raw vector with data to write.} \item{path}{A character string giving the file path to write to.} } \description{ This function differs from \code{\link[=write_lines]{write_lines()}} in that it writes the data in \code{text} directly, without any checking or adding any newlines. } \examples{ tf <- tempfile() write_file_raw(as.raw(c(0x66, 0x6f, 0x6f, 0x0, 0x62, 0x61, 0x72)), tf) unlink(tf) } brio/man/read_lines.Rd0000644000176200001440000000131114210415056014346 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/read_lines.R \name{read_lines} \alias{read_lines} \title{Read text lines from a file} \usage{ read_lines(path, n = -1) } \arguments{ \item{path}{A character string of the path to the file to read.} \item{n}{integer. The number of lines to read. A negative number means read all the lines in the file.} } \value{ A UTF-8 encoded character vector of the lines in the file. } \description{ The file is assumed to be UTF-8 and the resulting text has its encoding set as such. } \details{ Both '\\r\\n' and '\\n' are treated as a newline. } \examples{ authors_file <- file.path(R.home("doc"), "AUTHORS") data <- read_lines(authors_file) } brio/man/write_lines.Rd0000644000176200001440000000157614210415056014602 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/write_lines.R \name{write_lines} \alias{write_lines} \title{Write lines to a file} \usage{ write_lines(text, path, eol = "\\n") } \arguments{ \item{text}{A character vector to write} \item{path}{A character string giving the file path to write to.} \item{eol}{The end of line characters to use between lines.} } \value{ The UTF-8 encoded input text (invisibly). } \description{ The text is converted to UTF-8 encoding before writing. } \details{ The files are opened in binary mode, so they always use exactly the string given in \code{eol} as the line separator. To write a file with windows line endings use \code{write_lines(eol = "\\r\\n")} } \examples{ tf <- tempfile() write_lines(rownames(mtcars), tf) # Write with Windows style line endings write_lines(rownames(mtcars), tf, eol = "\r\n") unlink(tf) } brio/man/file_line_endings.Rd0000644000176200001440000000140114210415056015676 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/file_line_endings.R \name{file_line_endings} \alias{file_line_endings} \title{Retrieve the type of line endings used by a file} \usage{ file_line_endings(path) } \arguments{ \item{path}{A character string of the path to the file to read.} } \value{ The line endings used, one of \itemize{ \item '\\n' - if the file uses Unix line endings \item '\\r\\n' - if the file uses Windows line endings \item NA - if it cannot be determined } } \description{ Retrieve the type of line endings used by a file } \examples{ tf1 <- tempfile() tf2 <- tempfile() write_lines("foo", tf1, eol = "\n") write_lines("bar", tf2, eol = "\r\n") file_line_endings(tf1) file_line_endings(tf2) unlink(c(tf1, tf2)) } brio/man/read_file.Rd0000644000176200001440000000155614210502123014156 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/read_file.R, R/read_file_raw.R \name{read_file} \alias{read_file} \alias{read_file_raw} \title{Read an entire file} \usage{ read_file(path) read_file_raw(path) } \arguments{ \item{path}{A character string of the path to the file to read.} } \value{ \itemize{ \item \code{\link[=read_file]{read_file()}}: A length 1 character vector. \item \code{\link[=read_file_raw]{read_file_raw()}}: A raw vector. } } \description{ \code{read_file()} reads an entire file into a single character vector. \code{read_file_raw()} reads an entire file into a raw vector. } \details{ \code{read_file()} assumes the file has a UTF-8 encoding. } \examples{ authors_file <- file.path(R.home("doc"), "AUTHORS") data <- read_file(authors_file) data_raw <- read_file_raw(authors_file) identical(data, rawToChar(data_raw)) } brio/man/write_file.Rd0000644000176200001440000000120214210415056014371 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/write_file.R \name{write_file} \alias{write_file} \title{Write data to a file} \usage{ write_file(text, path) } \arguments{ \item{text}{A character vector of length 1 with data to write.} \item{path}{A character string giving the file path to write to.} } \value{ The UTF-8 encoded input text (invisibly). } \description{ This function differs from \code{\link[=write_lines]{write_lines()}} in that it writes the data in \code{text} directly, without any checking or adding any newlines. } \examples{ tf <- tempfile() write_file("some data\n", tf) unlink(tf) } brio/DESCRIPTION0000644000176200001440000000215714612255547012733 0ustar liggesusersPackage: brio Title: Basic R Input Output Version: 1.1.5 Authors@R: c( person("Jim", "Hester", role = "aut", comment = c(ORCID = "0000-0002-2739-7082")), person("Gábor", "Csárdi", , "csardi.gabor@gmail.com", role = c("aut", "cre")), person(given = "Posit Software, PBC", role = c("cph", "fnd")) ) Description: Functions to handle basic input output, these functions always read and write UTF-8 (8-bit Unicode Transformation Format) files and provide more explicit control over line endings. License: MIT + file LICENSE URL: https://brio.r-lib.org, https://github.com/r-lib/brio BugReports: https://github.com/r-lib/brio/issues Depends: R (>= 3.6) Suggests: covr, testthat (>= 3.0.0) Config/Needs/website: tidyverse/tidytemplate Config/testthat/edition: 3 Encoding: UTF-8 RoxygenNote: 7.2.3 NeedsCompilation: yes Packaged: 2024-04-24 18:51:29 UTC; gaborcsardi Author: Jim Hester [aut] (), Gábor Csárdi [aut, cre], Posit Software, PBC [cph, fnd] Maintainer: Gábor Csárdi Repository: CRAN Date/Publication: 2024-04-24 19:20:07 UTC brio/tests/0000755000176200001440000000000014210415056012345 5ustar liggesusersbrio/tests/testthat/0000755000176200001440000000000014612255547014222 5ustar liggesusersbrio/tests/testthat/test-read_file_raw.R0000644000176200001440000000076614210415056020101 0ustar liggesuserstest_that("read_file_raw reads empty files", { tmp <- tempfile() on.exit(unlink(tmp)) writeBin(charToRaw(""), tmp) expect_equal(read_file_raw(tmp), raw()) }) works_with <- function(contents) { tmp <- tempfile() on.exit(unlink(tmp)) writeBin(charToRaw(contents), tmp) expect_equal(read_file_raw(tmp), charToRaw(contents)) } test_that("read_file_raw reads the entire file", { works_with("foo") works_with("foo\nbar") works_with("foo\nbar\n") works_with("foo\r\nbar\r\n") }) brio/tests/testthat/test-writeLines.R0000644000176200001440000000051014210415056017426 0ustar liggesuserstest_that("writeLines works", { tmp <- tempfile() on.exit(unlink(tmp)) # Errors with connections con <- file(tmp) expect_error(writeLines("foo\nbar\n", con), "Only file paths are supported") close(con) # Warns if you use useBytes expect_warning(writeLines("foo\nbar\n", tmp, useBytes = TRUE), "is ignored") }) brio/tests/testthat/test-read_lines.R0000644000176200001440000000713214521176047017426 0ustar liggesuserstest_that("read_lines works on empty files", { tmp <- tempfile() on.exit(unlink(tmp)) writeBin(charToRaw(""), tmp) expect_equal(read_lines(tmp, 0), character()) expect_equal(read_lines(tmp), character()) expect_equal(read_lines(tmp, 1), character()) }) test_that("read_lines works files with no newlines", { tmp <- tempfile() on.exit(unlink(tmp)) writeBin(charToRaw("foo"), tmp) expect_equal(read_lines(tmp, 0), character()) expect_equal(read_lines(tmp), "foo") expect_equal(read_lines(tmp, 1), "foo") }) test_that("read_lines works files with only newlines", { tmp <- tempfile() on.exit(unlink(tmp)) writeBin(charToRaw("\n"), tmp) expect_equal(read_lines(tmp, 0), character()) expect_equal(read_lines(tmp, 1), "") expect_equal(read_lines(tmp), "") }) test_that("read_lines works files with only windows newlines", { tmp <- tempfile() on.exit(unlink(tmp)) writeBin(charToRaw("\r\n"), tmp) expect_equal(read_lines(tmp, 0), character()) expect_equal(read_lines(tmp, 1), "") expect_equal(read_lines(tmp), "") }) test_that("read_lines works with unix line endings", { tmp <- tempfile() on.exit(unlink(tmp)) writeBin(charToRaw("foo\nbar\nbaz\n"), tmp) expect_equal(read_lines(tmp), c("foo", "bar", "baz")) expect_equal(read_lines(tmp, 0), character()) expect_equal(read_lines(tmp, 1), c("foo")) }) test_that("read_lines works with unix line endings and no trailing newline", { tmp <- tempfile() on.exit(unlink(tmp)) writeBin(charToRaw("foo\nbar\nbaz"), tmp) expect_equal(read_lines(tmp), c("foo", "bar", "baz")) expect_equal(read_lines(tmp, 0), character()) expect_equal(read_lines(tmp, 1), c("foo")) }) test_that("read_lines works with Windows line endings", { tmp <- tempfile() on.exit(unlink(tmp)) writeBin(charToRaw("foo\r\nbar\r\nbaz\r\n"), tmp) expect_equal(read_lines(tmp), c("foo", "bar", "baz")) expect_equal(read_lines(tmp, 0), character()) expect_equal(read_lines(tmp, 1), c("foo")) }) test_that("read_lines works with Windows line endings and no trailing newline", { tmp <- tempfile() on.exit(unlink(tmp)) writeBin(charToRaw("foo\r\nbar\r\nbaz"), tmp) expect_equal(read_lines(tmp), c("foo", "bar", "baz")) expect_equal(read_lines(tmp, 0), character()) expect_equal(read_lines(tmp, 1), c("foo")) }) test_that("read_lines works with long lines", { tmp <- tempfile() on.exit(unlink(tmp)) data <- c( paste(rep("a", 1024), collapse = ""), paste(rep("b", 2048), collapse = "") ) writeLines(data, tmp) expect_equal(read_lines(tmp), data) expect_equal(read_lines(tmp, 0), character()) expect_equal(read_lines(tmp, 1), data[[1]]) }) test_that("read_lines works with lots of lines", { tmp <- tempfile() on.exit(unlink(tmp)) data <- rep("a", 1025) writeLines(data, tmp) expect_equal(read_lines(tmp), data) expect_equal(read_lines(tmp, 0), character()) expect_equal(read_lines(tmp, 1), data[[1]]) }) test_that("read_lines works with really long lines", { tmp <- tempfile() on.exit(unlink(tmp)) data <- rep(paste(rep("a", 1024 * 1024 - 2), collapse = ""), 5) con <- file(tmp, "wb") base::writeLines(data, con, sep = "\r\n") close(con) expect_equal(read_lines(tmp), data) expect_equal(read_lines(tmp, 0), character()) expect_equal(read_lines(tmp, 1), data[[1]]) }) test_that("read_lines works with lots of lines that don't end with a newline", { tmp <- tempfile() on.exit(unlink(tmp)) data <- rep("a", 1025) writeBin(paste(data, collapse = "\n"), tmp) expect_equal(read_lines(tmp), data) expect_equal(read_lines(tmp, 0), character()) expect_equal(read_lines(tmp, 1), "a") }) brio/tests/testthat/test-write_file.R0000644000176200001440000000154314210415056017441 0ustar liggesusersread_file_raw <- function(file) { readBin(file, file.info(file)$size, what = "raw") } test_that("write_file errors on invalid inputs", { tmp <- tempfile() on.exit(unlink(tmp)) expect_error( write_file(c("foo", "bar"), tmp), "cannot have more than one element" ) expect_error( write_file("foo", c("bar", tmp)), "must be a single element" ) }) test_that("write_file works", { tmp <- tempfile() on.exit(unlink(tmp)) write_file(character(), tmp) expect_equal(read_file_raw(tmp), charToRaw("")) write_file("", tmp) expect_equal(read_file_raw(tmp), charToRaw("")) write_file(c("foo"), tmp) expect_equal(read_file_raw(tmp), charToRaw("foo")) write_file(c("foo\n"), tmp) expect_equal(read_file_raw(tmp), charToRaw("foo\n")) write_file(c("foo\r\n"), tmp) expect_equal(read_file_raw(tmp), charToRaw("foo\r\n")) }) brio/tests/testthat/test-file_line_endings.R0000644000176200001440000000073314210415056020745 0ustar liggesuserstest_that("file_line_endings detects Unix line endings", { tmp <- tempfile() on.exit(unlink(tmp)) writeBin(charToRaw("foo\n"), tmp) expect_equal(file_line_endings(tmp), "\n") writeBin(charToRaw(""), tmp) expect_identical(file_line_endings(tmp), NA_character_) }) test_that("file_line_endings detects Windows line endings", { tmp <- tempfile() on.exit(unlink(tmp)) writeBin(charToRaw("foo\r\n"), tmp) expect_equal(file_line_endings(tmp), "\r\n") }) brio/tests/testthat/test-brio-package.R0000644000176200001440000000000014521176047017630 0ustar liggesusersbrio/tests/testthat/test-package.R0000644000176200001440000000000014521176047016677 0ustar liggesusersbrio/tests/testthat/test-read_file.R0000644000176200001440000000074114210415056017221 0ustar liggesuserstest_that("read_file reads empty files", { tmp <- tempfile() on.exit(unlink(tmp)) writeBin(charToRaw(""), tmp) expect_equal(read_file(tmp), character()) }) works_with <- function(contents) { tmp <- tempfile() on.exit(unlink(tmp)) writeBin(charToRaw(contents), tmp) expect_equal(read_file(tmp), contents) } test_that("read_file reads the entire file", { works_with("foo") works_with("foo\nbar") works_with("foo\nbar\n") works_with("foo\r\nbar\r\n") }) brio/tests/testthat/test-write_file_raw.R0000644000176200001440000000154414210415056020313 0ustar liggesusersread_file_raw <- function(file) { readBin(file, file.info(file)$size, what = "raw") } test_that("write_file_raw errors on invalid inputs", { tmp <- tempfile() on.exit(unlink(tmp)) expect_error( write_file_raw("foo", c("bar", tmp)), "must be a raw vector" ) expect_error( write_file_raw(charToRaw("foo"), c("bar", tmp)), "must be a single element" ) }) test_that("write_file_raw works", { tmp <- tempfile() on.exit(unlink(tmp)) write_file_raw(raw(), tmp) expect_equal(read_file_raw(tmp), charToRaw("")) write_file_raw(charToRaw("foo"), tmp) expect_equal(read_file_raw(tmp), charToRaw("foo")) write_file_raw(charToRaw("foo\n"), tmp) expect_equal(read_file_raw(tmp), charToRaw("foo\n")) vec <- as.raw(c(0x66, 0x6f, 0x6f, 0x0, 0x62, 0x61, 0x72)) write_file_raw(vec, tmp) expect_equal(read_file_raw(tmp), vec) }) brio/tests/testthat/test-readLines.R0000644000176200001440000000103114210415056017206 0ustar liggesuserstest_that("readLines works", { tmp <- tempfile() on.exit(unlink(tmp)) writeLines("foo\nbar\n", tmp) # Errors with connections con <- file(tmp) expect_error(readLines(con), "Only file paths are supported") close(con) # Warns if you use ok, warn, encoding or skipNul expect_warning(readLines(tmp, ok = TRUE), "is ignored") expect_warning(readLines(tmp, warn = TRUE), "is ignored") expect_warning(readLines(tmp, encoding = "Latin-1"), "is ignored") expect_warning(readLines(tmp, skipNul = TRUE), "is ignored") }) brio/tests/testthat/test-write_lines.R0000644000176200001440000000406214521176047017644 0ustar liggesusersread_file_raw <- function(file) { readBin(file, file.info(file)$size, what = "raw") } test_that("write_lines works with both unix and windows newlines", { tmp <- tempfile() on.exit(unlink(tmp)) write_lines(character(), tmp) expect_equal(read_file_raw(tmp), charToRaw("")) write_lines("", tmp) expect_equal(read_file_raw(tmp), charToRaw("\n")) write_lines("", tmp, eol = "\r\n") expect_equal(read_file_raw(tmp), charToRaw("\r\n")) write_lines(c("foo", "bar"), tmp) expect_equal(read_file_raw(tmp), charToRaw("foo\nbar\n")) write_lines(c("foo", "bar"), tmp, eol = "\r\n") expect_equal(read_file_raw(tmp), charToRaw("foo\r\nbar\r\n")) }) test_that("write_lines works with both unix and windows internal newlines", { tmp <- tempfile() on.exit(unlink(tmp)) write_lines(character(), tmp) write_lines(character(), tmp) expect_equal(read_file_raw(tmp), charToRaw("")) write_lines("foo\nbar", tmp) expect_equal(read_file_raw(tmp), charToRaw("foo\nbar\n")) write_lines("foo\r\nbar", tmp) expect_equal(read_file_raw(tmp), charToRaw("foo\nbar\n")) write_lines("foo\nbar", tmp, eol = "\r\n") expect_equal(read_file_raw(tmp), charToRaw("foo\r\nbar\r\n")) write_lines("foo\r\nbar", tmp, eol = "\r\n") expect_equal(read_file_raw(tmp), charToRaw("foo\r\nbar\r\n")) }) test_that("writeLines works", { tmp <- tempfile() on.exit(unlink(tmp)) # Errors with connections con <- file(tmp) expect_error(writeLines("foo\nbar\n", con), "Only file paths are supported") close(con) # Warns if you use useBytes expect_warning(writeLines("foo\nbar\n", tmp, useBytes = TRUE), "is ignored") }) test_that("UTF-8 file names", { skip_on_cran() tmp <- tempfile() on.exit(unlink(tmp, recursive = TRUE), add = TRUE) dir.create(tmp) str <- "xx\xfcxx" Encoding(str) <- "latin1" normalizePath(str, mustWork = FALSE) path <- file.path(tmp, str) Encoding(path) <- "latin1" write_lines(str, path) expect_true(file.exists(path)) str2 <- read_lines(path) expect_identical( charToRaw(enc2utf8(str2)), charToRaw(str2) ) }) brio/tests/testthat.R0000644000176200001440000000006414210415056014330 0ustar liggesuserslibrary(testthat) library(brio) test_check("brio") brio/src/0000755000176200001440000000000014612252261011775 5ustar liggesusersbrio/src/brio.h0000644000176200001440000000015114210415056013073 0ustar liggesusers#pragma once #include FILE* open_with_widechar_on_windows(SEXP path, const char* mode); brio/src/file_line_endings.c0000644000176200001440000000117614210415056015600 0ustar liggesusers#include #include #include #include #include "brio.h" SEXP brio_file_line_endings(SEXP path) { FILE* fp; if ((fp = open_with_widechar_on_windows(STRING_ELT(path, 0), "rb")) == NULL) { error("Could not open file: %s", Rf_translateChar(STRING_ELT(path, 0))); } int c; int prev_c = '\0'; while ((c = fgetc(fp)) != EOF) { if (c == '\n') { if (prev_c == '\r') { fclose(fp); return mkString("\r\n"); } else { fclose(fp); return mkString("\n"); } } prev_c = c; } fclose(fp); return ScalarString(NA_STRING); } brio/src/init.c0000644000176200001440000000177414210415056013112 0ustar liggesusers#include #include #include #include // for NULL /* .Call calls */ extern SEXP brio_read_lines(SEXP, SEXP); extern SEXP brio_write_lines(SEXP, SEXP, SEXP); extern SEXP brio_write_file(SEXP, SEXP); extern SEXP brio_write_file_raw(SEXP, SEXP); extern SEXP brio_file_line_endings(SEXP); extern SEXP brio_read_file(SEXP); extern SEXP brio_read_file_raw(SEXP); static const R_CallMethodDef CallEntries[] = { {"brio_read_lines", (DL_FUNC)&brio_read_lines, 2}, {"brio_write_lines", (DL_FUNC)&brio_write_lines, 3}, {"brio_write_file", (DL_FUNC)&brio_write_file, 2}, {"brio_write_file_raw", (DL_FUNC)&brio_write_file_raw, 2}, {"brio_file_line_endings", (DL_FUNC)&brio_file_line_endings, 1}, {"brio_read_file", (DL_FUNC)&brio_read_file, 1}, {"brio_read_file_raw", (DL_FUNC)&brio_read_file_raw, 1}, {NULL, NULL, 0}}; void R_init_brio(DllInfo* dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); } brio/src/read_file.c0000644000176200001440000000204014535113313014045 0ustar liggesusers#include #include #include #include #include "brio.h" SEXP brio_read_file(SEXP path) { FILE* fp; if ((fp = open_with_widechar_on_windows(STRING_ELT(path, 0), "rb")) == NULL) { error("Could not open file: %s", Rf_translateChar(STRING_ELT(path, 0))); } fseek(fp, 0, SEEK_END); // seek to end of file size_t file_size = ftell(fp); // get current file pointer rewind(fp); if (file_size == 0) { fclose(fp); return allocVector(STRSXP, 0); } char* read_buf; read_buf = (char*)malloc(file_size + 1); if (!read_buf) { fclose(fp); error("Allocation of size %zu failed", file_size + 1); } read_buf[file_size] = '\0'; if ((fread(read_buf, 1, file_size, fp)) != file_size) { fclose(fp); error("Error reading file: %s", Rf_translateChar(STRING_ELT(path, 0))); } fclose(fp); SEXP ans; PROTECT(ans = allocVector(STRSXP, 1)); SET_STRING_ELT(ans, 0, mkCharLenCE(read_buf, file_size, CE_UTF8)); free(read_buf); UNPROTECT(1); return ans; } brio/src/read_file_raw.c0000644000176200001440000000202014535113405014716 0ustar liggesusers#include #include #include #include #include "brio.h" SEXP brio_read_file_raw(SEXP path) { FILE* fp; if ((fp = open_with_widechar_on_windows(STRING_ELT(path, 0), "rb")) == NULL) { error("Could not open file: %s", Rf_translateChar(STRING_ELT(path, 0))); } fseek(fp, 0, SEEK_END); // seek to end of file size_t file_size = ftell(fp); // get current file pointer rewind(fp); if (file_size == 0) { fclose(fp); return allocVector(RAWSXP, 0); } char* read_buf; read_buf = (char*)malloc(file_size + 1); if (!read_buf) { fclose(fp); error("Allocation of size %zu failed", file_size + 1); } read_buf[file_size] = '\0'; if ((fread(read_buf, 1, file_size, fp)) != file_size) { fclose(fp); error("Error reading file: %s", Rf_translateChar(STRING_ELT(path, 0))); } fclose(fp); SEXP ans; PROTECT(ans = allocVector(RAWSXP, file_size)); memcpy(RAW(ans), read_buf, file_size); free(read_buf); UNPROTECT(1); return ans; } brio/src/read_lines.c0000644000176200001440000000763114611670773014270 0ustar liggesusers#include #include #include #include #include "brio.h" // A macro similar to SET_STRING_ELT, it assumes a string vector protected with // PROTECT_WITH_INDEX, will automatically grow it if needed. #define SET_STRING_ELT2(X, I, VAL, P_IDX) \ { \ R_xlen_t len = Rf_xlength(X); \ R_xlen_t i = I; \ while (i >= len) { \ len *= 2; \ REPROTECT(X = Rf_xlengthgets(X, len), P_IDX); \ } \ SET_STRING_ELT(X, i, VAL); \ } typedef struct { char* data; size_t size; size_t limit; } str_buf; void str_buf_set(str_buf* buf, const char* in, size_t in_size) { while (buf->size + in_size >= buf->limit) { buf->limit *= 2; buf->data = realloc(buf->data, buf->limit); } memcpy(buf->data + buf->size, in, in_size); buf->size += in_size; buf->data[buf->size] = '\0'; } SEXP brio_read_lines(SEXP path, SEXP n) { int n_c = INTEGER(n)[0]; if (n_c == 0) { return allocVector(STRSXP, 0); } FILE* fp; if ((fp = open_with_widechar_on_windows(STRING_ELT(path, 0), "rb")) == NULL) { error("Could not open file: %s", Rf_translateChar(STRING_ELT(path, 0))); } SEXP out; out = allocVector(STRSXP, n_c >= 0 ? n_c : 1024); PROTECT_INDEX out_idx; PROTECT_WITH_INDEX(out, &out_idx); #define READ_BUF_SIZE 1024 * 1024 char* read_buf = (char*)malloc(READ_BUF_SIZE); if (!read_buf) { fclose(fp); error("Allocation of size %d failed", READ_BUF_SIZE); } R_xlen_t out_num = 0; str_buf line; line.limit = 1024; line.data = (char*)malloc(line.limit); line.size = 0; if (!line.data) { fclose(fp); free(read_buf); error("Allocation of size %zu failed", line.limit); } size_t read_size = 0; while ((read_size = fread(read_buf, 1, READ_BUF_SIZE - 1, fp)) > 0) { if (read_size != READ_BUF_SIZE - 1 && ferror(fp)) { free(line.data); free(read_buf); error( "Error reading from file: %s", Rf_translateChar(STRING_ELT(path, 0))); } read_buf[read_size] = '\0'; // Find the newlines const char* prev_newline = read_buf; const char* next_newline; while ((next_newline = strchr(prev_newline, '\n')) != NULL) { size_t len = next_newline - prev_newline; if (len == 0) { if (line.size > 0) { if (line.data[line.size - 1] == '\r') { --line.size; line.data[line.size] = '\0'; } } } else { if ((next_newline - 1)[0] == '\r') { --len; } } str_buf_set(&line, prev_newline, len); SEXP str = PROTECT(mkCharLenCE(line.data, line.size, CE_UTF8)); SET_STRING_ELT2(out, out_num++, str, out_idx); UNPROTECT(1); if (n_c > 0 && out_num >= n_c) { free(line.data); free(read_buf); fclose(fp); UNPROTECT(1); return out; } prev_newline = next_newline + 1; line.size = 0; } size_t len = read_size - (prev_newline - read_buf); str_buf_set(&line, prev_newline, len); } if (line.size > 0) { SEXP str = PROTECT(mkCharCE(line.data, CE_UTF8)); SET_STRING_ELT2(out, out_num++, str, out_idx); UNPROTECT(1); } // Rf_xlengthgets is very cheap if the size is already correct, so // don't check for size mismatch. It is very likely that there is a // mismatch, anyway. REPROTECT(out = Rf_lengthgets(out, out_num), out_idx); fclose(fp); free(line.data); free(read_buf); UNPROTECT(1); return out; } brio/src/write_file.c0000644000176200001440000000103514210415056014266 0ustar liggesusers#include #include #include #include #include "brio.h" SEXP brio_write_file(SEXP text, SEXP path) { FILE* fp; if ((fp = open_with_widechar_on_windows(STRING_ELT(path, 0), "wb")) == NULL) { error("Could not open file: %s", Rf_translateChar(STRING_ELT(path, 0))); } if (xlength(text) == 0) { fwrite("", 1, 0, fp); } else { SEXP elt = STRING_ELT(text, 0); R_xlen_t elt_size = xlength(elt); fwrite(CHAR(elt), 1, elt_size, fp); } fclose(fp); return text; } brio/src/brio.c0000644000176200001440000000170514535273302013102 0ustar liggesusers#include "brio.h" #include #ifdef _WIN32 #include #endif // This is needed to support wide character paths on windows FILE* open_with_widechar_on_windows(SEXP path, const char* mode) { FILE* out; #ifdef _WIN32 const char* path_c = Rf_translateCharUTF8(path); // First convert the mode to the wide equivalent // Only usage is 2 characters so max 8 bytes + 2 byte null. wchar_t mode_w[10]; MultiByteToWideChar(CP_UTF8, 0, mode, -1, mode_w, 9); // Then convert the path wchar_t* buf; size_t len = MultiByteToWideChar(CP_UTF8, 0, path_c, -1, NULL, 0); if (len <= 0) { error("Cannot convert file to Unicode: %s", path_c); } buf = (wchar_t*)R_alloc(len, sizeof(wchar_t)); if (buf == NULL) { error("Could not allocate buffer of size: %zu", len); } MultiByteToWideChar(CP_UTF8, 0, path_c, -1, buf, len); out = _wfopen(buf, mode_w); #else out = fopen(Rf_translateChar(path), mode); #endif return out; } brio/src/write_file_raw.c0000644000176200001440000000076114210415056015144 0ustar liggesusers#include #include #include #include #include "brio.h" SEXP brio_write_file_raw(SEXP raw, SEXP path) { FILE* fp; if ((fp = open_with_widechar_on_windows(STRING_ELT(path, 0), "wb")) == NULL) { error("Could not open file: %s", Rf_translateChar(STRING_ELT(path, 0))); } if (xlength(raw) == 0) { fwrite("", 1, 0, fp); } else { R_xlen_t size = xlength(raw); fwrite(RAW(raw), 1, size, fp); } fclose(fp); return raw; } brio/src/write_lines.c0000644000176200001440000000202414210415056014460 0ustar liggesusers#include #include #include #include #include "brio.h" SEXP brio_write_lines(SEXP text, SEXP path, SEXP eol) { FILE* fp; if ((fp = open_with_widechar_on_windows(STRING_ELT(path, 0), "wb")) == NULL) { error("Could not open file: %s", Rf_translateChar(STRING_ELT(path, 0))); } SEXP eol_e = STRING_ELT(eol, 0); size_t eol_len = xlength(eol_e); const char* eol_c = CHAR(eol_e); R_xlen_t len = xlength(text); for (R_xlen_t i = 0; i < len; ++i) { SEXP elt = STRING_ELT(text, i); R_xlen_t elt_size = xlength(elt); const char* cur = CHAR(elt); const char* prev = cur; while ((cur = strchr(prev, '\n')) != NULL) { size_t len = cur - prev; if (len > 1 && (cur - 1)[0] == '\r') { --len; } fwrite(prev, 1, len, fp); fwrite(eol_c, 1, eol_len, fp); prev = cur + 1; } size_t len = elt_size - (prev - CHAR(elt)); fwrite(prev, 1, len, fp); fwrite(eol_c, 1, eol_len, fp); } fclose(fp); return text; } brio/R/0000755000176200001440000000000014521176047011415 5ustar liggesusersbrio/R/write_file_raw.R0000644000176200001440000000127314210415056014534 0ustar liggesusers#' Write data to a file #' #' This function differs from [write_lines()] in that it writes the data in #' `text` directly, without any checking or adding any newlines. #' #' @param raw A raw vector with data to write. #' @inheritParams write_file #' @export #' @examples #' tf <- tempfile() #' #' write_file_raw(as.raw(c(0x66, 0x6f, 0x6f, 0x0, 0x62, 0x61, 0x72)), tf) #' #' unlink(tf) write_file_raw <- function(raw, path) { if (!is.raw(raw)) { stop("`raw` must be a raw vector", call. = FALSE) } if (length(path) != 1) { stop("`path` must be a single element", call. = FALSE) } path <- normalizePath(path, mustWork = FALSE) invisible(.Call(brio_write_file_raw, raw, path)) } brio/R/read_file_raw.R0000644000176200001440000000022514210415056014311 0ustar liggesusers#' @rdname read_file #' @export read_file_raw <- function(path) { path <- normalizePath(path, mustWork = TRUE) .Call(brio_read_file_raw, path) } brio/R/readLines.R0000644000176200001440000000355114210415056013441 0ustar liggesusers#' Read text lines from a file #' #' This is a drop in replacement for [base::readLines()] with restricted #' functionality. Compared to [base::readLines()] it: #' - Only works with file paths, not connections. #' - Assumes the files are always UTF-8 encoded. #' - Does not warn or skip embedded nulls, they will likely crash R. #' - Does not warn if the file is missing the end of line character. #' - The arguments `ok`, `warn`, `encoding` and `skipNul` are ignored, with a warning. #' @param con A character string of the path to a file. Throws an error if a connection object is passed. #' @inheritParams read_lines #' @param ok Ignored, with a warning. #' @param warn Ignored, with a warning. #' @param encoding Ignored, with a warning. #' @param skipNul Ignored, with a warning. #' @export #' @return A UTF-8 encoded character vector of the lines in the file. #' @seealso [writeLines()] #' @examples #' authors_file <- file.path(R.home("doc"), "AUTHORS") #' data <- readLines(authors_file) #' #' # Trying to use connections throws an error #' con <- file(authors_file) #' try(readLines(con)) #' close(con) #' #' # Trying to use unsupported args throws a warning #' data <- readLines(authors_file, encoding = "UTF-16") readLines <- function(con, n = -1, ok, warn, encoding, skipNul) { if (!is.character(con)) { stop("Only file paths are supported by brio::readLines()", call. = FALSE) } if (!missing(ok)) { warning("`ok` is ignored by brio::readLines()", immediate. = TRUE, call. = FALSE) } if (!missing(warn)) { warning("`warn` is ignored by brio::readLines()", immediate. = TRUE, call. = FALSE) } if (!missing(encoding)) { warning("`encoding` is ignored by brio::readLines()", immediate. = TRUE, call. = FALSE) } if (!missing(skipNul)) { warning("`skipNul` is ignored by brio::readLines()", immediate. = TRUE, call. = FALSE) } read_lines(con, n) } brio/R/writeLines.R0000644000176200001440000000243314210415056013656 0ustar liggesusers#' Write lines to a file #' #' This is a drop in replacement for [base::writeLines()] with restricted #' functionality. Compared to [base::writeLines()] it: #' - Only works with file paths, not connections. #' - Uses [enc2utf8()] to convert `text()` to UTF-8 before writing. #' - Uses `sep` unconditionally as the line ending, regardless of platform. #' - The `useBytes` argument is ignored, with a warning. #' @inheritParams write_lines #' @inheritParams readLines #' @param sep The end of line characters to use between lines. #' @param useBytes Ignored, with a warning. #' @return The UTF-8 encoded input text (invisibly). #' @seealso [readLines()] #' @export #' @examples #' tf <- tempfile() #' #' writeLines(rownames(mtcars), tf) #' #' # Trying to use connections throws an error #' con <- file(tf) #' try(writeLines(con)) #' close(con) #' #' # Trying to use unsupported args throws a warning #' writeLines(rownames(mtcars), tf, useBytes = TRUE) #' #' unlink(tf) writeLines <- function(text, con, sep = "\n", useBytes) { if (!is.character(con)) { stop("Only file paths are supported by brio::writeLines()", call. = FALSE) } if (!missing(useBytes)) { warning("`useBytes` is ignored by brio::writeLines()", immediate. = TRUE, call. = FALSE) } write_lines(text, path = con, eol = sep) } brio/R/read_lines.R0000644000176200001440000000125614210415056013640 0ustar liggesusers#' Read text lines from a file #' #' The file is assumed to be UTF-8 and the resulting text has its encoding set #' as such. #' #' Both '\\r\\n' and '\\n' are treated as a newline. #' @param path A character string of the path to the file to read. #' @param n integer. The number of lines to read. A negative number means read #' all the lines in the file. #' @return A UTF-8 encoded character vector of the lines in the file. #' @export #' @examples #' authors_file <- file.path(R.home("doc"), "AUTHORS") #' data <- read_lines(authors_file) read_lines <- function(path, n = -1) { path <- normalizePath(path, mustWork = TRUE) n <- as.integer(n) .Call(brio_read_lines, path, n) } brio/R/read_file.R0000644000176200001440000000121514210502117013433 0ustar liggesusers#' Read an entire file #' #' `read_file()` reads an entire file into a single character vector. #' `read_file_raw()` reads an entire file into a raw vector. #' #' `read_file()` assumes the file has a UTF-8 encoding. #' @inheritParams read_lines #' @return #' - [read_file()]: A length 1 character vector. #' - [read_file_raw()]: A raw vector. #' @export #' @examples #' authors_file <- file.path(R.home("doc"), "AUTHORS") #' data <- read_file(authors_file) #' data_raw <- read_file_raw(authors_file) #' identical(data, rawToChar(data_raw)) read_file <- function(path) { path <- normalizePath(path, mustWork = TRUE) .Call(brio_read_file, path) } brio/R/write_lines.R0000644000176200001440000000176614210415056014065 0ustar liggesusers#' Write lines to a file #' #' The text is converted to UTF-8 encoding before writing. #' #' The files are opened in binary mode, so they always use exactly the string #' given in `eol` as the line separator. #' #' To write a file with windows line endings use `write_lines(eol = "\r\n")` #' @param text A character vector to write #' @param path A character string giving the file path to write to. #' @param eol The end of line characters to use between lines. #' @return The UTF-8 encoded input text (invisibly). #' @export #' @examples #' tf <- tempfile() #' #' write_lines(rownames(mtcars), tf) #' #' # Write with Windows style line endings #' write_lines(rownames(mtcars), tf, eol = "\r\n") #' #' unlink(tf) write_lines <- function(text, path, eol = "\n") { if (length(path) != 1) { stop("`path` must be a single element", call. = FALSE) } text <- as.character(text) text <- enc2utf8(text) path <- normalizePath(path, mustWork = FALSE) invisible(.Call(brio_write_lines, text, path, eol)) } brio/R/file_line_endings.R0000644000176200001440000000115614210415056015167 0ustar liggesusers#' Retrieve the type of line endings used by a file #' #' @inheritParams read_lines #' @return The line endings used, one of #' - '\\n' - if the file uses Unix line endings #' - '\\r\\n' - if the file uses Windows line endings #' - NA - if it cannot be determined #' @export #' @examples #' tf1 <- tempfile() #' tf2 <- tempfile() #' write_lines("foo", tf1, eol = "\n") #' write_lines("bar", tf2, eol = "\r\n") #' #' file_line_endings(tf1) #' file_line_endings(tf2) #' #' unlink(c(tf1, tf2)) file_line_endings <- function(path) { path <- normalizePath(path, mustWork = TRUE) .Call(brio_file_line_endings, path) } brio/R/brio-package.R0000644000176200001440000000013514521176047014063 0ustar liggesusers#' @keywords internal "_PACKAGE" ## usethis namespace: start ## usethis namespace: end NULL brio/R/write_file.R0000644000176200001440000000150414210415056013660 0ustar liggesusers#' Write data to a file #' #' This function differs from [write_lines()] in that it writes the data in #' `text` directly, without any checking or adding any newlines. #' #' @param text A character vector of length 1 with data to write. #' @param path A character string giving the file path to write to. #' @return The UTF-8 encoded input text (invisibly). #' @export #' @examples #' tf <- tempfile() #' #' write_file("some data\n", tf) #' #' unlink(tf) write_file <- function(text, path) { text <- as.character(text) if (length(text) > 1) { stop("`text` cannot have more than one element", call. = FALSE) } if (length(path) != 1) { stop("`path` must be a single element", call. = FALSE) } text <- enc2utf8(text) path <- normalizePath(path, mustWork = FALSE) invisible(.Call(brio_write_file, text, path)) } brio/R/package.R0000644000176200001440000000005614210415056013123 0ustar liggesusers#' @useDynLib brio, .registration = TRUE NULL brio/NEWS.md0000644000176200001440000000136014612252235012305 0ustar liggesusers# brio 1.1.5 * brio now works in WebR. # brio 1.1.4 * `printf()`-like format strings are now safer. # brio 1.1.3 * Gábor Csárdi is now the maintainer. * New `write_file_raw()` function to write a raw vector to a file. * Fix memory leak in `read_lines()` (@ms609, #20) # brio 1.1.2 * Input filenames are now automatically converted to UTF-8 from the native encoding (@gaborcsardi, #15) * `read_file_raw()` now closes file handles (@pbarber, #16) # brio 1.1.1 * `file_line_endings()` now works as expected on ARM systems (#8) # brio 1.1.0 * New `write_file()` function to write an entire file (#7) * `read_lines()` no longer leaks file handles. * Added a `NEWS.md` file to track changes to the package. # brio 1.0.0 * Initial release brio/MD50000644000176200001440000000477314612255547011543 0ustar liggesusers149bffc0bd747fac039922cedd0e39c9 *DESCRIPTION 1902819ec89d94d87b7d35ef39414201 *LICENSE cafe6abd98495de247c2e0182674a058 *NAMESPACE e8d5e72a192e0af55b3183c462119b39 *NEWS.md df6cc46bc7fae1a55b713f3d5065b35a *R/brio-package.R 0e69c43d9eff412c53206329383e08e4 *R/file_line_endings.R bcc8a3254419abe5faad39c3ad3ce6f6 *R/package.R 14c24d4ef66eb69aa1294c9a69c856fa *R/readLines.R 361ce44f378ed2fa9f4260edf36c98ff *R/read_file.R 30bfa707729ec772d1686924992968df *R/read_file_raw.R f3da7fa147c36465e908b908ba81a49e *R/read_lines.R 498c8779310452da7cdf0859af378447 *R/writeLines.R 88ec2cb825acb3e8b9316127f9d73a74 *R/write_file.R c84092de8597bcd4bafcbb571ada478d *R/write_file_raw.R 5f0498131536076f2f214fe13c4e0659 *R/write_lines.R 6ea1aea389bf1fddaab1fe87fae00aa8 *README.md da884e2bb4c1d6cf1605b5b7497cab32 *man/brio-package.Rd f33b35f5ec1176833cf91226eb87daae *man/file_line_endings.Rd b51a772df842fe84c3bf204a229ee290 *man/readLines.Rd 4548333d064610b420c5632e0f22d6ba *man/read_file.Rd db54df3ee4936dfcd4ba71bd1c4cee36 *man/read_lines.Rd baab6e5fe7131f14b2ac7b76cb6a0cd9 *man/writeLines.Rd 73945024f6aff4cf2739b855a65040ca *man/write_file.Rd ed119fdef92f11a88e3bae31d4435ea7 *man/write_file_raw.Rd d0294438216c19bcd49cc6bfa03ffbe7 *man/write_lines.Rd 0a15663bd190577b54548a19f2f53ce7 *src/brio.c ea2d1efb3c697dd6560443131a2d84cc *src/brio.h 560280d5bbadeadcad0b24e9a07a3386 *src/file_line_endings.c 2ab260d860d1954862616dfa3af126c8 *src/init.c 31c48762d0614d2b7550c2b11b35a2db *src/read_file.c f78175c5473068d0d3ab956c5c6fd87e *src/read_file_raw.c 9788a7295cb9b13d583204952c60c6ef *src/read_lines.c 79865cfbeee218163d3e308f8223a826 *src/write_file.c e7a3908ce11f1d73f3ef8fbb4f4fab56 *src/write_file_raw.c 09a0fff16127315f23f215d24b3fc2ab *src/write_lines.c f14216d33c516cd12ed67cbe76c4c9f1 *tests/testthat.R d41d8cd98f00b204e9800998ecf8427e *tests/testthat/test-brio-package.R 1307629d475206e16c5f5a993585e9fe *tests/testthat/test-file_line_endings.R d41d8cd98f00b204e9800998ecf8427e *tests/testthat/test-package.R eed2162c3f7621bee5e400222cd7d47f *tests/testthat/test-readLines.R 1e535a49cb31d521a351770928649da2 *tests/testthat/test-read_file.R dea7a8c587263f97e00066a5dbfbc0de *tests/testthat/test-read_file_raw.R 2e796952c7e9f8b64bf057619c317aae *tests/testthat/test-read_lines.R 4764c296dfa831b34d9a85290d0525ce *tests/testthat/test-writeLines.R 9e3120e45ad1995df71c1382012028fe *tests/testthat/test-write_file.R 6544795e1608c024e0790ae3e100eb7d *tests/testthat/test-write_file_raw.R 5b2473dc45a3375107ebec5768f077ea *tests/testthat/test-write_lines.R