star-hitran

Load line-by-line data from the HITRAN database
git clone git://git.meso-star.fr/star-hitran.git
Log | Files | Refs | README | LICENSE

commit 8e08a8c8a3be4e932afc198403e7bd2008f0fd60
parent 8a076a4b558c3b568f554fece0849b9085851f51
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 11 Feb 2026 11:50:37 +0100

Update the profile of shtr_line_list_write

Allow the caller to directly define the name of the file in which to
serialize the list of lines in order to avoid having to manage it
explicitly. The file pointer can still be provided directly.

This change unifies the way in which the load, read, and write functions
are called. The way in which the file pointer is managed internally by
these functions is also unified thanks to a new internal "stream" API.

Diffstat:
Msrc/shtr.h | 18++++++++++++++++--
Msrc/shtr_line_list.c | 164++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/shtr_main.c | 14+++-----------
Msrc/test_shtr_lines.c | 6++++--
4 files changed, 128 insertions(+), 74 deletions(-)

diff --git a/src/shtr.h b/src/shtr.h @@ -218,7 +218,7 @@ static const struct shtr_line_list_load_args SHTR_LINE_LIST_LOAD_ARGS_NULL = * they were written by the shtr_line_list_write function */ struct shtr_line_list_read_args { /* Name of the file to read or of the provided stream. - * NULL <=> uses a default name for the stream to be loaded, which must + * NULL <=> uses a default name for the stream to be read, which must * therefore be defined. */ const char* filename; /* Name of the file to read */ FILE* file; /* Stream from where data are read. NULL <=> read from file */ @@ -235,6 +235,20 @@ struct shtr_line_list_read_args { static const struct shtr_line_list_read_args SHTR_LINE_LIST_READ_ARGS_NULL = SHTR_LINE_LIST_READ_ARGS_NULL__; +struct shtr_line_list_write_args { + /* Name of the file in which the list of lines is serialized. + * NULL <=> uses a default name for the stream to be written, which must + * therefore be defined. */ + const char* filename; /* Name of the file to read */ + + /* Stream where data is written. + * NULL <=> write to the file defined by "filename" */ + FILE* file; +}; +#define SHTR_LINE_LIST_WRITE_ARGS_NULL__ {NULL, NULL} +static const struct shtr_line_list_write_args SHTR_LINE_LIST_WRITE_ARGS_NULL = + SHTR_LINE_LIST_WRITE_ARGS_NULL__; + BEGIN_DECLS /******************************************************************************* @@ -351,7 +365,7 @@ shtr_line_list_at SHTR_API res_T shtr_line_list_write (const struct shtr_line_list* list, - FILE* stream); + const struct shtr_line_list_write_args* args); SHTR_API res_T shtr_line_list_get_info diff --git a/src/shtr_line_list.c b/src/shtr_line_list.c @@ -30,10 +30,17 @@ /* Maximum number of lines that can be stored in a memory block */ #define NLINES_PER_BLOCK (BLOCK_SIZE/sizeof(struct line)) +struct stream { + const char* name; + FILE* fp; + int intern_fp; /* Define if the stream was internally opened */ +}; +static const struct stream STREAM_NULL = {NULL, NULL, 0}; + /******************************************************************************* * Helper functions ******************************************************************************/ -static res_T +static INLINE res_T check_shtr_line_list_load_args(const struct shtr_line_list_load_args* args) { if(!args) return RES_BAD_ARG; @@ -44,7 +51,7 @@ check_shtr_line_list_load_args(const struct shtr_line_list_load_args* args) return RES_OK; } -static res_T +static INLINE res_T check_shtr_line_list_read_args(const struct shtr_line_list_read_args* args) { if(!args) return RES_BAD_ARG; @@ -58,6 +65,63 @@ check_shtr_line_list_read_args(const struct shtr_line_list_read_args* args) return RES_OK; } +static INLINE res_T +check_shtr_line_list_write_args(const struct shtr_line_list_write_args* args) +{ + if(!args) return RES_BAD_ARG; + + /* Destination is missing */ + if(!args->file && !args->filename) return RES_BAD_ARG; + + return RES_OK; +} + +static INLINE void +stream_release(struct stream* stream) +{ + ASSERT(stream); + if(stream->intern_fp && stream->fp) CHK(fclose(stream->fp) == 0); +} + +static res_T +stream_init + (struct shtr* shtr, + const char* caller, + const char* name, /* NULL <=> default stream name */ + FILE* fp, /* NULL <=> open file "name" */ + const char* mode, /* mode in fopen */ + struct stream* stream) +{ + res_T res = RES_OK; + + ASSERT(shtr && caller && stream); + ASSERT(fp || name); + + *stream = STREAM_NULL; + + if(fp) { + stream->intern_fp = 0; + stream->name = name ? name : "stream"; + stream->fp = fp; + + } else { + stream->intern_fp = 1; + stream->name = name; + if(!(stream->fp = fopen(name, mode))) { + ERROR(shtr, "%s:%s: error opening file -- %s\n", + caller, name, strerror(errno)); + res = RES_IO_ERR; + goto error; + } + } + +exit: + return res; +error: + if(stream->intern_fp && stream->fp) CHK(fclose(stream->fp) == 0); + goto exit; +} + static res_T size_to_off(const size_t sz, off_t* off) { @@ -361,31 +425,27 @@ error: static res_T load_stream (struct shtr* shtr, - FILE* stream, const struct shtr_line_list_load_args* args, struct shtr_line_list** out_lines) { + struct stream stream = STREAM_NULL; struct shtr_line_list* list = NULL; struct txtrdr* txtrdr = NULL; - const char* name = NULL; res_T res = RES_OK; - ASSERT(shtr && stream && args && out_lines); - - if(args->file) { /* Load from stream */ - name = args->filename ? args->filename : "<stream>"; - } else { - name = args->filename; - } + ASSERT(shtr && args && out_lines); res = create_line_list(shtr, &list); if(res != RES_OK) goto error; - res = txtrdr_stream(list->shtr->allocator, stream, name, + res = stream_init(shtr, FUNC_NAME, args->filename, args->file, "r", &stream); + if(res != RES_OK) goto error; + + res = txtrdr_stream(list->shtr->allocator, stream.fp, stream.name, 0/*No comment char*/, &txtrdr); if(res != RES_OK) { ERROR(shtr, "%s: error creating the text reader -- %s.\n", - name, res_to_cstr(res)); + stream.name, res_to_cstr(res)); goto error; } @@ -395,7 +455,8 @@ load_stream res = txtrdr_read_line(txtrdr); if(res != RES_OK) { ERROR(shtr, "%s: error reading the line `%lu' -- %s.\n", - name, (unsigned long)txtrdr_get_line_num(txtrdr), res_to_cstr(res)); + stream.name, (unsigned long)txtrdr_get_line_num(txtrdr), + res_to_cstr(res)); goto error; } @@ -410,6 +471,7 @@ load_stream exit: if(txtrdr) txtrdr_ref_put(txtrdr); + stream_release(&stream); *out_lines = list; return res; error: @@ -450,30 +512,16 @@ shtr_line_list_load const struct shtr_line_list_load_args* args, struct shtr_line_list** list) { - FILE* file = NULL; res_T res = RES_OK; if(!shtr || !list) { res = RES_BAD_ARG; goto error; } res = check_shtr_line_list_load_args(args); if(res != RES_OK) goto error; - if(args->file) { /* Load from stream */ - file = args->file; - - } else { /* Load from file */ - file = fopen(args->filename, "r"); - if(!file) { - ERROR(shtr, "%s: error opening file `%s'.\n", FUNC_NAME, args->filename); - res = RES_IO_ERR; - goto error; - } - } - - res = load_stream(shtr, file, args, list); + res = load_stream(shtr, args, list); if(res != RES_OK) goto error; exit: - if(file && file != args->file) fclose(file); return res; error: goto exit; @@ -492,10 +540,8 @@ shtr_line_list_read struct shtr_line_list* list = NULL; /* The output list */ char** blocks = NULL; /* Allocated list of memory blocks */ - const char* name = NULL; /* file name */ - FILE* stream = NULL; /* The stream to load */ - /* Miscellaneous */ + struct stream stream = STREAM_NULL; size_t i = 0; size_t sz = 0; size_t sz_to_load = 0; @@ -511,33 +557,22 @@ shtr_line_list_read res = create_line_list(shtr, &list); if(res != RES_OK) goto error; - /* Setup the intput stream */ - if(args->file) { - name = args->filename ? args->filename : "<stream>"; - stream = args->file; - } else { - name = args->filename; - stream = fopen(args->filename, "r"); - if(!stream) { - ERROR(shtr, "%s: error opening file %s -- %s\n", - FUNC_NAME, args->filename, strerror(errno)); - res = RES_IO_ERR; - goto error; - } - } + res = stream_init + (list->shtr, FUNC_NAME, args->filename, args->file, "r", &stream); + if(res != RES_OK) goto error; #define READ(Var, Nb) { \ - if(fread((Var), sizeof(*(Var)), (Nb), stream) != (Nb)) { \ - if(feof(stream)) { \ + if(fread((Var), sizeof(*(Var)), (Nb), stream.fp) != (Nb)) { \ + if(feof(stream.fp)) { \ res = RES_BAD_ARG; \ - } else if(ferror(stream)) { \ + } else if(ferror(stream.fp)) { \ res = RES_IO_ERR; \ } else { \ res = RES_UNKNOWN_ERR; \ } \ ERROR(shtr, \ "%s:%s: error reading line list -- %s.\n", \ - FUNC_NAME, name, res_to_cstr(res)); \ + FUNC_NAME, stream.name, res_to_cstr(res)); \ goto error; \ } \ } (void)0 @@ -547,7 +582,7 @@ shtr_line_list_read ERROR(shtr, "%s:%s: unexpected line list version %d. " "Expecting a line list in version %d.\n", - FUNC_NAME, name, version, SHTR_LINE_LIST_VERSION); + FUNC_NAME, stream.name, version, SHTR_LINE_LIST_VERSION); res = RES_BAD_ARG; goto error; } @@ -575,14 +610,14 @@ shtr_line_list_read res = size_to_off(sz, &off); if(res != RES_OK) { ERROR(shtr, "%s:%s: file is too large regarding the seek offset %zu\n", - FUNC_NAME, name, sz); + FUNC_NAME, stream.name, sz); goto error; } /* Move to the first line to load */ - err = fseeko(stream, off, SEEK_CUR); + err = fseeko(stream.fp, off, SEEK_CUR); if(err) { - ERROR(shtr, "%s:%s: %s\n", FUNC_NAME, name, strerror(errno)); + ERROR(shtr, "%s:%s: %s\n", FUNC_NAME, stream.name, strerror(errno)); res = RES_IO_ERR; goto error; } @@ -595,7 +630,8 @@ shtr_line_list_read FOR_EACH(i, 0, nblocks) { blocks[i] = MEM_CALLOC(list->shtr->allocator, 1, BLOCK_SIZE); if(!blocks[i]) { - ERROR(shtr, "%s:%s: error allocating memory block\n", name, FUNC_NAME); + ERROR(shtr, "%s:%s: error allocating memory block\n", + stream.name, FUNC_NAME); res = RES_MEM_ERR; goto error; } @@ -609,6 +645,7 @@ shtr_line_list_read #undef READ exit: + stream_release(&stream); if(out_list) *out_list = list; return res; error: @@ -659,19 +696,27 @@ shtr_line_list_at res_T shtr_line_list_write (const struct shtr_line_list* list, - FILE* stream) + const struct shtr_line_list_write_args* args) { + struct stream stream = STREAM_NULL; char* const* blocks = NULL; size_t i=0, n=0; res_T res = RES_OK; - if(!list || !stream) { res = RES_BAD_ARG; goto error; } + if(!list) { res = RES_BAD_ARG; goto error; } + res = check_shtr_line_list_write_args(args); + if(res != RES_OK) goto error; + + res = stream_init + (list->shtr, FUNC_NAME, args->filename, args->file, "w", &stream); + if(res != RES_OK) goto error; #define WRITE(Var, Nb) { \ - if(fwrite((Var), sizeof(*(Var)), (Nb), stream) != (Nb)) { \ + if(fwrite((Var), sizeof(*(Var)), (Nb), stream.fp) != (Nb)) { \ res = RES_IO_ERR; \ ERROR(list->shtr, \ - "%s: error writing line list -- %s\n", FUNC_NAME, res_to_cstr(res)); \ + "%s:%s: error writing line list -- %s\n", \ + FUNC_NAME, stream.name, res_to_cstr(res)); \ goto error; \ } \ } (void)0 @@ -693,6 +738,7 @@ shtr_line_list_write #undef WRITE exit: + stream_release(&stream); return res; error: goto exit; diff --git a/src/shtr_main.c b/src/shtr_main.c @@ -251,23 +251,15 @@ print_memsz(const struct cmd* cmd) static res_T write_lines(const struct cmd* cmd, const struct shtr_line_list* list) { - FILE* fp = NULL; + struct shtr_line_list_write_args args = SHTR_LINE_LIST_WRITE_ARGS_NULL; res_T res = RES_OK; ASSERT(cmd && list && cmd->args.output); - fp = fopen(cmd->args.output, "w"); - if(!fp) { - fprintf(stderr, "%s: error opening file -- %s\n", - cmd->args.output, strerror(errno)); - res = RES_IO_ERR; - goto error; - } - - res = shtr_line_list_write(list, fp); + args.filename = cmd->args.output; + res = shtr_line_list_write(list, &args); if(res != RES_OK) goto error; exit: - if(fp) CHK(fclose(fp) == 0); return res; error: goto exit; diff --git a/src/test_shtr_lines.c b/src/test_shtr_lines.c @@ -340,6 +340,7 @@ test_serialization(struct shtr* shtr) struct shtr_line_list_load_args load_args = SHTR_LINE_LIST_LOAD_ARGS_NULL__; struct shtr_line_list_read_args read_args = SHTR_LINE_LIST_READ_ARGS_NULL__; + struct shtr_line_list_write_args write_args = SHTR_LINE_LIST_WRITE_ARGS_NULL__; struct shtr_line_list* list1 = NULL; struct shtr_line_list* list2 = NULL; @@ -354,9 +355,10 @@ test_serialization(struct shtr* shtr) CHK(fclose(fp) == 0); CHK(fp = tmpfile()); - CHK(shtr_line_list_write(NULL, fp) == RES_BAD_ARG); + write_args.file = fp; + CHK(shtr_line_list_write(NULL, &write_args) == RES_BAD_ARG); CHK(shtr_line_list_write(list1, NULL) == RES_BAD_ARG); - CHK(shtr_line_list_write(list1, fp) == RES_OK); + CHK(shtr_line_list_write(list1, &write_args) == RES_OK); rewind(fp); read_args.file = fp;