From 44b5e4df79884c8954857f86532f918ec8a9c5df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Ne=C4=8Dada?= Date: Thu, 20 Jun 2019 06:27:08 +0300 Subject: [PATCH] Separate double parsing functions. Former-commit-id: 809f28b4b0c4bfba98a2981abf2c17c0ea0a0e65 --- apps/transop-ewald/transop_ewald.c | 163 +---------------------------- qpms/CMakeLists.txt | 2 +- qpms/parsing.c | 138 ++++++++++++++++++++++++ qpms/parsing.h | 57 ++++++++++ 4 files changed, 197 insertions(+), 163 deletions(-) create mode 100644 qpms/parsing.c create mode 100644 qpms/parsing.h diff --git a/apps/transop-ewald/transop_ewald.c b/apps/transop-ewald/transop_ewald.c index 5a5ac43..6ec6997 100644 --- a/apps/transop-ewald/transop_ewald.c +++ b/apps/transop-ewald/transop_ewald.c @@ -15,6 +15,7 @@ #include #include #include +#include // Command line order: // outfile b1.x b1.y b2.x b2.y lMax scuffomega refindex npart part0.x part0.y [part1.x part1.y [...]] @@ -25,168 +26,6 @@ // Output data format (line): // -/** Parse a given number of doubles from a string. - * - * The doubles can be separated by whitespaces, comma or semicolon. - * - * \return If the string included up to n doubles, number of parsed doubles. - * If more, n+1. - */ -size_t qpms_parse_ndoubles( - double *target, - size_t n, - const char *orig -) { - QPMS_ENSURE(target, "The target parameter must not be NULL"); - char * const dup = strdup(orig); - QPMS_ENSURE(dup, "Memory error in a strdup() call."); - - // Replace commas and semicolons with whitespaces - for (char *c = dup; *c; ++c) - if (*c == ',' || *c == ';') - *c = ' '; - - errno = 0; - size_t i = 0; - - const char *beg = dup; - while(*beg) { - char *endptr; - double parsed = strtod(beg, endptr); - if (endptr > beg) { - if (i >= n) { - errno = EOVERFLOW; - if (i == n) QPMS_WARN("Supplied string contains additional numbers" - " (expected only %zd numbers): %s\n", n, beg); - } - else - target[i] = parsed; - ++i; - beg = endptr; - } else { - while (*beg) { - if (!isspace(*beg)) { - QPMS_WARN("Invalid character (expected a double), leaving the rest of the string unprocessed: %s\n", beg); - errno = EILSEQ; - goto qpms_parse_ndoubles_cleanup; - } - ++beg; - } - } - } - -qpms_parse_ndoubles_cleanup: - free(dup); - return i; -} - -// TODO move to qpmslib later. -/** Parse doubles from a string. - * - * The doubles can be separated by whitespaces, comma or semicolon. - * The parsed numbers are saved into an array specified by *target - * that has been preallocated with malloc() to contain at least start_index - * members. If start_index is nonzero, the newly parsed numbers are - * saved to the positions starting from start_index. - * - * If *target is NULL, the function allocates the necessary space. - * - * \return Number of newly parsed doubles + start_index. - */ -size_t qpms_parse_doubles( - double **target, - size_t start_index, - const char *orig -) { - QPMS_ENSURE(target, "The target parameter must not be NULL"); - char * const dup = strdup(orig); - QPMS_ENSURE(dup, "Memory error in a strdup() call."); - - size_t capacity = start_index * 2; - if (capacity < 128) capacity = 128; - - // Replace commas and semicolons with whitespaces - for (char *c = dup; *c; ++c) - if (*c == ',' || *c == ';') - *c = ' '; - - size_t i = start_index; - errno = 0; - - const char *beg = dup; - while(*beg) { - char *endptr; - errno = 0; - double parsed = strtod(beg, endptr); - if (endptr > beg) { - (*target)[i] = parsed; - ++i; - if (i >= capacity) { - capacity *= 2; - QPMS_CRASHING_REALLOC(*target, capacity * sizeof(double)); - } - beg = endptr; - } else { - while (*beg) { - if (!isspace(*beg)) { - QPMS_WARN("Invalid character (expected a double), leaving the rest of the string unprocessed: %s\n", beg); - errno = EILSEQ; - goto qpms_parse_doubles_cleanup; - } - ++beg; - } - } - } - -qpms_parse_doubles_cleanup: - free(dup); - return i; -} - -/** Parse doubles from a file. - * - * The doubles can be separated by whitespaces, comma or semicolon. - * The parsed numbers are saved into an array specified by *target - * that has been preallocated with malloc() to contain at least start_index - * members. If start_index is nonzero, the newly parsed numbers are - * saved to the positions starting from start_index. - * - * If *target is NULL, the function allocates the necessary space. - * - * If filepath is NULL, "" or "-", read from stdin. - * - * \return Number of newly parsed doubles + start_index. - */ -size_t qpms_parse_doubles_fromfile( - double **target, - size_t start_index, //< Starting index for writing the parsed values. - const char *filepath //< File to read from, or NULL, "", "-" to read from stdin. -) { - QPMS_ENSURE(target, "The target parameter must not be NULL"); - - FILE *src; - - if (!filepath || !strcmp(filepath, "-") || filepath[0]=='\0') - src = stdin; - else - QPMS_ENSURE(src = fopen(filepath, "f"), - "Could not open file %s: %s", filepath, strerror(errno)); - - char buf[1024]; - int scanresult; - while (1 == (scanresult = fscanf(src, "%1023s", buf))) - start_index = qpms_parse_doubles(target, start_index, buf); - - if (errno) QPMS_WARN("Problem reading %s: %s", - (src==stdin) ? "stdin" : filepath, strerror(errno)); - -qpms_parse_doubles_files_cleanup: - if (src != stdin) - QPMS_ENSURE(!fclose(src), - "Could not close file %s: %s", filepath, strerror(errno)); - - return start_index; -} #define MAXKCOUNT 200 // 200 // serves as klist default buffer size //#define KMINCOEFF 0.783 //0.9783 // 0.783 // not used if KSTDIN defined //#define KMAXCOEFF 1.217 //1.0217 // 1.217 // not used if KSTDIN defined diff --git a/qpms/CMakeLists.txt b/qpms/CMakeLists.txt index 7a9ea03..d216360 100644 --- a/qpms/CMakeLists.txt +++ b/qpms/CMakeLists.txt @@ -12,7 +12,7 @@ include_directories(${DIRS}) add_library (qpms translations.c tmatrices.c vecprint.c vswf.c wigner.c lattices2d.c gaunt.c error.c legendre.c symmetries.c vecprint.c - bessel.c own_zgemm.c) + bessel.c own_zgemm.c parsing.c) use_c99() set(LIBS ${LIBS} ${GSL_LIBRARIES} ${GSLCBLAS_LIBRARIES}) diff --git a/qpms/parsing.c b/qpms/parsing.c new file mode 100644 index 0000000..ef353ee --- /dev/null +++ b/qpms/parsing.c @@ -0,0 +1,138 @@ +#include "parsing.h" +#include "qpms_error.h" +#include +#include +#include +#include +#include + +size_t qpms_parse_ndoubles( + double *target, + size_t n, + const char *orig +) { + QPMS_ENSURE(target, "The target parameter must not be NULL"); + char * const dup = strdup(orig); + QPMS_ENSURE(dup, "Memory error in a strdup() call."); + + // Replace commas and semicolons with whitespaces + for (char *c = dup; *c; ++c) + if (*c == ',' || *c == ';') + *c = ' '; + + errno = 0; + size_t i = 0; + + const char *beg = dup; + while(*beg) { + char *endptr; + double parsed = strtod(beg, &endptr); + if (endptr > beg) { + if (i >= n) { + errno = EOVERFLOW; + if (i == n) QPMS_WARN("Supplied string contains additional numbers" + " (expected only %zd numbers): %s\n", n, beg); + } + else + target[i] = parsed; + ++i; + beg = endptr; + } else { + while (*beg) { + if (!isspace(*beg)) { + QPMS_WARN("Invalid character (expected a double), leaving the rest of the string unprocessed: %s\n", beg); + errno = EILSEQ; + goto qpms_parse_ndoubles_cleanup; + } + ++beg; + } + } + } + +qpms_parse_ndoubles_cleanup: + free(dup); + return i; +} + + +size_t qpms_parse_doubles( + double **target, + size_t start_index, + const char *orig +) { + QPMS_ENSURE(target, "The target parameter must not be NULL"); + char * const dup = strdup(orig); + QPMS_ENSURE(dup, "Memory error in a strdup() call."); + + size_t capacity = start_index * 2; + if (capacity < 128) capacity = 128; + + // Replace commas and semicolons with whitespaces + for (char *c = dup; *c; ++c) + if (*c == ',' || *c == ';') + *c = ' '; + + size_t i = start_index; + errno = 0; + + const char *beg = dup; + while(*beg) { + char *endptr; + errno = 0; + double parsed = strtod(beg, &endptr); + if (endptr > beg) { + (*target)[i] = parsed; + ++i; + if (i >= capacity) { + capacity *= 2; + QPMS_CRASHING_REALLOC(*target, capacity * sizeof(double)); + } + beg = endptr; + } else { + while (*beg) { + if (!isspace(*beg)) { + QPMS_WARN("Invalid character (expected a double), leaving the rest of the string unprocessed: %s\n", beg); + errno = EILSEQ; + goto qpms_parse_doubles_cleanup; + } + ++beg; + } + } + } + +qpms_parse_doubles_cleanup: + free(dup); + return i; +} + + +size_t qpms_parse_doubles_fromfile( + double **target, + size_t start_index, //< Starting index for writing the parsed values. + const char *filepath //< File to read from, or NULL, "", "-" to read from stdin. +) { + QPMS_ENSURE(target, "The target parameter must not be NULL"); + + FILE *src; + + if (!filepath || !strcmp(filepath, "-") || filepath[0]=='\0') + src = stdin; + else + QPMS_ENSURE(src = fopen(filepath, "f"), + "Could not open file %s: %s", filepath, strerror(errno)); + + char buf[1024]; + int scanresult; + while (1 == (scanresult = fscanf(src, "%1023s", buf))) + start_index = qpms_parse_doubles(target, start_index, buf); + + if (errno) QPMS_WARN("Problem reading %s: %s", + (src==stdin) ? "stdin" : filepath, strerror(errno)); + +qpms_parse_doubles_files_cleanup: + if (src != stdin) + QPMS_ENSURE(!fclose(src), + "Could not close file %s: %s", filepath, strerror(errno)); + + return start_index; +} diff --git a/qpms/parsing.h b/qpms/parsing.h new file mode 100644 index 0000000..7750686 --- /dev/null +++ b/qpms/parsing.h @@ -0,0 +1,57 @@ +#ifndef QPMS_PARSING_H +#define QPMS_PARSING_H + +#include + +/** Parse a given number of doubles from a string. + * + * The doubles can be separated by whitespaces, comma or semicolon. + * + * \return If the string included up to n doubles, number of parsed doubles. + * If more, n+1. + */ +size_t qpms_parse_ndoubles( + double *target, + size_t n, + const char *orig +); + +/** Parse doubles from a string. + * + * The doubles can be separated by whitespaces, comma or semicolon. + * The parsed numbers are saved into an array specified by *target + * that has been preallocated with malloc() to contain at least start_index + * members. If start_index is nonzero, the newly parsed numbers are + * saved to the positions starting from start_index. + * + * If *target is NULL, the function allocates the necessary space. + * + * \return Number of newly parsed doubles + start_index. + */ +size_t qpms_parse_doubles( + double **target, + size_t start_index, + const char *orig +); + +/** Parse doubles from a file. + * + * The doubles can be separated by whitespaces, comma or semicolon. + * The parsed numbers are saved into an array specified by *target + * that has been preallocated with malloc() to contain at least start_index + * members. If start_index is nonzero, the newly parsed numbers are + * saved to the positions starting from start_index. + * + * If *target is NULL, the function allocates the necessary space. + * + * If filepath is NULL, "" or "-", read from stdin. + * + * \return Number of newly parsed doubles + start_index. + */ +size_t qpms_parse_doubles_fromfile( + double **target, + size_t start_index, //< Starting index for writing the parsed values. + const char *filepath //< File to read from, or NULL, "", "-" to read from stdin. +); + +#endif // QPMS_PARSING_H