Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 14 additions & 14 deletions .github/workflows/R-CMD-check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ on:
push:
branches: [main, master]
pull_request:
branches: [main, master]

name: R-CMD-check
name: R-CMD-check.yaml

permissions: read-all

jobs:
R-CMD-check:
Expand All @@ -25,24 +26,22 @@ jobs:
- {os: macos-latest, r: 'release'}

- {os: windows-latest, r: 'release'}
# Use 3.6 to trigger usage of RTools35
- {os: windows-latest, r: '3.6'}
# use 4.1 to check with rtools40's older compiler
- {os: windows-latest, r: '4.1'}

- {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'}
- {os: ubuntu-latest, r: 'release'}
- {os: ubuntu-latest, r: 'oldrel-1'}
- {os: ubuntu-latest, r: 'oldrel-2'}
- {os: ubuntu-latest, r: 'oldrel-3'}
- {os: ubuntu-latest, r: 'oldrel-4'}
# use 4.0 or 4.1 to check with rtools40's older compiler
- {os: windows-latest, r: 'oldrel-4'}

- {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'}
- {os: ubuntu-latest, r: 'release'}
- {os: ubuntu-latest, r: 'oldrel-1'}
- {os: ubuntu-latest, r: 'oldrel-2'}
- {os: ubuntu-latest, r: 'oldrel-3'}
- {os: ubuntu-latest, r: 'oldrel-4'}

env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
R_KEEP_PKG_SOURCE: yes

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: r-lib/actions/setup-pandoc@v2

Expand All @@ -60,3 +59,4 @@ jobs:
- uses: r-lib/actions/check-r-package@v2
with:
upload-snapshots: true
build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")'
9 changes: 5 additions & 4 deletions .github/workflows/pkgdown.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
release:
types: [published]
workflow_dispatch:

name: pkgdown
name: pkgdown.yaml

permissions: read-all

jobs:
pkgdown:
Expand All @@ -22,7 +23,7 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: r-lib/actions/setup-pandoc@v2

Expand All @@ -41,7 +42,7 @@ jobs:

- name: Deploy to GitHub pages 🚀
if: github.event_name != 'pull_request'
uses: JamesIves/github-pages-deploy-action@v4.4.1
uses: JamesIves/github-pages-deploy-action@v4.5.0
with:
clean: false
branch: gh-pages
Expand Down
12 changes: 9 additions & 3 deletions .github/workflows/pr-commands.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ on:
issue_comment:
types: [created]

name: Commands
name: pr-commands.yaml

permissions: read-all

jobs:
document:
Expand All @@ -13,8 +15,10 @@ jobs:
runs-on: ubuntu-latest
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
permissions:
contents: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: r-lib/actions/pr-fetch@v2
with:
Expand Down Expand Up @@ -50,8 +54,10 @@ jobs:
runs-on: ubuntu-latest
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
permissions:
contents: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: r-lib/actions/pr-fetch@v2
with:
Expand Down
26 changes: 19 additions & 7 deletions .github/workflows/test-coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ on:
push:
branches: [main, master]
pull_request:
branches: [main, master]

name: test-coverage
name: test-coverage.yaml

permissions: read-all

jobs:
test-coverage:
Expand All @@ -15,36 +16,47 @@ jobs:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: r-lib/actions/setup-r@v2
with:
use-public-rspm: true

- uses: r-lib/actions/setup-r-dependencies@v2
with:
extra-packages: any::covr
extra-packages: any::covr, any::xml2
needs: coverage

- name: Test coverage
run: |
covr::codecov(
cov <- covr::package_coverage(
quiet = FALSE,
clean = FALSE,
install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package")
)
print(cov)
covr::to_cobertura(cov)
shell: Rscript {0}

- uses: codecov/codecov-action@v5
with:
# Fail if error if not on PR, or if on PR and token is given
fail_ci_if_error: ${{ github.event_name != 'pull_request' || secrets.CODECOV_TOKEN }}
files: ./cobertura.xml
plugins: noop
disable_search: true
token: ${{ secrets.CODECOV_TOKEN }}

- name: Show testthat output
if: always()
run: |
## --------------------------------------------------------------------
find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true
find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true
shell: bash

- name: Upload test results
if: failure()
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: coverage-test-failures
path: ${{ runner.temp }}/package
2 changes: 1 addition & 1 deletion README.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ knitr::opts_chunk$set(
<!-- badges: start -->
[![CRAN status](https://www.r-pkg.org/badges/version/haven)](https://cran.r-project.org/package=haven)
[![R-CMD-check](https://github.com/tidyverse/haven/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/tidyverse/haven/actions/workflows/R-CMD-check.yaml)
[![Codecov test coverage](https://codecov.io/gh/tidyverse/haven/branch/main/graph/badge.svg)](https://app.codecov.io/gh/tidyverse/haven?branch=main)
[![Codecov test coverage](https://codecov.io/gh/tidyverse/haven/graph/badge.svg)](https://app.codecov.io/gh/tidyverse/haven)
<!-- badges: end -->

## Overview
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
status](https://www.r-pkg.org/badges/version/haven)](https://cran.r-project.org/package=haven)
[![R-CMD-check](https://github.com/tidyverse/haven/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/tidyverse/haven/actions/workflows/R-CMD-check.yaml)
[![Codecov test
coverage](https://codecov.io/gh/tidyverse/haven/branch/main/graph/badge.svg)](https://app.codecov.io/gh/tidyverse/haven?branch=main)
coverage](https://codecov.io/gh/tidyverse/haven/graph/badge.svg)](https://app.codecov.io/gh/tidyverse/haven)
<!-- badges: end -->

## Overview
Expand Down
6 changes: 3 additions & 3 deletions src/cpp11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ extern "C" SEXP _haven_write_xpt_(SEXP data, SEXP path, SEXP version, SEXP name,

extern "C" {
/* .Call calls */
extern SEXP is_tagged_na_(void *, void *);
extern SEXP na_tag_(void *);
extern SEXP tagged_na_(void *);
extern SEXP is_tagged_na_(SEXP, SEXP);
extern SEXP na_tag_(SEXP);
extern SEXP tagged_na_(SEXP);

static const R_CallMethodDef CallEntries[] = {
{"_haven_df_parse_dta_file", (DL_FUNC) &_haven_df_parse_dta_file, 6},
Expand Down
17 changes: 16 additions & 1 deletion src/readstat/readstat.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,22 @@ typedef enum readstat_error_e {
READSTAT_ERROR_TOO_FEW_COLUMNS,
READSTAT_ERROR_TOO_MANY_COLUMNS,
READSTAT_ERROR_NAME_IS_ZERO_LENGTH,
READSTAT_ERROR_BAD_TIMESTAMP_VALUE
READSTAT_ERROR_BAD_TIMESTAMP_VALUE,
READSTAT_ERROR_BAD_MR_STRING
} readstat_error_t;

const char *readstat_error_message(readstat_error_t error_code);

typedef struct mr_set_s {
char type;
char *name;
char *label;
int is_dichotomy;
int counted_value;
char **subvariables;
int num_subvars;
} mr_set_t;

typedef struct readstat_metadata_s {
int64_t row_count;
int64_t var_count;
Expand All @@ -121,6 +132,8 @@ typedef struct readstat_metadata_s {
const char *file_label;
const char *file_encoding;
unsigned int is64bit:1;
size_t multiple_response_sets_length;
mr_set_t *mr_sets;
} readstat_metadata_t;

/* If the row count is unknown (e.g. it's an XPORT or POR file, or an SAV
Expand All @@ -138,6 +151,8 @@ readstat_endian_t readstat_get_endianness(readstat_metadata_t *metadata);
const char *readstat_get_table_name(readstat_metadata_t *metadata);
const char *readstat_get_file_label(readstat_metadata_t *metadata);
const char *readstat_get_file_encoding(readstat_metadata_t *metadata);
const mr_set_t *readstat_get_multiple_response_sets(readstat_metadata_t *metadata);
size_t readstat_get_multiple_response_sets_length(readstat_metadata_t *metadata);

typedef struct readstat_value_s {
union {
Expand Down
8 changes: 8 additions & 0 deletions src/readstat/readstat_metadata.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,11 @@ const char *readstat_get_file_encoding(readstat_metadata_t *metadata) {
const char *readstat_get_table_name(readstat_metadata_t *metadata) {
return metadata->table_name;
}

size_t readstat_get_multiple_response_sets_length(readstat_metadata_t *metadata) {
return metadata->multiple_response_sets_length;
}

const mr_set_t *readstat_get_multiple_response_sets(readstat_metadata_t *metadata) {
return metadata->mr_sets;
}
8 changes: 4 additions & 4 deletions src/readstat/sas/ieee.c
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ void ieee2xpt(unsigned char *ieee, unsigned char *xport) {
shift = (int)
(ieee_exp = (int)(((ieee1 >> 16) & 0x7ff0) >> 4) - 1023)
& 3;
/* the ieee format has an implied "1" immdeiately to the left */
/* the ieee format has an implied "1" immediately to the left */
/* of the binary point. Show it in here. */
xport1 |= 0x00100000;
if (shift)
Expand All @@ -377,7 +377,7 @@ void ieee2xpt(unsigned char *ieee, unsigned char *xport) {
/* from the lower half that would have been shifted in (if */
/* we could shift a double). The shift count can never */
/* exceed 3, so all we care about are the high order 3 */
/* bits. We don't want sign extention so make sure it's an */
/* bits. We don't want sign extension so make sure it's an */
/* unsigned char. We'll shift either5, 6, or 7 places to */
/* keep 3, 2, or 1 bits. After that, shift the second half */
/* of the number the right number of places. We always get */
Expand All @@ -391,9 +391,9 @@ void ieee2xpt(unsigned char *ieee, unsigned char *xport) {

/* Now set the ibm exponent and the sign of the fraction. The */
/* power of 2 ieee exponent must be divided by 4 and made */
/* excess 64 (we add 65 here because of the poisition of the */
/* excess 64 (we add 65 here because of the position of the */
/* fraction bits, essentially 4 positions lower than they */
/* should be so we incrment the ibm exponent). */
/* should be so we increment the ibm exponent). */

xport1 |=

Expand Down
33 changes: 24 additions & 9 deletions src/readstat/sas/readstat_sas.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ static time_t sas_epoch(void) {
return - 3653 * 86400; // seconds between 01-01-1960 and 01-01-1970
}

static time_t sas_convert_time(double time, time_t epoch) {
static time_t sas_convert_time(double time, double time_diff, time_t epoch) {
time -= time_diff;
time += epoch;
if (isnan(time))
return 0;
Expand Down Expand Up @@ -212,7 +213,7 @@ readstat_error_t sas_read_header(readstat_io_t *io, sas_header_info_t *hinfo,
goto cleanup;
}

double creation_time, modification_time;
double creation_time, modification_time, creation_time_diff, modification_time_diff;

if (io->read(&creation_time, sizeof(double), io->io_ctx) < sizeof(double)) {
retval = READSTAT_ERROR_READ;
Expand All @@ -228,13 +229,22 @@ readstat_error_t sas_read_header(readstat_io_t *io, sas_header_info_t *hinfo,
if (bswap)
modification_time = byteswap_double(modification_time);

hinfo->creation_time = sas_convert_time(creation_time, epoch);
hinfo->modification_time = sas_convert_time(modification_time, epoch);

if (io->seek(16, READSTAT_SEEK_CUR, io->io_ctx) == -1) {
retval = READSTAT_ERROR_SEEK;
if (io->read(&creation_time_diff, sizeof(double), io->io_ctx) < sizeof(double)) {
retval = READSTAT_ERROR_READ;
goto cleanup;
}
if (bswap)
creation_time_diff = byteswap_double(creation_time_diff);

if (io->read(&modification_time_diff, sizeof(double), io->io_ctx) < sizeof(double)) {
retval = READSTAT_ERROR_READ;
goto cleanup;
}
if (bswap)
modification_time_diff = byteswap_double(modification_time_diff);

hinfo->creation_time = sas_convert_time(creation_time, creation_time_diff, epoch);
hinfo->modification_time = sas_convert_time(modification_time, modification_time_diff, epoch);

uint32_t header_size, page_size;

Expand Down Expand Up @@ -299,9 +309,9 @@ readstat_error_t sas_read_header(readstat_io_t *io, sas_header_info_t *hinfo,
retval = READSTAT_ERROR_READ;
goto cleanup;
}
char major;
char major, revision_tag;
int minor, revision;
if (sscanf(header_end.release, "%c.%04dM%1d", &major, &minor, &revision) != 3) {
if (sscanf(header_end.release, "%c.%04d%c%1d", &major, &minor, &revision_tag, &revision) != 4) {
retval = READSTAT_ERROR_PARSE;
goto cleanup;
}
Expand All @@ -316,6 +326,11 @@ readstat_error_t sas_read_header(readstat_io_t *io, sas_header_info_t *hinfo,
retval = READSTAT_ERROR_PARSE;
goto cleanup;
}
// revision_tag is usually M, but J has been observed in the wild (not created with SAS?)
if (revision_tag != 'M' && revision_tag != 'J') {
retval = READSTAT_ERROR_PARSE;
goto cleanup;
}
hinfo->minor_version = minor;
hinfo->revision = revision;

Expand Down
Loading
Loading