diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 5b6585375e..213d883723 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -40,9 +40,10 @@ jobs: sudo apt install libxcb-xkb-dev libxcb-xkb1 libxcb-xinerama0 libxkbcommon-dev libxkbcommon-x11-dev autoconf zlib1g zlib1g-dev cmake sudo apt install gfortran build-essential flex libssl-dev libgl1-mesa-dev libsqlite3-dev sudo apt install libharfbuzz-dev libfribidi-dev libfreetype6-dev libpng-dev libtiff5-dev libjpeg-dev #required by some r packgaes - sudo apt install libglpk-dev libcurl4-openssl-dev libmpfr-dev libfontconfig1-dev libcairo2-dev #required by some r packages + sudo apt install libglpk-dev libcurl4-openssl-dev libmpfr-dev libfontconfig1-dev libcairo2-dev netcdf-bin #required by some r packages sudo apt install jags sudo apt install libminizip-dev # required by freexl + sudo apt install librdata-dev git clone https://github.com/jasp-stats/freexl.git cd freexl && ./configure && make && sudo make install diff --git a/Common/utilenums.h b/Common/utilenums.h index a51fecf8c5..a0b618a841 100644 --- a/Common/utilenums.h +++ b/Common/utilenums.h @@ -2,7 +2,7 @@ #define UTILENUMS_H #include "enumutilities.h" -DECLARE_ENUM(FileTypeBase, jasp = 0, html, csv, txt, tsv, sav, zsav, ods, xls, xlsx, pdf, sas7bdat, sas7bcat, por, xpt, dta, database, empty, unknown ); +DECLARE_ENUM(FileTypeBase, jasp = 0, html, csv, txt, tsv, sav, zsav, ods, xls, xlsx, pdf, sas7bdat, sas7bcat, por, xpt, dta, database, rdata, rds, empty, unknown ); //const QStringList Database::dbTypes() const should be updated if DbType is changed. DECLARE_ENUM(DbType, NOTCHOSEN, QDB2, /*QIBASE,*/ QMYSQL, QOCI, QODBC, QPSQL, QSQLITE /*, QSQLITE2, QTDS*/ ); diff --git a/Desktop/CMakeLists.txt b/Desktop/CMakeLists.txt index 6e7afaf733..f70e1fe637 100644 --- a/Desktop/CMakeLists.txt +++ b/Desktop/CMakeLists.txt @@ -106,8 +106,9 @@ target_include_directories( ${PROJECT_SOURCE_DIR}/CommonData ${PROJECT_SOURCE_DIR}/QMLComponents # ReadStat - $<$:${RTOOLS_LIBREADSTAT_H}> ${LIBREADSTAT_INCLUDE_DIRS} + # librdata + ${LIBRDATA_INCLUDE_DIRS} # JSONCPP $<$:${_PKGCONFIG_LIB_JSONCPP_INCLUDEDIR}> $<$:/app/include/QtCore5Compat> @@ -158,6 +159,9 @@ target_link_libraries( ${LIBREADSTAT_LIBRARIES} # MinGW's ReadStat $<$:${RTOOLS_LIBREADSTAT_DLL_A}> + # librdata ----------------------------------- + ${LIBRDATA_LIBRARIES} + $<$:${RTOOLS_LIBRDATA_DLL_A}> # JSONCPP #$<$:${_PKGCONFIG_LIB_JSONCPP_LIBRARIES}> #$<$:${_PKGCONFIG_LIB_JSONCPP_LINK_LIBRARIES}> diff --git a/Desktop/data/datasetloader.cpp b/Desktop/data/datasetloader.cpp index 6f37f87638..b3cbc07b17 100644 --- a/Desktop/data/datasetloader.cpp +++ b/Desktop/data/datasetloader.cpp @@ -26,6 +26,7 @@ #include "importers/odsimporter.h" #include "importers/readstatimporter.h" #include "importers/excelimporter.h" +#include "importers/rdataimporter.h" #include @@ -56,6 +57,8 @@ Importer* DataSetLoader::getImporter(const string & locator, const string &ext) if( boost::iequals(ext,".xls") || boost::iequals(ext,".xlsx")) return new ExcelImporter(); if( ReadStatImporter::extSupported(ext)) return new ReadStatImporter(ext); + if( boost::iequals(ext,".rdata") || + boost::iequals(ext,".rds")) return new RDataImporter(ext); return nullptr; //If NULL then JASP will try to load it as a .jasp file (if the extension matches) } diff --git a/Desktop/data/fileevent.cpp b/Desktop/data/fileevent.cpp index 68bc9c3c46..991475238f 100644 --- a/Desktop/data/fileevent.cpp +++ b/Desktop/data/fileevent.cpp @@ -119,7 +119,7 @@ const std::string FileEvent::databaseStr() const QString FileEvent::getProgressMsg() const { - //jasp = 0, html, csv, txt, tsv, sav, zsav, ods, pdf, sas7bdat, sas7bcat, por, xpt, empty, unknown + //jasp = 0, html, csv, txt, tsv, sav, zsav, ods, xls, xlsx, pdf, sas7bdat, sas7bcat, por, xpt, dta, database, rdata, rds, empty, unknown switch(_operation) { case FileEvent::FileOpen: @@ -139,6 +139,8 @@ QString FileEvent::getProgressMsg() const case Utils::FileType::sas7bcat: return tr("Importing SAS File"); case Utils::FileType::dta: return tr("Importing STATA File"); case Utils::FileType::jasp: return tr("Loading JASP File"); + case Utils::FileType::rdata: + case Utils::FileType::rds: return tr("Loading R Data File"); default: return tr("Loading File"); } break; diff --git a/Desktop/data/importers/rdata/rdataimportcolumn.cpp b/Desktop/data/importers/rdata/rdataimportcolumn.cpp new file mode 100644 index 0000000000..1406b295bb --- /dev/null +++ b/Desktop/data/importers/rdata/rdataimportcolumn.cpp @@ -0,0 +1,48 @@ +// +// Copyright (C) 2013-2025 University of Amsterdam +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "rdataimportcolumn.h" +#include "timers.h" + +RDataImportColumn::RDataImportColumn(ImportDataSet* importDataSet, std::string name) : ImportColumn(importDataSet, name) +{ +} + +RDataImportColumn::RDataImportColumn(ImportDataSet *importDataSet, std::string name, long reserve) : ImportColumn(importDataSet, name) +{ + _data.reserve(reserve); +} + +RDataImportColumn::~RDataImportColumn() +{ + JASPTIMER_SCOPE(RDataImportColumn::~RDataImportColumn()); +} + +size_t RDataImportColumn::size() const +{ + return _data.size(); +} + +void RDataImportColumn::addValue(const std::string &value) +{ + _data.push_back(value); +} + +const std::vector &RDataImportColumn::getValues() const +{ + return _data; +} diff --git a/Desktop/data/importers/rdata/rdataimportcolumn.h b/Desktop/data/importers/rdata/rdataimportcolumn.h new file mode 100644 index 0000000000..944e8a83c6 --- /dev/null +++ b/Desktop/data/importers/rdata/rdataimportcolumn.h @@ -0,0 +1,39 @@ +// +// Copyright (C) 2013-2025 University of Amsterdam +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef RDATAIMPORTCOLUMN_H +#define RDATAIMPORTCOLUMN_H + +#include "data/importers/importcolumn.h" + +class RDataImportColumn : public ImportColumn +{ +public: + RDataImportColumn(ImportDataSet *importDataSet, std::string name); + RDataImportColumn(ImportDataSet *importDataSet, std::string name, long reserve); + ~RDataImportColumn() override; + + size_t size() const override; + const stringvec &allValuesAsStrings() const override { return _data; } + void addValue(const std::string &value); + const stringvec &getValues() const; + +private: + stringvec _data; +}; + +#endif // RDATAIMPORTCOLUMN_H diff --git a/Desktop/data/importers/rdata/readrdata.cpp b/Desktop/data/importers/rdata/readrdata.cpp new file mode 100644 index 0000000000..525fc5402d --- /dev/null +++ b/Desktop/data/importers/rdata/readrdata.cpp @@ -0,0 +1,167 @@ +// +// Copyright (C) 2013-2025 University of Amsterdam +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "readrdata.h" +#include "log.h" + +RDataReader::RDataReader(const std::string &locator) +{ + _filePath = locator; +} + +void RDataReader::open() +{ + if (_filePath.empty()) + throw std::runtime_error("File path cannot be empty."); + + _parser = rdata_parser_init(); + + rdata_set_table_handler(_parser, &_tableHandler); + rdata_set_column_handler(_parser, &_columnHandler); + rdata_set_text_value_handler(_parser, &_textValueHandler); + rdata_set_column_name_handler(_parser, &_columnNameHandler); + rdata_set_error_handler(_parser, &_errorHandler); + // rdata_set_value_label_handler(_parser, &_valueLabelHandler); + + rdata_error_t result = rdata_parse(_parser, _filePath.c_str(), &_context); + + _rowCount = _context.row_count; + _colCount = _context.column_count; + _columnNames = _context.column_names; + _column_data = _context.column_data; + + if (result != RDATA_OK) + throw std::runtime_error("Failed to parse file"); + + if (_parser) + rdata_parser_free(_parser); +} + +int RDataReader::_tableHandler(const char *name, void *ctx) +{ + RDataCtx *context = static_cast(ctx); + + if (!name) + context->table_name = "Default_table"; + else + context->table_name = name; + + Log::log() << "Table Name: " << name << std::endl; + + return 0; +} + +int RDataReader::_columnHandler(const char *name, rdata_type_t type, void *data, long count, void *ctx) +{ + + RDataCtx *context = static_cast(ctx); + // Log::log() << "Column name: " << name << ", Type: " << type << ", Count: " << count << std::endl; + + context->column_count++; + + if (count > context->row_count) + { + context->row_count = count; + } + + stringvec column_values; + + if (type == RDATA_TYPE_STRING) + { + // Initialize an empty vector for string type to be filled in _textValueHandler + context->column_data.emplace_back(stringvec(count, "")); + } + else + { + switch (type) + { + case RDATA_TYPE_INT32: + case RDATA_TYPE_LOGICAL: + { + int32_t *values = static_cast(data); + for (size_t i = 0; i < count; i++) + column_values.push_back(std::to_string(values[i])); + break; + } + case RDATA_TYPE_REAL: + { + double *values = static_cast(data); + for (size_t i = 0; i < count; i++) + { + if (std::isnan(values[i])) + column_values.push_back("NA"); + else + column_values.push_back(std::to_string(values[i])); + } + break; + } + default: + Log::log() << "Unsupported data type for column: " << name << std::endl; + break; + } + + context->column_data.push_back(column_values); + } + + return 0; +} + +int RDataReader::_columnNameHandler(const char *value, int index, void *ctx) +{ + RDataCtx *context = static_cast(ctx); + + if (index >= context->column_names.size()) + context->column_names.resize(index + 1); + + context->column_names[index] = value ? std::string(value) : "Column_" + std::to_string(index + 1); + //Log::log() << "Column name : " << value << " [Index " << index << "]: " << context->column_names[index] << std::endl; + + return 0; +} + +void RDataReader::_errorHandler(const char *error_message, void *ctx) +{ + Log::log() << "Error: " << error_message << std::endl; +} + +int RDataReader::_textValueHandler(const char *value, int index, void *ctx) +{ + // This handled if data type in _columnHandler is "RDATA_TYPE_STRING", because it's empty! + RDataCtx *context = static_cast(ctx); + + if (context->column_data.empty()) + { + Log::log() << "Error: _textValueHandler called before _columnHandler." << std::endl; + return 1; // Abort processing + } + + size_t column_index = context->column_data.size() - 1; + if (index >= context->column_data[column_index].size()) + { + context->column_data[column_index].resize(index + 1, ""); + } + + context->column_data[column_index][index] = value ? value : "NA"; + + return 0; +} + +int RDataReader::_valueLabelHandler(const char *value, int index, void *ctx) +{ + // TODO: implement importing factor level as label + return 0; +} diff --git a/Desktop/data/importers/rdata/readrdata.h b/Desktop/data/importers/rdata/readrdata.h new file mode 100644 index 0000000000..1ace636d87 --- /dev/null +++ b/Desktop/data/importers/rdata/readrdata.h @@ -0,0 +1,63 @@ +// +// Copyright (C) 2013-2025 University of Amsterdam +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef RDATA_H +#define RDATA_H + +#include +#include "rdata.h" +#include "utils.h" + +class RDataReader +{ +public: + RDataReader(const std::string &_filePath); + + void open(); + size_t getRowCount() const { return _rowCount; } + size_t getColCount() const { return _colCount; } + stringvec getColumnNames() const { return _columnNames;} + stringvecvec getColData() const { return _column_data;} + +private: + struct RDataCtx + { + size_t column_count = 0; + size_t row_count = 0; + const char *table_name = nullptr; + stringvec column_names; + stringvecvec column_data; + }; + + static int _tableHandler(const char *name, void *ctx); + static int _columnHandler(const char *name, rdata_type_t type, void *data, long count, void *ctx); + static int _columnNameHandler(const char *value, int index, void *ctx); + static int _textValueHandler(const char *value, int index, void *ctx); + static int _valueLabelHandler(const char *value, int index, void *ctx); + static void _errorHandler(const char *error_message, void *ctx); + + std::string _filePath; + rdata_parser_t *_parser; + + RDataCtx _context; + stringvec _columnNames; + size_t _rowCount; + size_t _colCount; + stringvecvec _column_data; +}; + +#endif // RDATA_H diff --git a/Desktop/data/importers/rdataimporter.cpp b/Desktop/data/importers/rdataimporter.cpp new file mode 100644 index 0000000000..2b41c599ad --- /dev/null +++ b/Desktop/data/importers/rdataimporter.cpp @@ -0,0 +1,85 @@ +// +// Copyright (C) 2013-2025 University of Amsterdam +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "rdataimporter.h" +#include "data/importers/rdata/readrdata.h" +#include "data/importers/rdata/rdataimportcolumn.h" +#include "utilities/qutils.h" +#include +#include +#include +#include + +RDataImporter::~RDataImporter() {} + +ImportDataSet *RDataImporter::loadFile(const std::string &locator, std::function progressCallback) +{ + JASPTIMER_RESUME(RDataImporter::loadFile); + + ImportDataSet *data = new ImportDataSet(this); + + std::vector importColumns; + + progressCallback(5); + + RDataReader reader(locator); + reader.open(); + + size_t rowCount, colCount; + stringvec colNames; + + rowCount = reader.getRowCount(); + colCount = reader.getColCount(); + colNames = reader.getColumnNames(); + const auto &columns = reader.getColData(); + + progressCallback(25); + + if (colCount == 0) + throw std::runtime_error(fq(tr("0 valid columns were read from the file, please check your data file."))); + + importColumns.reserve(colCount); + + for (size_t colIndex = 0; colIndex < colCount; ++colIndex) + { + if (colIndex >= colCount || colIndex >= columns.size()) + throw std::runtime_error("Column names or data mismatch."); + + RDataImportColumn *importColumn = new RDataImportColumn(data, colNames[colIndex], rowCount); + + for (size_t rowIndex = 0; rowIndex < rowCount; ++rowIndex) + { + if (static_cast(rowIndex) >= columns[colIndex].size()) + throw std::runtime_error("Row data is out of bounds for column."); + + importColumn->addValue(columns[colIndex][rowIndex]); + } + + importColumns.push_back(importColumn); + } + + for (RDataImportColumn *col : importColumns) + data->addColumn(col); + + progressCallback(100); + + data->buildDictionary(); + + JASPTIMER_STOP(RDataImporter::loadFile); + + return data; +} diff --git a/Desktop/data/importers/rdataimporter.h b/Desktop/data/importers/rdataimporter.h new file mode 100644 index 0000000000..180b3a2a99 --- /dev/null +++ b/Desktop/data/importers/rdataimporter.h @@ -0,0 +1,28 @@ +#ifndef RDATAIMPORTER_H +#define RDATAIMPORTER_H + +#include "importer.h" +#include +#include "timers.h" + + +class RDataImporter : public Importer +{ + +public: + RDataImporter(std::string ext) : Importer(), _ext(stringUtils::toLower(ext)) + { + if(_ext.size() == 0) throw std::runtime_error("Rdata reader NEEDS to know the extension!"); + if(_ext[0] == '.') _ext = _ext.substr(1); + } + ~RDataImporter() override; + +protected: + ImportDataSet* loadFile(const std::string &locator, std::function progressCallback) override; + std::string _ext; + +private: + JASPTIMER_CLASS(RDataImporter); +}; + +#endif // RDATAIMPORTER_H diff --git a/Desktop/data/importers/readstat/readstat.h b/Desktop/data/importers/readstat/readstat.h deleted file mode 100644 index bfa960ceb1..0000000000 --- a/Desktop/data/importers/readstat/readstat.h +++ /dev/null @@ -1,602 +0,0 @@ -// -// Taken from github on 3-7-19 from commit 1f7a3bdc3f173b914a942cde12cbb0a67baa60c7 for version 1.0.1 -// readstat.h - API and internal data structures for ReadStat -// -// Copyright Evan Miller and ReadStat authors (see LICENSE) -// - -#ifndef INCLUDE_READSTAT_H -#define INCLUDE_READSTAT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include -#include - -enum { - READSTAT_HANDLER_OK, - READSTAT_HANDLER_ABORT, - READSTAT_HANDLER_SKIP_VARIABLE -}; - -typedef enum readstat_type_e { - READSTAT_TYPE_STRING, - READSTAT_TYPE_INT8, - READSTAT_TYPE_INT16, - READSTAT_TYPE_INT32, - READSTAT_TYPE_FLOAT, - READSTAT_TYPE_DOUBLE, - READSTAT_TYPE_STRING_REF -} readstat_type_t; - -typedef enum readstat_type_class_e { - READSTAT_TYPE_CLASS_STRING, - READSTAT_TYPE_CLASS_NUMERIC -} readstat_type_class_t; - -typedef enum readstat_measure_e { - READSTAT_MEASURE_UNKNOWN, - READSTAT_MEASURE_NOMINAL = 1, - READSTAT_MEASURE_ORDINAL, - READSTAT_MEASURE_SCALE -} readstat_measure_t; - -typedef enum readstat_alignment_e { - READSTAT_ALIGNMENT_UNKNOWN, - READSTAT_ALIGNMENT_LEFT = 1, - READSTAT_ALIGNMENT_CENTER, - READSTAT_ALIGNMENT_RIGHT -} readstat_alignment_t; - -typedef enum readstat_compress_e { - READSTAT_COMPRESS_NONE, - READSTAT_COMPRESS_ROWS, - READSTAT_COMPRESS_BINARY -} readstat_compress_t; - -typedef enum readstat_endian_e { - READSTAT_ENDIAN_NONE, - READSTAT_ENDIAN_LITTLE, - READSTAT_ENDIAN_BIG -} readstat_endian_t; - -typedef enum readstat_error_e { - READSTAT_OK, - READSTAT_ERROR_OPEN = 1, - READSTAT_ERROR_READ, - READSTAT_ERROR_MALLOC, - READSTAT_ERROR_USER_ABORT, - READSTAT_ERROR_PARSE, - READSTAT_ERROR_UNSUPPORTED_COMPRESSION, - READSTAT_ERROR_UNSUPPORTED_CHARSET, - READSTAT_ERROR_COLUMN_COUNT_MISMATCH, - READSTAT_ERROR_ROW_COUNT_MISMATCH, - READSTAT_ERROR_ROW_WIDTH_MISMATCH, - READSTAT_ERROR_BAD_FORMAT_STRING, - READSTAT_ERROR_VALUE_TYPE_MISMATCH, - READSTAT_ERROR_WRITE, - READSTAT_ERROR_WRITER_NOT_INITIALIZED, - READSTAT_ERROR_SEEK, - READSTAT_ERROR_CONVERT, - READSTAT_ERROR_CONVERT_BAD_STRING, - READSTAT_ERROR_CONVERT_SHORT_STRING, - READSTAT_ERROR_CONVERT_LONG_STRING, - READSTAT_ERROR_NUMERIC_VALUE_IS_OUT_OF_RANGE, - READSTAT_ERROR_TAGGED_VALUE_IS_OUT_OF_RANGE, - READSTAT_ERROR_STRING_VALUE_IS_TOO_LONG, - READSTAT_ERROR_TAGGED_VALUES_NOT_SUPPORTED, - READSTAT_ERROR_UNSUPPORTED_FILE_FORMAT_VERSION, - READSTAT_ERROR_NAME_BEGINS_WITH_ILLEGAL_CHARACTER, - READSTAT_ERROR_NAME_CONTAINS_ILLEGAL_CHARACTER, - READSTAT_ERROR_NAME_IS_RESERVED_WORD, - READSTAT_ERROR_NAME_IS_TOO_LONG, - READSTAT_ERROR_BAD_TIMESTAMP, - READSTAT_ERROR_BAD_FREQUENCY_WEIGHT, - READSTAT_ERROR_TOO_MANY_MISSING_VALUE_DEFINITIONS, - READSTAT_ERROR_NOTE_IS_TOO_LONG, - READSTAT_ERROR_STRING_REFS_NOT_SUPPORTED, - READSTAT_ERROR_STRING_REF_IS_REQUIRED, - READSTAT_ERROR_ROW_IS_TOO_WIDE_FOR_PAGE, - READSTAT_ERROR_TOO_FEW_COLUMNS, - READSTAT_ERROR_TOO_MANY_COLUMNS, - READSTAT_ERROR_NAME_IS_ZERO_LENGTH -} readstat_error_t; - -const char *readstat_error_message(readstat_error_t error_code); - -typedef struct readstat_metadata_s { - int64_t row_count; - int64_t var_count; - time_t creation_time; - time_t modified_time; - int64_t file_format_version; - readstat_compress_t compression; - readstat_endian_t endianness; - const char *table_name; - const char *file_label; - const char *file_encoding; - unsigned int is64bit:1; -} readstat_metadata_t; - -int readstat_get_row_count(readstat_metadata_t *metadata); -int readstat_get_var_count(readstat_metadata_t *metadata); -time_t readstat_get_creation_time(readstat_metadata_t *metadata); -time_t readstat_get_modified_time(readstat_metadata_t *metadata); -int readstat_get_file_format_version(readstat_metadata_t *metadata); -int readstat_get_file_format_is_64bit(readstat_metadata_t *metadata); -readstat_compress_t readstat_get_compression(readstat_metadata_t *metadata); -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); - -typedef struct readstat_value_s { - union { - float float_value; - double double_value; - int8_t i8_value; - int16_t i16_value; - int32_t i32_value; - const char *string_value; - } v; - readstat_type_t type; - char tag; - unsigned int is_system_missing:1; - unsigned int is_tagged_missing:1; -} readstat_value_t; - -/* Internal data structures */ -typedef struct readstat_value_label_s { - double double_key; - int32_t int32_key; - char tag; - - char *string_key; - size_t string_key_len; - - char *label; - size_t label_len; -} readstat_value_label_t; - -typedef struct readstat_label_set_s { - readstat_type_t type; - char name[256]; - - readstat_value_label_t *value_labels; - long value_labels_count; - long value_labels_capacity; - - void *variables; - long variables_count; - long variables_capacity; -} readstat_label_set_t; - -typedef struct readstat_missingness_s { - readstat_value_t missing_ranges[32]; - long missing_ranges_count; -} readstat_missingness_t; - -typedef struct readstat_variable_s { - readstat_type_t type; - int index; - char name[300]; - char format[256]; - char label[1024]; - readstat_label_set_t *label_set; - off_t offset; - size_t storage_width; - size_t user_width; - readstat_missingness_t missingness; - readstat_measure_t measure; - readstat_alignment_t alignment; - int display_width; - int decimals; - int skip; - int index_after_skipping; -} readstat_variable_t; - -typedef struct readstat_schema_entry_s { - int row; - int col; - int len; - int skip; - readstat_variable_t variable; - char labelset[32]; - char decimal_separator; -} readstat_schema_entry_t; - -typedef struct readstat_schema_s { - char filename[255]; - int rows_per_observation; - int cols_per_observation; - int first_line; - int entry_count; - char field_delimiter; - readstat_schema_entry_t *entries; -} readstat_schema_t; - -/* Value accessors */ -readstat_type_t readstat_value_type(readstat_value_t value); -readstat_type_class_t readstat_value_type_class(readstat_value_t value); - -/* Values can be missing in one of three ways: - * 1. "System missing", delivered to value handlers as NaN. Occurs in all file - * types. The most common kind of missing value. - * 2. Tagged missing, also delivered as NaN, but with a single character tag - * accessible via readstat_value_tag(). The tag might be 'a', 'b', etc, - * corresponding to Stata's .a, .b, values etc. Occurs only in Stata and - * SAS files. - * 3. Defined missing. The value is a real number but is to be treated as - * missing according to the variable's missingness rules (such as "value < 0 || - * value == 999"). Occurs only in SPSS files. access the rules via: - * - * readstat_variable_get_missing_ranges_count() - * readstat_variable_get_missing_range_lo() - * readstat_variable_get_missing_range_hi() - * - * Note that "ranges" include individual values where lo == hi. - * - * readstat_value_is_missing() is equivalent to: - * - * (readstat_value_is_system_missing() - * || readstat_value_is_tagged_missing() - * || readstat_value_is_defined_missing()) - */ -int readstat_value_is_missing(readstat_value_t value, readstat_variable_t *variable); -int readstat_value_is_system_missing(readstat_value_t value); -int readstat_value_is_tagged_missing(readstat_value_t value); -int readstat_value_is_defined_missing(readstat_value_t value, readstat_variable_t *variable); -char readstat_value_tag(readstat_value_t value); - -char readstat_int8_value(readstat_value_t value); -int16_t readstat_int16_value(readstat_value_t value); -int32_t readstat_int32_value(readstat_value_t value); -float readstat_float_value(readstat_value_t value); -double readstat_double_value(readstat_value_t value); -const char *readstat_string_value(readstat_value_t value); - -readstat_type_class_t readstat_type_class(readstat_type_t type); - -/* Accessor methods for use inside variable handlers */ -int readstat_variable_get_index(const readstat_variable_t *variable); -int readstat_variable_get_index_after_skipping(const readstat_variable_t *variable); -const char *readstat_variable_get_name(const readstat_variable_t *variable); -const char *readstat_variable_get_label(const readstat_variable_t *variable); -const char *readstat_variable_get_format(const readstat_variable_t *variable); -readstat_type_t readstat_variable_get_type(const readstat_variable_t *variable); -readstat_type_class_t readstat_variable_get_type_class(const readstat_variable_t *variable); -size_t readstat_variable_get_storage_width(const readstat_variable_t *variable); -int readstat_variable_get_display_width(const readstat_variable_t *variable); -readstat_measure_t readstat_variable_get_measure(const readstat_variable_t *variable); -readstat_alignment_t readstat_variable_get_alignment(const readstat_variable_t *variable); - -int readstat_variable_get_missing_ranges_count(const readstat_variable_t *variable); -readstat_value_t readstat_variable_get_missing_range_lo(const readstat_variable_t *variable, int i); -readstat_value_t readstat_variable_get_missing_range_hi(const readstat_variable_t *variable, int i); - -/* Callbacks should return 0 (aka READSTAT_HANDLER_OK) on success and 1 (aka READSTAT_HANDLER_ABORT) to abort. */ -/* If the variable handler returns READSTAT_HANDLER_SKIP_VARIABLE, the value handler will not be called on - * the associated variable. (Note that subsequent variables will retain their original index values.) - */ -typedef int (*readstat_metadata_handler)(readstat_metadata_t *metadata, void *ctx); -typedef int (*readstat_note_handler)(int note_index, const char *note, void *ctx); -typedef int (*readstat_variable_handler)(int index, readstat_variable_t *variable, - const char *val_labels, void *ctx); -typedef int (*readstat_fweight_handler)(readstat_variable_t *variable, void *ctx); -typedef int (*readstat_value_handler)(int obs_index, readstat_variable_t *variable, - readstat_value_t value, void *ctx); -typedef int (*readstat_value_label_handler)(const char *val_labels, - readstat_value_t value, const char *label, void *ctx); -typedef void (*readstat_error_handler)(const char *error_message, void *ctx); -typedef int (*readstat_progress_handler)(double progress, void *ctx); - -#if defined _WIN32 || defined __CYGWIN__ -typedef _off64_t readstat_off_t; -#elif defined _AIX -typedef off64_t readstat_off_t; -#else -typedef off_t readstat_off_t; -#endif - -typedef enum readstat_io_flags_e { - READSTAT_SEEK_SET, - READSTAT_SEEK_CUR, - READSTAT_SEEK_END -} readstat_io_flags_t; - -typedef int (*readstat_open_handler)(const char *path, void *io_ctx); -typedef int (*readstat_close_handler)(void *io_ctx); -typedef readstat_off_t (*readstat_seek_handler)(readstat_off_t offset, readstat_io_flags_t whence, void *io_ctx); -typedef ssize_t (*readstat_read_handler)(void *buf, size_t nbyte, void *io_ctx); -typedef readstat_error_t (*readstat_update_handler)(long file_size, readstat_progress_handler progress_handler, void *user_ctx, void *io_ctx); - -typedef struct readstat_io_s { - readstat_open_handler open; - readstat_close_handler close; - readstat_seek_handler seek; - readstat_read_handler read; - readstat_update_handler update; - void *io_ctx; - int io_ctx_needs_free; -} readstat_io_t; - -typedef struct readstat_callbacks_s { - readstat_metadata_handler metadata; - readstat_note_handler note; - readstat_variable_handler variable; - readstat_fweight_handler fweight; - readstat_value_handler value; - readstat_value_label_handler value_label; - readstat_error_handler error; - readstat_progress_handler progress; -} readstat_callbacks_t; - -typedef struct readstat_parser_s { - readstat_callbacks_t handlers; - readstat_io_t *io; - const char *input_encoding; - const char *output_encoding; - long row_limit; -} readstat_parser_t; - -readstat_parser_t *readstat_parser_init(void); -void readstat_parser_free(readstat_parser_t *parser); -void readstat_io_free(readstat_io_t *io); - -readstat_error_t readstat_set_metadata_handler(readstat_parser_t *parser, readstat_metadata_handler metadata_handler); -readstat_error_t readstat_set_note_handler(readstat_parser_t *parser, readstat_note_handler note_handler); -readstat_error_t readstat_set_variable_handler(readstat_parser_t *parser, readstat_variable_handler variable_handler); -readstat_error_t readstat_set_fweight_handler(readstat_parser_t *parser, readstat_fweight_handler fweight_handler); -readstat_error_t readstat_set_value_handler(readstat_parser_t *parser, readstat_value_handler value_handler); -readstat_error_t readstat_set_value_label_handler(readstat_parser_t *parser, readstat_value_label_handler value_label_handler); -readstat_error_t readstat_set_error_handler(readstat_parser_t *parser, readstat_error_handler error_handler); -readstat_error_t readstat_set_progress_handler(readstat_parser_t *parser, readstat_progress_handler progress_handler); - -readstat_error_t readstat_set_open_handler(readstat_parser_t *parser, readstat_open_handler open_handler); -readstat_error_t readstat_set_close_handler(readstat_parser_t *parser, readstat_close_handler close_handler); -readstat_error_t readstat_set_seek_handler(readstat_parser_t *parser, readstat_seek_handler seek_handler); -readstat_error_t readstat_set_read_handler(readstat_parser_t *parser, readstat_read_handler read_handler); -readstat_error_t readstat_set_update_handler(readstat_parser_t *parser, readstat_update_handler update_handler); -readstat_error_t readstat_set_io_ctx(readstat_parser_t *parser, void *io_ctx); - -// Usually inferred from the file, but sometimes a manual override is desirable. -// In particular, pre-14 Stata uses the system encoding, which is usually Win 1252 -// but could be anything. `encoding' should be an iconv-compatible name. -readstat_error_t readstat_set_file_character_encoding(readstat_parser_t *parser, const char *encoding); - -// Defaults to UTF-8. Pass in NULL to disable transliteration. -readstat_error_t readstat_set_handler_character_encoding(readstat_parser_t *parser, const char *encoding); - -readstat_error_t readstat_set_row_limit(readstat_parser_t *parser, long row_limit); - -/* Parse binary / portable files */ -readstat_error_t readstat_parse_dta(readstat_parser_t *parser, const char *path, void *user_ctx); -readstat_error_t readstat_parse_sav(readstat_parser_t *parser, const char *path, void *user_ctx); -readstat_error_t readstat_parse_por(readstat_parser_t *parser, const char *path, void *user_ctx); -readstat_error_t readstat_parse_sas7bdat(readstat_parser_t *parser, const char *path, void *user_ctx); -readstat_error_t readstat_parse_sas7bcat(readstat_parser_t *parser, const char *path, void *user_ctx); -readstat_error_t readstat_parse_xport(readstat_parser_t *parser, const char *path, void *user_ctx); - -/* Parse a schema file... */ -readstat_schema_t *readstat_parse_sas_commands(readstat_parser_t *parser, - const char *filepath, void *user_ctx, readstat_error_t *outError); -readstat_schema_t *readstat_parse_spss_commands(readstat_parser_t *parser, - const char *filepath, void *user_ctx, readstat_error_t *outError); -readstat_schema_t *readstat_parse_stata_dictionary(readstat_parser_t *parser, - const char *filepath, void *user_ctx, readstat_error_t *outError); - -/* ... then pass the schema to the plain-text parser ... */ -readstat_error_t readstat_parse_txt(readstat_parser_t *parser, const char *filename, - readstat_schema_t *schema, void *user_ctx); - -/* ... and free the schema structure */ -void readstat_schema_free(readstat_schema_t *schema); - -/* Internal module callbacks */ -typedef struct readstat_string_ref_s { - int64_t first_v; - int64_t first_o; - size_t len; - char data[1]; // Flexible array; using [1] for C++98 compatibility -} readstat_string_ref_t; - -typedef size_t (*readstat_variable_width_callback)(readstat_type_t type, size_t user_width); -typedef readstat_error_t (*readstat_variable_ok_callback)(const readstat_variable_t *variable); - -typedef readstat_error_t (*readstat_write_int8_callback)(void *row_data, const readstat_variable_t *variable, int8_t value); -typedef readstat_error_t (*readstat_write_int16_callback)(void *row_data, const readstat_variable_t *variable, int16_t value); -typedef readstat_error_t (*readstat_write_int32_callback)(void *row_data, const readstat_variable_t *variable, int32_t value); -typedef readstat_error_t (*readstat_write_float_callback)(void *row_data, const readstat_variable_t *variable, float value); -typedef readstat_error_t (*readstat_write_double_callback)(void *row_data, const readstat_variable_t *variable, double value); -typedef readstat_error_t (*readstat_write_string_callback)(void *row_data, const readstat_variable_t *variable, const char *value); -typedef readstat_error_t (*readstat_write_string_ref_callback)(void *row_data, const readstat_variable_t *variable, readstat_string_ref_t *ref); -typedef readstat_error_t (*readstat_write_missing_callback)(void *row_data, const readstat_variable_t *variable); -typedef readstat_error_t (*readstat_write_tagged_callback)(void *row_data, const readstat_variable_t *variable, char tag); - -typedef readstat_error_t (*readstat_begin_data_callback)(void *writer); -typedef readstat_error_t (*readstat_write_row_callback)(void *writer, void *row_data, size_t row_len); -typedef readstat_error_t (*readstat_end_data_callback)(void *writer); -typedef void (*readstat_module_ctx_free_callback)(void *module_ctx); -typedef readstat_error_t (*readstat_metadata_ok_callback)(void *writer); - -typedef struct readstat_writer_callbacks_s { - readstat_variable_width_callback variable_width; - readstat_variable_ok_callback variable_ok; - readstat_write_int8_callback write_int8; - readstat_write_int16_callback write_int16; - readstat_write_int32_callback write_int32; - readstat_write_float_callback write_float; - readstat_write_double_callback write_double; - readstat_write_string_callback write_string; - readstat_write_string_ref_callback write_string_ref; - readstat_write_missing_callback write_missing_string; - readstat_write_missing_callback write_missing_number; - readstat_write_tagged_callback write_missing_tagged; - readstat_begin_data_callback begin_data; - readstat_write_row_callback write_row; - readstat_end_data_callback end_data; - readstat_module_ctx_free_callback module_ctx_free; - readstat_metadata_ok_callback metadata_ok; -} readstat_writer_callbacks_t; - -/* You'll need to define one of these to get going. Should return # bytes written, - * or -1 on error, a la write(2) */ -typedef ssize_t (*readstat_data_writer)(const void *data, size_t len, void *ctx); - -typedef struct readstat_writer_s { - readstat_data_writer data_writer; - size_t bytes_written; - long version; - int is_64bit; // SAS only - readstat_compress_t compression; - time_t timestamp; - - readstat_variable_t **variables; - long variables_count; - long variables_capacity; - - readstat_label_set_t **label_sets; - long label_sets_count; - long label_sets_capacity; - - char **notes; - long notes_count; - long notes_capacity; - - readstat_string_ref_t **string_refs; - long string_refs_count; - long string_refs_capacity; - - unsigned char *row; - size_t row_len; - - int row_count; - int current_row; - char file_label[100]; - char table_name[33]; - const readstat_variable_t *fweight_variable; - - readstat_writer_callbacks_t callbacks; - readstat_error_handler error_handler; - - void *module_ctx; - void *user_ctx; - - int initialized; -} readstat_writer_t; - -/* Writer API */ - - -// First call this... -readstat_writer_t *readstat_writer_init(void); - -// Then specify a function that will handle the output bytes... -readstat_error_t readstat_set_data_writer(readstat_writer_t *writer, readstat_data_writer data_writer); - -// Next define your value labels, if any. Create as many named sets as you'd like. -readstat_label_set_t *readstat_add_label_set(readstat_writer_t *writer, readstat_type_t type, const char *name); -void readstat_label_double_value(readstat_label_set_t *label_set, double value, const char *label); -void readstat_label_int32_value(readstat_label_set_t *label_set, int32_t value, const char *label); -void readstat_label_string_value(readstat_label_set_t *label_set, const char *value, const char *label); -void readstat_label_tagged_value(readstat_label_set_t *label_set, char tag, const char *label); - -// Now define your variables. Note that `storage_width' is used for: -// * READSTAT_TYPE_STRING variables in all formats -// * READSTAT_TYPE_DOUBLE variables, but only in the SAS XPORT format (valid values 3-8, defaults to 8) -readstat_variable_t *readstat_add_variable(readstat_writer_t *writer, const char *name, readstat_type_t type, - size_t storage_width); -void readstat_variable_set_label(readstat_variable_t *variable, const char *label); -void readstat_variable_set_format(readstat_variable_t *variable, const char *format); -void readstat_variable_set_label_set(readstat_variable_t *variable, readstat_label_set_t *label_set); -void readstat_variable_set_measure(readstat_variable_t *variable, readstat_measure_t measure); -void readstat_variable_set_alignment(readstat_variable_t *variable, readstat_alignment_t alignment); -void readstat_variable_set_display_width(readstat_variable_t *variable, int display_width); -readstat_error_t readstat_variable_add_missing_double_value(readstat_variable_t *variable, double value); -readstat_error_t readstat_variable_add_missing_double_range(readstat_variable_t *variable, double lo, double hi); -readstat_error_t readstat_variable_add_missing_string_value(readstat_variable_t *variable, const char *value); -readstat_error_t readstat_variable_add_missing_string_range(readstat_variable_t *variable, const char *lo, const char *hi); -readstat_variable_t *readstat_get_variable(readstat_writer_t *writer, int index); - -// "Notes" appear in the file metadata. In SPSS these are stored as -// lines in the Document Record; in Stata these are stored using -// the "notes" feature. -// -// Note that the line length in SPSS is 80 characters; ReadStat will -// produce a write error if a note is longer than this limit. -void readstat_add_note(readstat_writer_t *writer, const char *note); - -// String refs are used for creating a READSTAT_TYPE_STRING_REF column, -// which is only supported in Stata. String references can be shared -// across columns, and inserted with readstat_insert_string_ref(). -readstat_string_ref_t *readstat_add_string_ref(readstat_writer_t *writer, const char *string); -readstat_string_ref_t *readstat_get_string_ref(readstat_writer_t *writer, int index); - -// Optional metadata -readstat_error_t readstat_writer_set_file_label(readstat_writer_t *writer, const char *file_label); -readstat_error_t readstat_writer_set_file_timestamp(readstat_writer_t *writer, time_t timestamp); -readstat_error_t readstat_writer_set_fweight_variable(readstat_writer_t *writer, const readstat_variable_t *variable); - -readstat_error_t readstat_writer_set_file_format_version(readstat_writer_t *writer, - uint8_t file_format_version); -// e.g. 104-119 for DTA; 5 or 8 for SAS Transport. -// SAV files support 2 or 3, where 3 is equivalent to setting -// readstat_writer_set_compression(READSTAT_COMPRESS_BINARY) - -readstat_error_t readstat_writer_set_table_name(readstat_writer_t *writer, const char *table_name); -// Only used in XPORT files at the moment (defaults to DATASET) - -readstat_error_t readstat_writer_set_file_format_is_64bit(readstat_writer_t *writer, - int is_64bit); // applies only to SAS files; defaults to 1=true -readstat_error_t readstat_writer_set_compression(readstat_writer_t *writer, - readstat_compress_t compression); - // READSTAT_COMPRESS_BINARY is supported only with SAV files (i.e. ZSAV files) - // READSTAT_COMPRESS_ROWS is supported only with sas7bdat and SAV files - -// Optional error handler -readstat_error_t readstat_writer_set_error_handler(readstat_writer_t *writer, - readstat_error_handler error_handler); - -// Call one of these at any time before the first invocation of readstat_begin_row -readstat_error_t readstat_begin_writing_dta(readstat_writer_t *writer, void *user_ctx, long row_count); -readstat_error_t readstat_begin_writing_por(readstat_writer_t *writer, void *user_ctx, long row_count); -readstat_error_t readstat_begin_writing_sas7bcat(readstat_writer_t *writer, void *user_ctx); -readstat_error_t readstat_begin_writing_sas7bdat(readstat_writer_t *writer, void *user_ctx, long row_count); -readstat_error_t readstat_begin_writing_sav(readstat_writer_t *writer, void *user_ctx, long row_count); -readstat_error_t readstat_begin_writing_xport(readstat_writer_t *writer, void *user_ctx, long row_count); - -// Optional, file-specific validation routines, to be called AFTER readstat_begin_writing_XXX -readstat_error_t readstat_validate_metadata(readstat_writer_t *writer); -readstat_error_t readstat_validate_variable(readstat_writer_t *writer, const readstat_variable_t *variable); - -// Start a row of data (that is, a case or observation) -readstat_error_t readstat_begin_row(readstat_writer_t *writer); - -// Then call one of these for each variable -readstat_error_t readstat_insert_int8_value(readstat_writer_t *writer, const readstat_variable_t *variable, int8_t value); -readstat_error_t readstat_insert_int16_value(readstat_writer_t *writer, const readstat_variable_t *variable, int16_t value); -readstat_error_t readstat_insert_int32_value(readstat_writer_t *writer, const readstat_variable_t *variable, int32_t value); -readstat_error_t readstat_insert_float_value(readstat_writer_t *writer, const readstat_variable_t *variable, float value); -readstat_error_t readstat_insert_double_value(readstat_writer_t *writer, const readstat_variable_t *variable, double value); -readstat_error_t readstat_insert_string_value(readstat_writer_t *writer, const readstat_variable_t *variable, const char *value); -readstat_error_t readstat_insert_string_ref(readstat_writer_t *writer, const readstat_variable_t *variable, readstat_string_ref_t *ref); -readstat_error_t readstat_insert_missing_value(readstat_writer_t *writer, const readstat_variable_t *variable); -readstat_error_t readstat_insert_tagged_missing_value(readstat_writer_t *writer, const readstat_variable_t *variable, char tag); - -// Finally, close out the row -readstat_error_t readstat_end_row(readstat_writer_t *writer); - -// Once you've written all the rows, clean up after yourself -readstat_error_t readstat_end_writing(readstat_writer_t *writer); -void readstat_writer_free(readstat_writer_t *writer); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/Desktop/mainwindow.cpp b/Desktop/mainwindow.cpp index 6fb28f2f52..17484e65ef 100644 --- a/Desktop/mainwindow.cpp +++ b/Desktop/mainwindow.cpp @@ -1705,7 +1705,7 @@ bool MainWindow::startDataEditorHandler() else { QString caption = "Find Data File"; - QString filter = "Data File (*.csv *.txt *.tsv *.sav *.ods *.xls *.xlsx)"; + QString filter = "Data File (*.csv *.txt *.tsv *.sav *.ods *.xls *.xlsx *.rdata *.rds)"; dataFilePath = MessageForwarder::browseOpenFile(caption, "", filter); if (dataFilePath == "") diff --git a/Desktop/widgets/filemenu/computer.cpp b/Desktop/widgets/filemenu/computer.cpp index 58314facb6..5929afda89 100644 --- a/Desktop/widgets/filemenu/computer.cpp +++ b/Desktop/widgets/filemenu/computer.cpp @@ -39,13 +39,14 @@ FileEvent *Computer::browseOpen(const QString &path) else browsePath = path; - QString filter = tr("All Data Sets %1").arg("(*.jasp *.csv *.txt *.tsv *.sav *.zsav *.ods *.xls *.xlsx *.dta *.por *.sas7bdat *.sas7bcat *.xpt);;") + QString filter = tr("All Data Sets %1").arg("(*.jasp *.csv *.txt *.tsv *.sav *.zsav *.ods *.xls *.xlsx *.dta *.por *.sas7bdat *.sas7bcat *.xpt *.rdata *.rds);;") + tr("JASP Files %1").arg("(*.jasp);;") + tr("CSV Text Files %1").arg("(*.csv *.txt *.tsv);;") + tr("Spreadsheet Files %1").arg("(*.ods *.xls *.xlsx);;") + tr("SPSS Files %1").arg("(*.sav *.zsav *.por)") + ";;" + tr("Stata Files %1").arg("(*.dta);;") - + tr("SAS Files %1").arg("(*.sas7bdat *.sas7bcat *.xpt)"); + + tr("SAS Files %1").arg("(*.sas7bdat *.sas7bcat *.xpt);;") + + tr("R Data files %1").arg("(*.rdata *.rds)"); if (mode() == FileEvent::FileSyncData) filter = "Data Sets (*.csv *.txt *.tsv *.sav *.ods *.xls *.xlsx)"; diff --git a/Engine/CMakeLists.txt b/Engine/CMakeLists.txt index 5f5470e805..1787900c86 100644 --- a/Engine/CMakeLists.txt +++ b/Engine/CMakeLists.txt @@ -80,6 +80,8 @@ if(WINDOWS) ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${RTOOLS_LIBREADSTAT_DLL} ${CMAKE_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${RTOOLS_LIBRDATA_DLL} + ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${RTOOLS_ZLIB_DLL} ${CMAKE_BINARY_DIR} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${RTOOLS_LIBICONV_DLL} diff --git a/Tools/CMake/Install.cmake b/Tools/CMake/Install.cmake index 5316368941..beefa51a34 100644 --- a/Tools/CMake/Install.cmake +++ b/Tools/CMake/Install.cmake @@ -411,6 +411,7 @@ if(WIN32) ${RTOOLS_LIBWINPTHREAD_DLL} #${RTOOLS_LIBJSONCPP_DLL} ${RTOOLS_LIBREADSTAT_DLL} + ${RTOOLS_LIBRDATA_DLL} ${RTOOLS_ZLIB_DLL} ${RTOOLS_LIBICONV_DLL} ${_LIB_R_INTERFACE_DLL} diff --git a/Tools/CMake/Libraries.cmake b/Tools/CMake/Libraries.cmake index a95ef78efa..8d7ce50cdf 100644 --- a/Tools/CMake/Libraries.cmake +++ b/Tools/CMake/Libraries.cmake @@ -219,6 +219,26 @@ if(LINUX) ) endif() + # ---- librdata ---- + message(CHECK_START "Looking for `librdata`") + set(LIBRDATA_INCLUDE_DIRS /usr/include/ /usr/include/rdata /usr/local/include /usr/local/include/rdata /app/include) + set(LIBRDATA_LIBRARY_DIRS /usr/local/lib /usr/lib /app/lib64 /usr/lib/x86_64-linux-gnu /usr/lib/aarch64-linux-gnu) + + message(CHECK_START "Looking for librdata.so") + find_library(LIBRDATA_LIBRARIES librdata.so + HINTS ${LIBRDATA_LIBRARY_DIRS} REQUIRED) + + if(EXISTS ${LIBRDATA_LIBRARIES}) + message(CHECK_PASS "found") + message(STATUS " ${LIBRDATA_LIBRARIES}") + else() + message(CHECK_FAIL "not found") + message( + FATAL_ERROR + "librdata is required for building on Linux(e.g. librdata-dev on debian/ubuntu), please follow the build instruction before you continue." + ) + endif() + find_package(PkgConfig) #pkg_check_modules(_PKGCONFIG_LIB_JSONCPP REQUIRED jsoncpp>=1.9) @@ -266,7 +286,8 @@ if(WIN32) if(EXISTS ${RTOOLS_LIBREADSTAT_H}) message(CHECK_PASS "found") - message(STATUS " ${RTOOLS_LIBREADSTAT_H}") + message(STATUS "Now copy ${RTOOLS_LIBREADSTAT_H} to source directory.") + configure_file("${RTOOLS_LIBREADSTAT_H}" "${CMAKE_SOURCE_DIR}/Desktop/data/importers/readstat/readstat.h" COPYONLY) else() message(CHECK_FAIL "not found") message( @@ -292,6 +313,62 @@ if(WIN32) "ReadStat is required for building on Windows, please follow the build instruction before you continue." ) endif() + + # librdata + message(CHECK_START "Looking for librdata.dll.a") + find_file( + RTOOLS_LIBRDATA_DLL_A + NAMES librdata.dll.a + PATHS ${RTOOLS_PATH}/lib + NO_DEFAULT_PATH) + + if(EXISTS ${RTOOLS_LIBRDATA_DLL_A}) + message(CHECK_PASS "found") + message(STATUS " ${RTOOLS_LIBRDATA_DLL_A}") + else() + message(CHECK_FAIL "not found") + message( + FATAL_ERROR + "librdata is required for building on Windows, please follow the build instruction before you continue." + ) + endif() + + message(CHECK_START "Looking for rdata.h") + find_file( + RTOOLS_LIBRDATA_H + NAMES rdata.h + PATHS ${RTOOLS_PATH}/include + NO_DEFAULT_PATH) + + if(EXISTS ${RTOOLS_LIBRDATA_H}) + message(CHECK_PASS "found") + message(STATUS "Now copy ${RTOOLS_LIBRDATA_H} to source directory") + configure_file("${RTOOLS_LIBRDATA_H}" "${CMAKE_SOURCE_DIR}/Desktop/data/importers/rdata/rdata.h" COPYONLY) + else() + message(CHECK_FAIL "not found") + message( + FATAL_ERROR + "rdata is required for building on Windows, please follow the build instruction before you continue." + ) + endif() + + message(CHECK_START "Looking for librdata-0.dll") + find_file( + RTOOLS_LIBRDATA_DLL + NAMES librdata-0.dll + PATHS ${RTOOLS_PATH}/bin + NO_DEFAULT_PATH) + + if(EXISTS ${RTOOLS_LIBRDATA_DLL}) + message(CHECK_PASS "found") + message(STATUS " ${RTOOLS_LIBRDATA_DLL}") + else() + message(CHECK_FAIL "not found") + message( + FATAL_ERROR + "librdata is required for building on Windows, please follow the build instruction before you continue." + ) + endif() message(CHECK_START "Looking for zlib1.dll") find_file(