brio/0000755000175000017500000000000014151421252011334 5ustar nileshnileshbrio/MD50000644000175000017500000000451214151421252011646 0ustar nileshnilesha50aebba21f68092cc00fc8a69a27597 *DESCRIPTION 5174dfc514f0941d2edd4b0b4c9941dd *LICENSE cafe6abd98495de247c2e0182674a058 *NAMESPACE 0192aa1170413e17c816f469e6061737 *NEWS.md 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 1b8157c9ce8c6a208d46913b28ed6a2b *README.md 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 3a9a89c02ef32eb2a386d347b1a97b07 *src/brio.c ea2d1efb3c697dd6560443131a2d84cc *src/brio.h 560280d5bbadeadcad0b24e9a07a3386 *src/file_line_endings.c 2ab260d860d1954862616dfa3af126c8 *src/init.c 40ee8b15c31693833772caa9271e639c *src/read_file.c a2c6cf039a68cf33dbc25edb8c8d33f6 *src/read_file_raw.c 82de4e56fe82c297199d25b7f1f2db9b *src/read_lines.c 79865cfbeee218163d3e308f8223a826 *src/write_file.c e7a3908ce11f1d73f3ef8fbb4f4fab56 *src/write_file_raw.c 09a0fff16127315f23f215d24b3fc2ab *src/write_lines.c f14216d33c516cd12ed67cbe76c4c9f1 *tests/testthat.R 1307629d475206e16c5f5a993585e9fe *tests/testthat/test-file_line_endings.R eed2162c3f7621bee5e400222cd7d47f *tests/testthat/test-readLines.R 1e535a49cb31d521a351770928649da2 *tests/testthat/test-read_file.R dea7a8c587263f97e00066a5dbfbc0de *tests/testthat/test-read_file_raw.R fdeecfaa6b1b97ed944438cf7e86c9ac *tests/testthat/test-read_lines.R acb25c87476013f1fe531cf54073213b *tests/testthat/test-utf8.R 4764c296dfa831b34d9a85290d0525ce *tests/testthat/test-writeLines.R 9e3120e45ad1995df71c1382012028fe *tests/testthat/test-write_file.R 6544795e1608c024e0790ae3e100eb7d *tests/testthat/test-write_file_raw.R 473b0af29eb97de6f43cb1e2468090b0 *tests/testthat/test-write_lines.R brio/NEWS.md0000644000175000017500000000121014151260010012415 0ustar nileshnilesh# 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/DESCRIPTION0000644000175000017500000000175714151421252013054 0ustar nileshnileshPackage: brio Title: Basic R Input Output Version: 1.1.3 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("RStudio", 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 Suggests: covr, testthat (>= 2.1.0) Encoding: UTF-8 RoxygenNote: 7.1.2 NeedsCompilation: yes Packaged: 2021-11-29 23:19:46 UTC; jhester Author: Jim Hester [aut] (), Gábor Csárdi [aut, cre], RStudio [cph, fnd] Maintainer: Gábor Csárdi Repository: CRAN Date/Publication: 2021-11-30 13:10:02 UTC brio/README.md0000644000175000017500000000660214151257606012631 0ustar nileshnilesh # brio - Basic R Input Output [![Codecov test coverage](https://codecov.io/gh/r-lib/brio/branch/master/graph/badge.svg)](https://app.codecov.io/gh/r-lib/brio?branch=master) [![R build status](https://github.com/r-lib/brio/workflows/R-CMD-check/badge.svg)](https://github.com/r-lib/brio/actions) 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") 676.56µs 694.67µs 1382. 8.05KB 0 #> 2 readr::read_lines("benchmark") 3.87ms 4.19ms 235. 7.2MB 8.70 #> 3 base::readLines("benchmark") 3.68ms 3.92ms 250. 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") 833.8µs 1.3ms 751. 0B #> 2 readr::write_lines(data, "benchmark") 11.86ms 13ms 76.5 195KB #> 3 base::writeLines(data, "benchmark") 1.07ms 1.52ms 636. 0B #> # … with 1 more variable: gc/sec unlink("benchmark") ``` brio/man/0000755000175000017500000000000014151257263012120 5ustar nileshnileshbrio/man/read_lines.Rd0000644000175000017500000000131114151257263014510 0ustar nileshnilesh% 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/file_line_endings.Rd0000644000175000017500000000140113636657476016061 0ustar nileshnilesh% 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.Rd0000644000175000017500000000155613636657476014351 0ustar nileshnilesh% 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_lines.Rd0000644000175000017500000000157614151257263014744 0ustar nileshnilesh% 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/writeLines.Rd0000644000175000017500000000251013636711504014532 0ustar nileshnilesh% 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.Rd0000644000175000017500000000116314151257263015412 0ustar nileshnilesh% 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/write_file.Rd0000644000175000017500000000120214151257263014533 0ustar nileshnilesh% 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/man/readLines.Rd0000644000175000017500000000306113636711504014315 0ustar nileshnilesh% 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/src/0000755000175000017500000000000014151260022012117 5ustar nileshnileshbrio/src/read_file.c0000644000175000017500000000203714151257263014214 0ustar nileshnilesh#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 %i 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/brio.c0000644000175000017500000000170514151257263013236 0ustar nileshnilesh#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: %ll", 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/read_file_raw.c0000644000175000017500000000201714151257263015063 0ustar nileshnilesh#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 %i 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/file_line_endings.c0000644000175000017500000000117614151257263015742 0ustar nileshnilesh#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/write_file_raw.c0000644000175000017500000000076114151257263015306 0ustar nileshnilesh#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_file.c0000644000175000017500000000103514151257263014430 0ustar nileshnilesh#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/read_lines.c0000644000175000017500000000713414151257265014414 0ustar nileshnilesh#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[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); error("Allocation of size %i 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); 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); 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); } if (out_num < Rf_xlength(out)) { SETLENGTH(out, out_num); SET_TRUELENGTH(out, out_num); } fclose(fp); free(line.data); UNPROTECT(1); return out; } brio/src/brio.h0000644000175000017500000000015114151257263013235 0ustar nileshnilesh#pragma once #include FILE* open_with_widechar_on_windows(SEXP path, const char* mode); brio/src/init.c0000644000175000017500000000177414151257263013254 0ustar nileshnilesh#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/write_lines.c0000644000175000017500000000202414151257263014622 0ustar nileshnilesh#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/tests/0000755000175000017500000000000013636145041012504 5ustar nileshnileshbrio/tests/testthat/0000755000175000017500000000000014151421252014336 5ustar nileshnileshbrio/tests/testthat/test-read_lines.R0000644000175000017500000000714613722235142017557 0ustar nileshnileshtest_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.R0000644000175000017500000000154314151257263017603 0ustar nileshnileshread_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-read_file_raw.R0000644000175000017500000000076613636462364020252 0ustar nileshnileshtest_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-read_file.R0000644000175000017500000000074113636462267017374 0ustar nileshnileshtest_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-utf8.R0000644000175000017500000000070514151257263016337 0ustar nileshnileshtest_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/test-writeLines.R0000644000175000017500000000051013636662714017600 0ustar nileshnileshtest_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-write_file_raw.R0000644000175000017500000000154414151257263020455 0ustar nileshnileshread_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.R0000644000175000017500000000103113636662735017363 0ustar nileshnileshtest_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.R0000644000175000017500000000315513636661154020004 0ustar nileshnileshread_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") }) brio/tests/testthat/test-file_line_endings.R0000644000175000017500000000073313636463551021115 0ustar nileshnileshtest_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.R0000644000175000017500000000006413636145041014467 0ustar nileshnileshlibrary(testthat) library(brio) test_check("brio") brio/R/0000755000175000017500000000000014151257263011546 5ustar nileshnileshbrio/R/write_file_raw.R0000644000175000017500000000127314151257263014676 0ustar nileshnilesh#' 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/readLines.R0000644000175000017500000000355113636711501013600 0ustar nileshnilesh#' 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/package.R0000644000175000017500000000005613636145041013262 0ustar nileshnilesh#' @useDynLib brio, .registration = TRUE NULL brio/R/read_lines.R0000644000175000017500000000125614151257263014002 0ustar nileshnilesh#' 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.R0000644000175000017500000000121514037327221013575 0ustar nileshnilesh#' 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/writeLines.R0000644000175000017500000000243313636711472014024 0ustar nileshnilesh#' 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/write_file.R0000644000175000017500000000150414151257263014022 0ustar nileshnilesh#' 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/write_lines.R0000644000175000017500000000176614151257263014227 0ustar nileshnilesh#' 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.R0000644000175000017500000000115614037327204015325 0ustar nileshnilesh#' 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/read_file_raw.R0000644000175000017500000000022514037327215014451 0ustar nileshnilesh#' @rdname read_file #' @export read_file_raw <- function(path) { path <- normalizePath(path, mustWork = TRUE) .Call(brio_read_file_raw, path) } brio/LICENSE0000644000175000017500000000004513636717536012364 0ustar nileshnileshYEAR: 2020 COPYRIGHT HOLDER: RStudio brio/NAMESPACE0000644000175000017500000000041414151257637012570 0ustar nileshnilesh# 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)