commit 283118f491df57508d1b850a8752fa9a9ea72100
parent dc77a3e11bf5be054b7dd1d6f98c0c16f84b033e
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 21 Jun 2022 10:45:44 +0200
Implement the loading functions
Diffstat:
| M | doc/rnsf.5.scd | | | 4 | ++-- |
| M | src/rnsf.c | | | 637 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- |
2 files changed, 638 insertions(+), 3 deletions(-)
diff --git a/doc/rnsf.5.scd b/doc/rnsf.5.scd
@@ -64,8 +64,8 @@ only of spaces and tabs.
<wlen-band-func> ::= <wavelength-min> <wavelength-max> <phase-func>
<bands-count> ::= INTEGER
-<wavelength-min> ::= REAL # In nanometers
-<wavelength-max> ::= REAL # In nanometers
+<wavelength-min> ::= REAL # Inclusive bound in nanometers
+<wavelength-max> ::= REAL # Inlcusive bound in nanometers
---
diff --git a/src/rnsf.c b/src/rnsf.c
@@ -1,7 +1,7 @@
/* Copyright (C) 2022 GSMA - Université de Reims Champgne-Ardenne, CNRS
* Copyright (C) 2022 IPGP, Université Paris Cité, CNRS
* Copyright (C) 2022 LAPLACE - Université de Toulouse, CNRS, INPT, UPS
- * Copyright (C) 2022 LATMOS/IPSL - UVSQ, Université Paris-Saclay,
+ * Copyright (C) 2022 LATMOS/IPSL - UVSQ, Université Paris-Saclay,
* Sorbonne Université, CNRS
* Copyright (C) 2022 LESIA - Observatoire de Paris, Université PSL,
* Sorbonne Université, Université Paris Cité
@@ -23,10 +23,18 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#define _POSIX_C_SOURCE 200112L /* strtok_r */
+
#include "rnsf.h"
#include "rnsf_c.h"
#include "rnsf_log.h"
+#include <string.h>
+
+#include <rsys/cstr.h>
+#include <rsys/math.h>
+#include <rsys/text_reader.h>
+
/*******************************************************************************
* Helper functions
******************************************************************************/
@@ -37,6 +45,582 @@ check_rnsf_create_args(const struct rnsf_create_args* args)
return args ? RES_OK : RES_BAD_ARG;
}
+static res_T
+parse_phase_fn_hg
+ (struct rnsf* rnsf,
+ struct txtrdr* txtrdr,
+ char** tk_ctx,
+ struct phase_fn_hg* phase)
+{
+ char* tk = NULL;
+ res_T res = RES_OK;
+ ASSERT(rnsf && txtrdr && tk_ctx && phase);
+
+ tk = strtok_r(NULL, " \t", tk_ctx);
+ if(!tk) {
+ log_err(rnsf,
+ "%s:%lu: missing the Henyey & Greenstein asymmetric parameter.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = cstr_to_double(tk, &phase->g);
+ if(res == RES_OK && (phase->g < -1 || phase->g > 1)) res = RES_BAD_ARG;
+ if(res != RES_OK) {
+ log_err(rnsf,
+ "%s:%lu: invalid Henyey & Greenstein asymmetric parameter `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ goto error;
+ }
+
+ tk = strtok_r(NULL, " \t", tk_ctx);
+ if(tk) {
+ log_warn(rnsf, "%s:%lu: unexpected text `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_discrete_item
+ (struct rnsf* rnsf,
+ struct txtrdr* txtrdr,
+ struct discrete_item* item)
+{
+ char* tk = NULL;
+ char* tk_ctx = NULL;
+ res_T res = RES_OK;
+ ASSERT(rnsf && txtrdr && item);
+
+ res = txtrdr_read_line(txtrdr);
+ if(res != RES_OK) {
+ log_err(rnsf, "%s: could not read the line `%lu' -- %s.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ res_to_cstr(res));
+ goto error;
+ }
+
+ if(!txtrdr_get_cline(txtrdr)) {
+ log_err(rnsf, "%s:%lu: missing an item of a discretized phase function.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx);
+ ASSERT(tk);
+
+ if(!strcmp(tk, "PI")) {
+ item->theta = PI;
+ } else {
+ res = cstr_to_double(tk, &item->theta);
+ if(res == RES_OK && (item->theta < 0 || item->theta > PI)) res = RES_BAD_ARG;
+ if(res != RES_OK) {
+ log_err(rnsf, "%s:%lu: invalid phase function angle `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ goto error;
+ }
+ }
+
+ tk = strtok_r(NULL, " \t", &tk_ctx);
+ if(!tk) {
+ log_err(rnsf,
+ "%s:%lu: the value of the discretized phase function is missing.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = cstr_to_double(tk, &item->value);
+ if(res == RES_OK && item->value < 0) res = RES_BAD_ARG;
+ if(res != RES_OK) {
+ log_err(rnsf, "%s:%lu: invalid value `%s' of the discretized phase function.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ goto error;
+ }
+
+ tk = strtok_r(NULL, " \t", &tk_ctx);
+ if(tk) {
+ log_warn(rnsf, "%s:%lu: unexpected text `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_phase_fn_discrete
+ (struct rnsf* rnsf,
+ struct txtrdr* txtrdr,
+ char** tk_ctx,
+ struct phase_fn_discrete* phase)
+{
+ char* tk = NULL;
+ unsigned long nangles = 0;
+ unsigned long i;
+ res_T res = RES_OK;
+ ASSERT(rnsf && txtrdr && tk_ctx && phase);
+
+ tk = strtok_r(NULL, " \t", tk_ctx);
+ if(!tk) {
+ log_err(rnsf,
+ "%s:%lu: missing the angle number of the discretized phase function.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = cstr_to_ulong(tk, &nangles);
+ if(res == RES_OK && nangles < 2) res = RES_BAD_ARG;
+ if(res != RES_OK) {
+ log_err(rnsf,
+ "%s:%lu: invalid angle number of the discretized phase function `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ goto error;
+ }
+
+ res = darray_discrete_item_resize(&phase->items, nangles);
+ if(res != RES_OK) {
+ log_err(rnsf,
+ "%s:%lu: could not allocate the list of values of the discretized "
+ "phase function -- %s.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ res_to_cstr(res));
+ goto error;
+ }
+
+ tk = strtok_r(NULL, " \t", tk_ctx);
+ if(tk) {
+ log_warn(rnsf, "%s:%lu: unexpected text `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ }
+
+ FOR_EACH(i, 0, nangles) {
+ struct discrete_item* item = NULL;
+ item = darray_discrete_item_data_get(&phase->items) + i;
+
+ res = parse_discrete_item(rnsf, txtrdr, item);
+ if(res != RES_OK) goto error;
+
+ if(i == 0 && item->theta != 0) {
+ log_err(rnsf,
+ "%s:%lu: invalid angle value `%g'. The first angle must be 0.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ item->theta);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(i == nangles - 1 && item->theta != PI) {
+ log_err(rnsf,
+ "%s:%lu: invalid angle value `%g'. The last angle must be PI.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ item->theta);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(i > 0 && item[0].theta <= item[-1].theta) {
+ log_err(rnsf,
+ "%s:%lu: the discretized phase function must be sorted in ascending "
+ "order of angle.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_phase_fn
+ (struct rnsf* rnsf,
+ struct txtrdr* txtrdr,
+ char** tk_ctx,
+ struct rnsf_phase_fn* phase)
+{
+ char* tk = NULL;
+ res_T res = RES_OK;
+ ASSERT(rnsf && txtrdr && tk_ctx && phase);
+
+ tk = strtok_r(NULL, " \t", tk_ctx);
+ if(!tk) {
+ log_err(rnsf, "%s:%lu: missing phase function type.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(!strcmp(tk, "hg")) {
+ phase->type = RNSF_PHASE_FN_HG;
+ res = parse_phase_fn_hg(rnsf, txtrdr, tk_ctx, &phase->param.hg);
+ if(res != RES_OK) goto error;
+
+ } else if(!strcmp(tk, "discrete")) {
+ phase->type = RNSF_PHASE_FN_DISCRETE;
+ phase_fn_discrete_init(rnsf->allocator, &phase->param.discrete);
+ res = parse_phase_fn_discrete(rnsf, txtrdr, tk_ctx, &phase->param.discrete);
+ if(res != RES_OK) goto error;
+
+ } else {
+ log_err(rnsf, "%s:%lu: invalid phase function type `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+
+static res_T
+parse_wlen_phase_fn
+ (struct rnsf* rnsf,
+ struct txtrdr* txtrdr,
+ struct rnsf_phase_fn* phase)
+{
+ char* tk = NULL;
+ char* tk_ctx = NULL;
+ double wlen = 0;
+ res_T res = RES_OK;
+ ASSERT(rnsf && txtrdr && phase);
+
+ res = txtrdr_read_line(txtrdr);
+ if(res != RES_OK) {
+ log_err(rnsf, "%s: could not read the line `%lu' -- %s.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ res_to_cstr(res));
+ goto error;
+ }
+
+ if(!txtrdr_get_cline(txtrdr)) {
+ const size_t nexpect = darray_phase_fn_size_get(&rnsf->phases);
+ const size_t nparsed = (size_t)
+ (phase - darray_phase_fn_cdata_get(&rnsf->phases));
+ log_err(rnsf,
+ "%s:%lu: missing phase function. "
+ "Expecting %lu function%swhile %lu %s parsed.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ (unsigned long)nexpect, nexpect == 1 ? " " : "s ",
+ (unsigned long)nparsed, nparsed > 1 ? "were" : "was");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx);
+ ASSERT(tk);
+
+ res = cstr_to_double(tk, &wlen);
+ if(res == RES_OK && wlen < 0) res = RES_BAD_ARG;
+ if(res != RES_OK) {
+ log_err(rnsf, "%s:%lu: invalid wavelength `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ goto error;
+ }
+ phase->wlen[0] = wlen;
+ phase->wlen[1] = wlen;
+
+ res = parse_phase_fn(rnsf, txtrdr, &tk_ctx, phase);
+ if(res != RES_OK) goto error;
+
+ tk = strtok_r(NULL, " \t", &tk_ctx);
+ if(tk) {
+ log_warn(rnsf, "%s:%lu: unexpected text `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_per_wlen_phase_fn
+ (struct rnsf* rnsf,
+ struct txtrdr* txtrdr,
+ char** tk_ctx)
+{
+ char* tk = NULL;
+ unsigned long count = 0;
+ unsigned long i;
+ res_T res = RES_OK;
+ ASSERT(rnsf && txtrdr && tk_ctx);
+
+ tk = strtok_r(NULL, " \t", tk_ctx);
+ if(!tk) {
+ log_err(rnsf, "%s:%lu: the number of wavelengths is missing.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = cstr_to_ulong(tk, &count);
+ if(res != RES_OK) {
+ log_err(rnsf, "%s:%lu: invalid number of wavelengths `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ tk = strtok_r(NULL, " \t", tk_ctx);
+ if(tk) {
+ log_warn(rnsf, "%s:%lu: unexpected text `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ }
+
+ res = darray_phase_fn_resize(&rnsf->phases, count);
+ if(res != RES_OK) {
+ log_err(rnsf,
+ "%s:%lu: could not allocate the list of phase functions -- %s.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ res_to_cstr(res));
+ goto error;
+ }
+
+ FOR_EACH(i, 0, count) {
+ struct rnsf_phase_fn* phase = NULL;
+
+ phase = darray_phase_fn_data_get(&rnsf->phases) + i;
+
+ res = parse_wlen_phase_fn(rnsf, txtrdr, phase);
+ if(res != RES_OK) goto error;
+ ASSERT(phase->wlen[0] == phase->wlen[1]);
+
+ if(i > 0 && phase[0].wlen[0] <= phase[-1].wlen[0]) {
+ log_err(rnsf,
+ "%s:%lu: the phase function must be sorted in ascending order of "
+ "wavelength.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+
+exit:
+ return res;
+error:
+ darray_phase_fn_clear(&rnsf->phases);
+ goto exit;
+}
+
+static res_T
+parse_band_brdf
+ (struct rnsf* rnsf,
+ struct txtrdr* txtrdr,
+ struct rnsf_phase_fn* phase)
+{
+ char* tk = NULL;
+ char* tk_ctx = NULL;
+ res_T res = RES_OK;
+ ASSERT(rnsf && txtrdr && phase);
+
+ res = txtrdr_read_line(txtrdr);
+ if(res != RES_OK) {
+ log_err(rnsf, "%s: could not read the line `%lu' -- %s.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ res_to_cstr(res));
+ goto error;
+ }
+
+ if(!txtrdr_get_cline(txtrdr)) {
+ const size_t nexpect = darray_phase_fn_size_get(&rnsf->phases);
+ const size_t nparsed = (size_t)
+ (phase - darray_phase_fn_cdata_get(&rnsf->phases));
+ log_err(rnsf,
+ "%s:%lu: missing phase function. "
+ "Expecting %lu functions%swhile %lu %s parsed.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ (unsigned long)nexpect, nexpect == 1 ? " " : "s ",
+ (unsigned long)nparsed, nparsed > 1 ? "were" : "was");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx);
+ ASSERT(tk);
+
+ res = cstr_to_double(tk, &phase->wlen[0]);
+ if(res == RES_OK && phase->wlen[0] < 0) res = RES_BAD_ARG;
+ if(res != RES_OK) {
+ log_err(rnsf, "%s:%lu: invalid band min boundary `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ goto error;
+ }
+
+ tk = strtok_r(NULL, " \t", &tk_ctx);
+ if(!tk) {
+ log_err(rnsf, "%s:%lu: missing band max boundary.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = cstr_to_double(tk, &phase->wlen[1]);
+ if(res == RES_OK && phase->wlen[1] < 0) res = RES_BAD_ARG;
+ if(res != RES_OK) {
+ log_err(rnsf, "%s:%lu: invalid band max boundary `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ goto error;
+ }
+
+ if(phase->wlen[0] > phase->wlen[1]) {
+ log_err(rnsf, "%s:%lu: band boundaries are degenerated -- [%g, %g].\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ phase->wlen[0], phase->wlen[1]);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = parse_phase_fn(rnsf, txtrdr, &tk_ctx, phase);
+ if(res != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+parse_per_band_phase_fn
+ (struct rnsf* rnsf,
+ struct txtrdr* txtrdr,
+ char** tk_ctx)
+{
+ char* tk = NULL;
+ unsigned long count = 0;
+ unsigned long i = 0;
+ res_T res = RES_OK;
+ ASSERT(rnsf && txtrdr && tk_ctx);
+
+ tk = strtok_r(NULL, " \t", tk_ctx);
+ if(!tk) {
+ log_err(rnsf, "%s:%lu: the number of bands is missing.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = cstr_to_ulong(tk, &count);
+ if(res != RES_OK) {
+ log_err(rnsf, "%s:%lu: invalid number of bands `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ tk = strtok_r(NULL, " \t", tk_ctx);
+ if(tk) {
+ log_warn(rnsf, "%s:%lu: unexpected text `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ }
+
+ res = darray_phase_fn_resize(&rnsf->phases, count);
+ if(res != RES_OK) {
+ log_err(rnsf,
+ "%s:%lu: could not allocate the list of phase functions -- %s.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ res_to_cstr(res));
+ goto error;
+ }
+
+ FOR_EACH(i, 0, count) {
+ struct rnsf_phase_fn* phase = NULL;
+
+ phase = darray_phase_fn_data_get(&rnsf->phases) + i;
+
+ res = parse_band_brdf(rnsf, txtrdr, phase);
+ if(res != RES_OK) goto error;
+
+ if(i > 0) {
+ if(phase[0].wlen[0] < phase[-1].wlen[1]
+ || phase[0].wlen[0] == phase[-1].wlen[1]) {
+ log_err(rnsf,
+ "%s:%lu: the phase function must be sorted in ascending order of "
+ "wavelength.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+ }
+
+exit:
+ return res;
+error:
+ darray_phase_fn_clear(&rnsf->phases);
+ goto exit;
+}
+
+static res_T
+load_stream
+ (struct rnsf* rnsf,
+ FILE* stream,
+ const char* stream_name)
+{
+ char* tk = NULL;
+ char* tk_ctx = NULL;
+ struct txtrdr* txtrdr = NULL;
+ res_T res = RES_OK;
+ ASSERT(rnsf && stream && stream_name);
+
+ darray_phase_fn_clear(&rnsf->phases); /* Clean-up */
+
+ res = txtrdr_stream(rnsf->allocator, stream, stream_name, '#', &txtrdr);
+ if(res != RES_OK) {
+ log_err(rnsf, "Could not create the text reader to parse `%s' -- %s.\n",
+ stream_name, res_to_cstr(res));
+ goto error;
+ }
+
+ res = txtrdr_read_line(txtrdr);
+ if(res != RES_OK) {
+ log_err(rnsf, "%s: could not read the line `%lu' -- %s.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr),
+ res_to_cstr(res));
+ goto error;
+ }
+
+ if(!txtrdr_get_cline(txtrdr)) goto exit; /* No line to parse */
+
+ tk = strtok_r(txtrdr_get_line(txtrdr), " \t", &tk_ctx);
+ ASSERT(tk);
+
+ if(!strcmp(tk, "wavelengths")) {
+ res = parse_per_wlen_phase_fn(rnsf, txtrdr, &tk_ctx);
+ if(res != RES_BAD_ARG) goto error;
+ } else if(!strcmp(tk, "bands")) {
+ res = parse_per_band_phase_fn(rnsf, txtrdr, &tk_ctx);
+ if(res != RES_BAD_ARG) goto error;
+ } else {
+ log_err(rnsf, "%s:%lu: invalid directive `%s'.\n",
+ txtrdr_get_name(txtrdr), (unsigned long)txtrdr_get_line_num(txtrdr), tk);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+exit:
+ if(txtrdr) txtrdr_ref_put(txtrdr);
+ return res;
+error:
+ goto exit;
+}
+
static void
release_rnsf(ref_T* ref)
{
@@ -114,3 +698,54 @@ rnsf_ref_put(struct rnsf* rnsf)
ref_put(&rnsf->ref, release_rnsf);
return RES_OK;
}
+
+res_T
+rnsf_load(struct rnsf* rnsf, const char* filename)
+{
+ FILE* fp = NULL;
+ res_T res = RES_OK;
+
+ if(!rnsf || !filename) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ fp = fopen(filename, "r");
+ if(!fp) {
+ log_err(rnsf, "%s: error opening file `%s' -- %s.\n",
+ FUNC_NAME, filename, strerror(errno));
+ res = RES_IO_ERR;
+ goto error;
+ }
+
+ res = load_stream(rnsf, fp, filename);
+ if(res != RES_OK) goto error;
+
+exit:
+ if(fp) fclose(fp);
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+rnsf_load_stream
+ (struct rnsf* rnsf,
+ FILE* stream,
+ const char* stream_name)
+{
+ res_T res = RES_OK;
+
+ if(!rnsf || !stream) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = load_stream(rnsf, stream, stream_name ? stream_name : "<stream>");
+ if(res != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ goto exit;
+}