From 975f5980f38f77a57a9409756b4d080d6d32fe1f Mon Sep 17 00:00:00 2001 From: Niels Bassler Date: Tue, 31 Mar 2026 13:42:59 +0200 Subject: [PATCH 1/8] fix #70 --- libdedx/dedx_file_access.c | 169 +++++++++++++++---------------------- libdedx/dedx_file_access.h | 2 + 2 files changed, 69 insertions(+), 102 deletions(-) diff --git a/libdedx/dedx_file_access.c b/libdedx/dedx_file_access.c index 3285030..880284f 100644 --- a/libdedx/dedx_file_access.c +++ b/libdedx/dedx_file_access.c @@ -9,7 +9,7 @@ libdedx 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. + the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with libdedx. If not, see . @@ -17,28 +17,25 @@ #include "dedx_file_access.h" -// char folder[] = "data/"; -// DEDX_DATA_PATH is set by dedx_config.h which is generated by cmake. -char folder[512] = DEDX_DATA_PATH; // default is installation path -int attemps = 0; - -void _dedx_set_folder(void) { - /* switch to local data path, if directory exists */ - struct stat st; - char buff[256]; - // This will break new installs, since .dat files are - // searched in /usr/local/share..... - // if(sizeof(DEDX_DATA_PATH) > 0) - // return; - // instead: - // test first if data/ folder exists and is populated with proper files. - strcpy(buff, DEDX_DATA_PATH_LOCAL); - strcat(buff, "icru_pstarEng.dat"); // icru_pstarEng.txt is magic. - // better solution would be to check for all files? - if (stat(buff, &st) == 0) // TODO: this might be broken. - strcpy(folder, DEDX_DATA_PATH_LOCAL); // cmake build, not yet installed - // if(stat("data/",&st) == 0) // non-cmake builds - // strcpy(folder,"data/"); +/* Resolve the data directory once per process. + * Prefers DEDX_DATA_PATH_LOCAL (build tree) if it contains the sentinel file, + * otherwise falls back to DEDX_DATA_PATH (install prefix). + * Result is cached in a static buffer; never changes after the first call. */ +static const char *_dedx_get_data_path(void) { + static char resolved[DEDX_PATH_SIZE]; + static int done = 0; + if (!done) { + struct stat st; + char probe[DEDX_PATH_SIZE]; + strcpy(probe, DEDX_DATA_PATH_LOCAL); + strcat(probe, "icru_pstarEng.dat"); + if (stat(probe, &st) == 0) + strcpy(resolved, DEDX_DATA_PATH_LOCAL); + else + strcpy(resolved, DEDX_DATA_PATH); + done = 1; + } + return resolved; } void _dedx_convert_to_binary(char *path, char *output, int *err) { @@ -87,34 +84,32 @@ void _dedx_convert_to_binary(char *path, char *output, int *err) { void _dedx_read_binary_data(stopping_data *data, int prog, int ion, int target, int *err) { *err = 0; - // char folder[] = "data/"; - // char folder[] = DEDX_DATA_PATH; // it is global - _dedx_set_folder(); - char path[200]; + const char *folder = _dedx_get_data_path(); + char path[DEDX_PATH_SIZE]; path[0] = '\0'; strcat(path, folder); strcat(path, _dedx_get_program_file(prog)); strcat(path, ".bin"); FILE *fp = fopen(path, "rb"); - stopping_data dat; if (fp == NULL) { - char input_path[200]; + char input_path[DEDX_PATH_SIZE]; input_path[0] = '\0'; strcat(input_path, folder); strcat(input_path, _dedx_get_program_file(prog)); strcat(input_path, ".dat"); _dedx_convert_to_binary(input_path, path, err); - if (*err == 0 && attemps == 0) { - attemps++; - _dedx_read_binary_data(data, prog, ion, target, err); - } else { + if (*err != 0) { *err = 4; + return; + } + fp = fopen(path, "rb"); + if (fp == NULL) { + *err = 4; + return; } - attemps = 0; - return; } - // Set error status to, combination does not exist + stopping_data dat; *err = 202; while (fread(&dat, sizeof(stopping_data), 1, fp) == 1) { if (dat.target == target && dat.ion == ion) { @@ -123,12 +118,12 @@ void _dedx_read_binary_data(stopping_data *data, int prog, int ion, int target, } } fclose(fp); - return; } + void _dedx_convert_energy_binary(char *path, char *output, int *err) { *err = 0; FILE *fp = fopen(path, "r"); - // TODO: Next line wont work after insallation, unless user is root. + // TODO: Next line wont work after installation, unless user is root. FILE *out = fopen(output, "wb+"); char line[100]; int datalines; @@ -156,38 +151,39 @@ void _dedx_convert_energy_binary(char *path, char *output, int *err) { fclose(fp); fclose(out); } -void _dedx_read_energy_data(float *energy, int prog, int *err) { +void _dedx_read_energy_data(float *energy, int prog, int *err) { *err = 0; - // char folder[] = "data/"; - // char folder[] = DEDX_DATA_PATH; - char path[200]; - _dedx_set_folder(); + const char *folder = _dedx_get_data_path(); + char path[DEDX_PATH_SIZE]; path[0] = '\0'; strcat(path, folder); strcat(path, _dedx_get_energy_file(prog)); strcat(path, ".bin"); + FILE *fp = fopen(path, "rb"); if (fp == NULL) { - char input_path[100]; + char input_path[DEDX_PATH_SIZE]; input_path[0] = '\0'; strcat(input_path, folder); strcat(input_path, _dedx_get_energy_file(prog)); strcat(input_path, ".dat"); _dedx_convert_energy_binary(input_path, path, err); - if (*err == 0 && attemps == 0) { - attemps++; - _dedx_read_energy_data(energy, prog, err); - } else { + if (*err != 0) { *err = 5; + return; + } + fp = fopen(path, "rb"); + if (fp == NULL) { + *err = 5; + return; } - attemps = 0; - return; } if (fread(energy, sizeof(float) * _DEDX_MAXELEMENTS, 1, fp) == 0) { } fclose(fp); } + float _dedx_read_effective_charge(int id, int *err) { *err = 0; float charge = -1; @@ -195,12 +191,12 @@ float _dedx_read_effective_charge(int id, int *err) { charge = (float) id; return charge; } + const char *folder = _dedx_get_data_path(); char line[100]; char **temp = NULL; unsigned int items = 0; char file[] = "effective_charge.dat"; - char path[512]; - _dedx_set_folder(); + char path[DEDX_PATH_SIZE]; strcpy(path, folder); strcat(path, file); @@ -230,10 +226,9 @@ size_t _dedx_target_is_gas(int target, int *err) { *err = 0; size_t is_gas = 0; char str[100]; - - _dedx_set_folder(); + const char *folder = _dedx_get_data_path(); char file[] = "gas_states.dat"; - char path[512]; + char path[DEDX_PATH_SIZE]; strcpy(path, folder); strcat(path, file); FILE *fp = fopen(path, "r"); @@ -251,20 +246,21 @@ size_t _dedx_target_is_gas(int target, int *err) { fclose(fp); return is_gas; } + float _dedx_read_density(int id, int *err) { - *err = 0; - float density; - density = 1.0; + float density = 1.0; char str[100]; - char path[200]; - _dedx_set_folder(); - path[0] = '\0'; + char path[DEDX_PATH_SIZE]; char file[] = "compos.txt"; - strcpy(path, folder); - strcat(path, file); - FILE *fp = fopen(path, "r"); unsigned int items = 0; char **temp; + FILE *fp; + + *err = 0; + const char *folder = _dedx_get_data_path(); + strcpy(path, folder); + strcat(path, file); + fp = fopen(path, "r"); if (fp == NULL) { *err = 1; @@ -291,44 +287,12 @@ float _dedx_read_density(int id, int *err) { } return density; } -/* void _dedx_get_short_name(int id,char * name, int *err) */ -/* { */ -/* char file[] = "short_names"; */ -/* char path[80]; */ -/* char str[100]; */ -/* char ** temp; */ -/* int items = 0; */ - -/* strcpy(path,folder); */ -/* strcat(path,file); */ - -/* FILE *fp = fopen(path,"r"); */ -/* if(fp == NULL) */ -/* { */ -/* *err = 9; */ -/* return; */ -/* } */ -/* while(!feof(fp)) */ -/* { */ -/* fgets(str,100,fp); */ - -/* temp = _dedx_split(str,':',&items,100); */ -/* if(atoi(temp[0]) == id) */ -/* { */ -/* _dedx_remove_character_at_end(temp[1],'\n'); */ -/* memcpy(name,temp[1],10); */ -/* break; */ -/* } */ -/* } */ -/* free(temp); */ -/* fclose(fp); */ -/* } */ float _dedx_get_i_value(int target, int state, int *err) { float pot = 0.0; char file[] = "compos.txt"; - char path[512]; - _dedx_set_folder(); + char path[DEDX_PATH_SIZE]; + const char *folder = _dedx_get_data_path(); char str[100]; char **temp; unsigned int items = 0; @@ -365,10 +329,11 @@ float _dedx_get_i_value(int target, int state, int *err) { } return pot; } + void _dedx_get_composition(int target, float composition[][2], unsigned int *length, int *err) { *err = 0; char file[] = "composition"; - char path[512]; + char path[DEDX_PATH_SIZE]; char str[100]; *length = 0; float f_temp; @@ -376,7 +341,7 @@ void _dedx_get_composition(int target, float composition[][2], unsigned int *len unsigned int items; char **temp; - _dedx_set_folder(); + const char *folder = _dedx_get_data_path(); strcpy(path, folder); strcat(path, file); @@ -411,8 +376,8 @@ void _dedx_get_composition(int target, float composition[][2], unsigned int *len float *_dedx_get_atima_data(int target, int *err) { *err = 0; char file[] = "atima_compos"; - char path[512]; - _dedx_set_folder(); + char path[DEDX_PATH_SIZE]; + const char *folder = _dedx_get_data_path(); char str[100]; float *compos; diff --git a/libdedx/dedx_file_access.h b/libdedx/dedx_file_access.h index 8390101..b51deac 100644 --- a/libdedx/dedx_file_access.h +++ b/libdedx/dedx_file_access.h @@ -14,6 +14,8 @@ #include "dedx_config.h" #include "dedx_split.h" +#define DEDX_PATH_SIZE 512 + void _dedx_convert_to_binary(char *path, char *output, int *err); void _dedx_read_binary_data(stopping_data *data, int prog, int ion, int target, int *err); From d068539c34b8a86af30f1306da55837477bd42c1 Mon Sep 17 00:00:00 2001 From: Niels Bassler Date: Tue, 31 Mar 2026 14:03:13 +0200 Subject: [PATCH 2/8] Refactor error handling --- CONTRIBUTING.md | 34 +++++++ libdedx/CMakeLists.txt | 2 +- libdedx/dedx.c | 96 +++++++++--------- libdedx/dedx.h | 2 + libdedx/dedx_error.h | 55 +++++++++++ libdedx/dedx_file_access.c | 178 +++++++++++++++++++--------------- libdedx/dedx_mstar.c | 2 +- libdedx/dedx_periodic_table.c | 10 +- libdedx/dedx_periodic_table.h | 2 + libdedx/dedx_tools.c | 6 +- libdedx/dedx_validate.c | 4 +- 11 files changed, 254 insertions(+), 137 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 libdedx/dedx_error.h diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..09964eb --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,34 @@ +# Contributing to libdedx + +## C coding style + +### Variable declarations + +Declare all variables at the top of their enclosing block, before any statements. +This is consistent with the Linux kernel coding style and makes the variable +inventory of a function visible before reading the logic. + +```c +/* good */ +int foo(int x) { + const char *path; + int result; + FILE *fp; + + path = get_path(); + fp = fopen(path, "r"); + ... +} + +/* bad — declaration mixed into statements */ +int foo(int x) { + const char *path = get_path(); + FILE *fp = fopen(path, "r"); + do_something(); + int result = 0; /* not allowed */ + ... +} +``` + +Declarations at the top of an inner block (e.g. inside an `if` or `for`) are +fine when the variable is genuinely local to that scope. diff --git a/libdedx/CMakeLists.txt b/libdedx/CMakeLists.txt index deeeac8..2a9d36c 100644 --- a/libdedx/CMakeLists.txt +++ b/libdedx/CMakeLists.txt @@ -47,7 +47,7 @@ if(NOT WIN32) target_link_libraries(dedx_shared PUBLIC m) endif() -install(FILES dedx.h dedx_tools.h dedx_wrappers.h DESTINATION include) +install(FILES dedx.h dedx_error.h dedx_tools.h dedx_wrappers.h DESTINATION include) install(TARGETS dedx dedx_shared RUNTIME DESTINATION bin diff --git a/libdedx/dedx.c b/libdedx/dedx.c index 55bc4e3..efd4eee 100644 --- a/libdedx/dedx.c +++ b/libdedx/dedx.c @@ -55,18 +55,18 @@ int _dedx_load_atima(stopping_data *data, dedx_config *config, float *energy, in dedx_workspace *dedx_allocate_workspace(unsigned int count, int *err) { int i = 0; - *err = 0; + *err = DEDX_OK; dedx_workspace *temp = malloc(sizeof(dedx_workspace)); if (temp == NULL) { - *err = 301; + *err = DEDX_ERR_NO_MEMORY; return NULL; } temp->loaded_data = malloc(count * sizeof(_dedx_lookup_data *)); for (i = 0; i < count; i++) { temp->loaded_data[i] = malloc(sizeof(_dedx_lookup_data)); if (temp->loaded_data[i] == NULL) { - *err = 301; + *err = DEDX_ERR_NO_MEMORY; return NULL; } } @@ -76,7 +76,7 @@ dedx_workspace *dedx_allocate_workspace(unsigned int count, int *err) { } void dedx_free_workspace(dedx_workspace *workspace, int *err) { int i = 0; - *err = 0; + *err = DEDX_OK; for (i = 0; i < workspace->datasets; i++) { free(workspace->loaded_data[i]); @@ -86,7 +86,7 @@ void dedx_free_workspace(dedx_workspace *workspace, int *err) { } int _dedx_load_data(dedx_workspace *ws, stopping_data *data, float *energy, int prog, int *err) { int active_dataset = ws->active_datasets; - *err = 0; + *err = DEDX_OK; _dedx_calculate_coefficients(ws->loaded_data[active_dataset]->base, energy, data->data, data->length); ws->loaded_data[active_dataset]->acc.cache = 0; @@ -106,7 +106,7 @@ int _dedx_check_energy_bounds(_dedx_lookup_data *data, float energy) { float low = data->base[0].x; float high = data->base[length - 1].x; if (energy < low || energy > high) { - return 101; + return DEDX_ERR_ENERGY_OUT_OF_RANGE; } return 0; } @@ -114,76 +114,76 @@ int _dedx_check_energy_bounds(_dedx_lookup_data *data, float energy) { /*Return an explanation to the error code*/ void dedx_get_error_code(char *err_str, int err) { switch (err) { - case 0: + case DEDX_OK: strcpy(err_str, "No error."); break; - case 1: + case DEDX_ERR_NO_COMPOS_FILE: strcpy(err_str, "Composition file compos.txt does not exist."); break; - case 2: + case DEDX_ERR_NO_GAS_FILE: strcpy(err_str, "MSTAR file mstar_gas_states.dat does not exist."); break; - case 3: + case DEDX_ERR_NO_CHARGE_FILE: strcpy(err_str, "MSTAR effective_charge.dat file does not exist."); break; - case 4: + case DEDX_ERR_NO_BINARY_DATA: strcpy(err_str, "Unable to access binary data file."); break; - case 5: + case DEDX_ERR_NO_BINARY_ENERGY: strcpy(err_str, "Unable to access binary energy file."); break; - case 6: + case DEDX_ERR_WRITE_FAILED: strcpy(err_str, "Unable to write to disk."); break; - case 7: + case DEDX_ERR_NO_ENERGY_FILE: strcpy(err_str, "Unable to read energy file."); break; - case 8: + case DEDX_ERR_NO_DATA_FILE: strcpy(err_str, "Unable to read data file."); break; - case 9: + case DEDX_ERR_NO_NAMES_FILE: strcpy(err_str, "Unable to read short_names file."); break; - case 10: + case DEDX_ERR_NO_COMPOSITION: strcpy(err_str, "Unable to read composition file."); break; - case 11: + case DEDX_ERR_NO_ATIMA_FILE: strcpy(err_str, "Unable to read atima composition file."); break; - case 101: + case DEDX_ERR_ENERGY_OUT_OF_RANGE: strcpy(err_str, "Energy out of bounds."); break; - case 201: + case DEDX_ERR_TARGET_NOT_FOUND: strcpy(err_str, "Target is not in composition file."); break; - case 202: + case DEDX_ERR_COMBINATION_NOT_FOUND: strcpy(err_str, "Target and ion combination is not in data file."); break; - case 203: + case DEDX_ERR_INVALID_DATASET_ID: strcpy(err_str, "ID does not exist."); break; - case 204: + case DEDX_ERR_NOT_AN_ELEMENT: strcpy(err_str, "Target is not an atomic element."); break; - case 205: + case DEDX_ERR_ESTAR_NOT_IMPL: strcpy(err_str, "ESTAR is not implemented yet."); break; - case 206: + case DEDX_ERR_ION_NOT_SUPPORTED_MSTAR: strcpy(err_str, "Ion is not supported for MSTAR."); break; - case 207: + case DEDX_ERR_ION_NOT_SUPPORTED: strcpy(err_str, "Ion is not supported for requested table."); break; - case 208: + case DEDX_ERR_RHO_REQUIRED: strcpy(err_str, "Rho must be specified in this configuration."); break; - case 209: + case DEDX_ERR_ION_A_REQUIRED: strcpy(err_str, "ion_a must be specified in this configuration."); break; - case 210: + case DEDX_ERR_INVALID_I_VALUE: strcpy(err_str, "I value must be larger than zero."); break; - case 301: + case DEDX_ERR_NO_MEMORY: strcpy(err_str, "Out of memory"); break; @@ -394,12 +394,12 @@ int _dedx_load_config_clean(dedx_workspace *ws, dedx_config *config, int *err) { int ion = config->ion; int target = config->target; config->bragg_used = 0; - *err = 0; + *err = DEDX_OK; stopping_data data; // check if ion is available in requested program if (!_dedx_check_ion(prog, ion)) { - *err = 207; + *err = DEDX_ERR_ION_NOT_SUPPORTED; return -1; } config->_temp_i_value = config->i_value; @@ -409,14 +409,14 @@ int _dedx_load_config_clean(dedx_workspace *ws, dedx_config *config, int *err) { if (*err != 0) { // Check whether the error was that the combination wasn't in the data files and target is a compound - if (*err == 202 && target > 99) { - *err = 0; + if (*err == DEDX_ERR_COMBINATION_NOT_FOUND && target > 99) { + *err = DEDX_OK; _dedx_evaluate_compound(config, err); if (*err != 0) return -1; if (config->elements_length == 0) { printf("error \n"); - *err = 201; + *err = DEDX_ERR_TARGET_NOT_FOUND; return -1; } cfg = _dedx_load_compound(ws, config, err); @@ -440,7 +440,7 @@ int _dedx_find_data(stopping_data *data, dedx_config *config, float *energy, int int ion_load = ion; int target_load = target; - *err = 0; + *err = DEDX_OK; if (prog == DEDX_ICRU) { if (ion == 1) { @@ -460,14 +460,14 @@ int _dedx_find_data(stopping_data *data, dedx_config *config, float *energy, int } else if (ion == 2) { prog_load = DEDX_ICRU49; } else { - *err = 202; + *err = DEDX_ERR_COMBINATION_NOT_FOUND; return -1; } } // ESTAR not supported else if (prog == DEDX_ESTAR) { - *err = 205; + *err = DEDX_ERR_ESTAR_NOT_IMPL; return -1; } else if (prog == DEDX_ICRU73 && !(target == 276 || target == 104)) { prog_load = DEDX_ICRU73_OLD; @@ -513,10 +513,10 @@ int _dedx_load_compound(dedx_workspace *ws, dedx_config *config, int *err) { stopping_data data; stopping_data *compound_data = malloc(sizeof(stopping_data) * length); - *err = 0; + *err = DEDX_OK; if (compound_data == NULL) { - *err = 301; + *err = DEDX_ERR_NO_MEMORY; return -1; } weight = config->elements_mass_fraction; @@ -528,7 +528,7 @@ int _dedx_load_compound(dedx_workspace *ws, dedx_config *config, int *err) { if (config->elements_i_value != NULL) { config->_temp_i_value = config->elements_i_value[i]; if (config->elements_i_value[i] <= 0.0) { - *err = 210; + *err = DEDX_ERR_INVALID_I_VALUE; return -1; } } @@ -554,9 +554,9 @@ int _dedx_load_compound(dedx_workspace *ws, dedx_config *config, int *err) { int _dedx_load_bethe_2(stopping_data *data, dedx_config *config, float *energy, int *err) { int i = 0; - *err = 0; + *err = DEDX_OK; if (config->target > 99) { - *err = 202; + *err = DEDX_ERR_COMBINATION_NOT_FOUND; return -1; } float PZ, PA, TZ, TA, rho, pot; @@ -584,19 +584,19 @@ int _dedx_load_bethe_2(stopping_data *data, dedx_config *config, float *energy, return 0; } int _dedx_load_atima(stopping_data *data, dedx_config *config, float *energy, int *err) { - *err = 0; + *err = DEDX_OK; return 0; } float dedx_get_stp(dedx_workspace *ws, dedx_config *config, float energy, int *err) { int id = config->cfg_id; - *err = 0; + *err = DEDX_OK; // Check that the energy is within the boundary - if ((*err = _dedx_check_energy_bounds(ws->loaded_data[id], energy)) != 0) + if ((*err = _dedx_check_energy_bounds(ws->loaded_data[id], energy)) != DEDX_OK) return 0; if (id > ws->active_datasets) // Check that the dataset is loaded. { - *err = 203; + *err = DEDX_ERR_INVALID_DATASET_ID; return 0; } // Evaluating the spline function @@ -615,7 +615,7 @@ void dedx_free_config(dedx_config *config, int *err) { free(config->elements_i_value); free(config); } - *err = 0; + *err = DEDX_OK; } float dedx_get_simple_stp(int ion, int target, float energy, int *err) { diff --git a/libdedx/dedx.h b/libdedx/dedx.h index 75ad2a9..e7846da 100644 --- a/libdedx/dedx.h +++ b/libdedx/dedx.h @@ -1,6 +1,8 @@ #ifndef DEDX_H_INCLUDED #define DEDX_H_INCLUDED +#include "dedx_error.h" + /** * @file dedx.h * @brief Public API for libdedx — a stopping power (dE/dx) library. diff --git a/libdedx/dedx_error.h b/libdedx/dedx_error.h new file mode 100644 index 0000000..1e16ef1 --- /dev/null +++ b/libdedx/dedx_error.h @@ -0,0 +1,55 @@ +#ifndef DEDX_ERROR_H_INCLUDED +#define DEDX_ERROR_H_INCLUDED + +/** + * @file dedx_error.h + * @brief Error codes returned via the int *err output parameter. + * + * Functions signal success by setting *err = DEDX_OK (0). + * On failure they set *err to one of the values below and, unless + * stated otherwise, return 0 / NULL / -1. + */ + +/** No error. */ +#define DEDX_OK 0 + +/** @defgroup err_file File I/O errors (1–11) + * @{ */ +#define DEDX_ERR_NO_COMPOS_FILE 1 /**< compos.txt not found */ +#define DEDX_ERR_NO_GAS_FILE 2 /**< gas_states.dat not found */ +#define DEDX_ERR_NO_CHARGE_FILE 3 /**< effective_charge.dat not found */ +#define DEDX_ERR_NO_BINARY_DATA 4 /**< binary stopping-power data file inaccessible */ +#define DEDX_ERR_NO_BINARY_ENERGY 5 /**< binary energy-grid file inaccessible */ +#define DEDX_ERR_WRITE_FAILED 6 /**< cannot write to disk */ +#define DEDX_ERR_NO_ENERGY_FILE 7 /**< energy .dat source file unreadable */ +#define DEDX_ERR_NO_DATA_FILE 8 /**< stopping-power .dat source file unreadable */ +#define DEDX_ERR_NO_NAMES_FILE 9 /**< short_names file unreadable (reserved) */ +#define DEDX_ERR_NO_COMPOSITION 10 /**< elemental composition file unreadable */ +#define DEDX_ERR_NO_ATIMA_FILE 11 /**< ATIMA composition file unreadable (reserved) */ +/** @} */ + +/** @defgroup err_bounds Bounds errors (101) + * @{ */ +#define DEDX_ERR_ENERGY_OUT_OF_RANGE 101 /**< requested energy outside tabulated range */ +/** @} */ + +/** @defgroup err_data Data and configuration errors (201–210) + * @{ */ +#define DEDX_ERR_TARGET_NOT_FOUND 201 /**< target not found in composition table */ +#define DEDX_ERR_COMBINATION_NOT_FOUND 202 /**< ion/target combination not in data file */ +#define DEDX_ERR_INVALID_DATASET_ID 203 /**< dataset ID does not exist in workspace */ +#define DEDX_ERR_NOT_AN_ELEMENT 204 /**< ID does not correspond to an atomic element */ +#define DEDX_ERR_ESTAR_NOT_IMPL 205 /**< ESTAR program is not implemented */ +#define DEDX_ERR_ION_NOT_SUPPORTED_MSTAR 206 /**< ion not supported for MSTAR (reserved) */ +#define DEDX_ERR_ION_NOT_SUPPORTED 207 /**< ion not supported by requested program */ +#define DEDX_ERR_RHO_REQUIRED 208 /**< target density rho must be provided */ +#define DEDX_ERR_ION_A_REQUIRED 209 /**< nucleon number ion_a must be provided */ +#define DEDX_ERR_INVALID_I_VALUE 210 /**< mean excitation potential must be > 0 */ +/** @} */ + +/** @defgroup err_memory Memory errors (301) + * @{ */ +#define DEDX_ERR_NO_MEMORY 301 /**< memory allocation failed */ +/** @} */ + +#endif /* DEDX_ERROR_H_INCLUDED */ diff --git a/libdedx/dedx_file_access.c b/libdedx/dedx_file_access.c index 880284f..a467954 100644 --- a/libdedx/dedx_file_access.c +++ b/libdedx/dedx_file_access.c @@ -24,9 +24,10 @@ static const char *_dedx_get_data_path(void) { static char resolved[DEDX_PATH_SIZE]; static int done = 0; + struct stat st; + char probe[DEDX_PATH_SIZE]; + if (!done) { - struct stat st; - char probe[DEDX_PATH_SIZE]; strcpy(probe, DEDX_DATA_PATH_LOCAL); strcat(probe, "icru_pstarEng.dat"); if (stat(probe, &st) == 0) @@ -39,31 +40,35 @@ static const char *_dedx_get_data_path(void) { } void _dedx_convert_to_binary(char *path, char *output, int *err) { - *err = 0; - FILE *fp = fopen(path, "r"); - FILE *out = fopen(output, "wb+"); + FILE *fp; + FILE *out; char line[100]; int datalines = 0; + int i; + unsigned int length; float data[_DEDX_MAXELEMENTS]; char **temp = NULL; stopping_data container; + + *err = DEDX_OK; + fp = fopen(path, "r"); + out = fopen(output, "wb+"); if (fp == NULL || out == NULL) { if (out == NULL) - *err = 6; + *err = DEDX_ERR_WRITE_FAILED; else - *err = 8; + *err = DEDX_ERR_NO_DATA_FILE; return; } while (!feof(fp)) { if (fgets(line, 100, fp) == NULL) { } if (line[0] == '#') { - - unsigned int length = 0; + length = 0; + i = 0; memset(&data, 0, _DEDX_MAXELEMENTS); temp = _dedx_split(line, ':', &length, 100); temp[0][0] = ' '; - int i = 0; datalines = atoi(temp[2]); while (i++ < datalines && !feof(fp)) { if (fgets(line, 100, fp) == NULL) { @@ -83,58 +88,63 @@ void _dedx_convert_to_binary(char *path, char *output, int *err) { } void _dedx_read_binary_data(stopping_data *data, int prog, int ion, int target, int *err) { - *err = 0; - const char *folder = _dedx_get_data_path(); + const char *folder; char path[DEDX_PATH_SIZE]; + char input_path[DEDX_PATH_SIZE]; + FILE *fp; + stopping_data dat; + + *err = DEDX_OK; + folder = _dedx_get_data_path(); path[0] = '\0'; strcat(path, folder); strcat(path, _dedx_get_program_file(prog)); strcat(path, ".bin"); - FILE *fp = fopen(path, "rb"); + fp = fopen(path, "rb"); if (fp == NULL) { - char input_path[DEDX_PATH_SIZE]; input_path[0] = '\0'; strcat(input_path, folder); strcat(input_path, _dedx_get_program_file(prog)); strcat(input_path, ".dat"); _dedx_convert_to_binary(input_path, path, err); - if (*err != 0) { - *err = 4; + if (*err != DEDX_OK) { + *err = DEDX_ERR_NO_BINARY_DATA; return; } fp = fopen(path, "rb"); if (fp == NULL) { - *err = 4; + *err = DEDX_ERR_NO_BINARY_DATA; return; } } - stopping_data dat; - *err = 202; + *err = DEDX_ERR_COMBINATION_NOT_FOUND; while (fread(&dat, sizeof(stopping_data), 1, fp) == 1) { if (dat.target == target && dat.ion == ion) { memcpy(data, &dat, sizeof(stopping_data)); - *err = 0; + *err = DEDX_OK; } } fclose(fp); } void _dedx_convert_energy_binary(char *path, char *output, int *err) { - *err = 0; - FILE *fp = fopen(path, "r"); - // TODO: Next line wont work after installation, unless user is root. - FILE *out = fopen(output, "wb+"); + FILE *fp; + FILE *out; char line[100]; int datalines; int i; float data[_DEDX_MAXELEMENTS]; - if (fp == NULL || out == NULL) { + *err = DEDX_OK; + fp = fopen(path, "r"); + // TODO: Next line wont work after installation, unless user is root. + out = fopen(output, "wb+"); + if (fp == NULL || out == NULL) { if (out == NULL) - *err = 6; + *err = DEDX_ERR_WRITE_FAILED; else - *err = 7; + *err = DEDX_ERR_NO_ENERGY_FILE; return; } @@ -153,29 +163,32 @@ void _dedx_convert_energy_binary(char *path, char *output, int *err) { } void _dedx_read_energy_data(float *energy, int prog, int *err) { - *err = 0; - const char *folder = _dedx_get_data_path(); + const char *folder; char path[DEDX_PATH_SIZE]; + char input_path[DEDX_PATH_SIZE]; + FILE *fp; + + *err = DEDX_OK; + folder = _dedx_get_data_path(); path[0] = '\0'; strcat(path, folder); strcat(path, _dedx_get_energy_file(prog)); strcat(path, ".bin"); - FILE *fp = fopen(path, "rb"); + fp = fopen(path, "rb"); if (fp == NULL) { - char input_path[DEDX_PATH_SIZE]; input_path[0] = '\0'; strcat(input_path, folder); strcat(input_path, _dedx_get_energy_file(prog)); strcat(input_path, ".dat"); _dedx_convert_energy_binary(input_path, path, err); - if (*err != 0) { - *err = 5; + if (*err != DEDX_OK) { + *err = DEDX_ERR_NO_BINARY_ENERGY; return; } fp = fopen(path, "rb"); if (fp == NULL) { - *err = 5; + *err = DEDX_ERR_NO_BINARY_ENERGY; return; } } @@ -185,29 +198,32 @@ void _dedx_read_energy_data(float *energy, int prog, int *err) { } float _dedx_read_effective_charge(int id, int *err) { - *err = 0; - float charge = -1; - if (id < 99) { - charge = (float) id; - return charge; - } - const char *folder = _dedx_get_data_path(); + const char *folder; char line[100]; - char **temp = NULL; - unsigned int items = 0; + char **temp; + unsigned int items; char file[] = "effective_charge.dat"; char path[DEDX_PATH_SIZE]; + FILE *fp; + float charge = -1; + + *err = DEDX_OK; + if (id < 99) { + return (float) id; + } + folder = _dedx_get_data_path(); + items = 0; + temp = NULL; strcpy(path, folder); strcat(path, file); - FILE *fp = fopen(path, "r"); + fp = fopen(path, "r"); if (fp == NULL) { - *err = 3; + *err = DEDX_ERR_NO_CHARGE_FILE; return 0; } while (!feof(fp)) { - if (fgets(line, 100, fp) != NULL) { } temp = _dedx_split(line, '\t', &items, 100); @@ -223,17 +239,21 @@ float _dedx_read_effective_charge(int id, int *err) { } size_t _dedx_target_is_gas(int target, int *err) { - *err = 0; - size_t is_gas = 0; + const char *folder; + size_t is_gas; char str[100]; - const char *folder = _dedx_get_data_path(); char file[] = "gas_states.dat"; char path[DEDX_PATH_SIZE]; + FILE *fp; + + *err = DEDX_OK; + is_gas = 0; + folder = _dedx_get_data_path(); strcpy(path, folder); strcat(path, file); - FILE *fp = fopen(path, "r"); + fp = fopen(path, "r"); if (fp == NULL) { - *err = 2; + *err = DEDX_ERR_NO_GAS_FILE; return 0; } @@ -248,32 +268,32 @@ size_t _dedx_target_is_gas(int target, int *err) { } float _dedx_read_density(int id, int *err) { - float density = 1.0; + const char *folder; + float density; char str[100]; char path[DEDX_PATH_SIZE]; char file[] = "compos.txt"; - unsigned int items = 0; + unsigned int items; char **temp; FILE *fp; - *err = 0; - const char *folder = _dedx_get_data_path(); + *err = DEDX_OK; + density = 1.0; + items = 0; + folder = _dedx_get_data_path(); strcpy(path, folder); strcat(path, file); fp = fopen(path, "r"); if (fp == NULL) { - *err = 1; + *err = DEDX_ERR_NO_COMPOS_FILE; return 0; } while (!feof(fp)) { - if (fgets(str, 100, fp) == NULL) { } - temp = _dedx_split(str, '\t', &items, 100); - if (atoi(temp[0]) == id) { density = atof(temp[1]); _dedx_free_split_temp(temp); @@ -283,27 +303,30 @@ float _dedx_read_density(int id, int *err) { } fclose(fp); if (density == 0.0) { - *err = 201; + *err = DEDX_ERR_TARGET_NOT_FOUND; } return density; } float _dedx_get_i_value(int target, int state, int *err) { - float pot = 0.0; + const char *folder; + float pot; char file[] = "compos.txt"; char path[DEDX_PATH_SIZE]; - const char *folder = _dedx_get_data_path(); char str[100]; char **temp; - unsigned int items = 0; + unsigned int items; + FILE *fp; + pot = 0.0; + items = 0; + folder = _dedx_get_data_path(); strcpy(path, folder); strcat(path, file); - FILE *fp = fopen(path, "r"); - + fp = fopen(path, "r"); if (fp == NULL) { - *err = 1; + *err = DEDX_ERR_NO_COMPOS_FILE; return 0; } while (!feof(fp)) { @@ -325,29 +348,30 @@ float _dedx_get_i_value(int target, int state, int *err) { } fclose(fp); if (pot == 0.0) { - *err = 201; + *err = DEDX_ERR_TARGET_NOT_FOUND; } return pot; } void _dedx_get_composition(int target, float composition[][2], unsigned int *length, int *err) { - *err = 0; + const char *folder; char file[] = "composition"; char path[DEDX_PATH_SIZE]; char str[100]; - *length = 0; float f_temp; - FILE *fp; unsigned int items; char **temp; + FILE *fp; - const char *folder = _dedx_get_data_path(); + *err = DEDX_OK; + *length = 0; + folder = _dedx_get_data_path(); strcpy(path, folder); strcat(path, file); fp = fopen(path, "r"); if (fp == NULL) { - *err = 10; + *err = DEDX_ERR_NO_COMPOSITION; return; } while (!feof(fp)) { @@ -374,23 +398,23 @@ void _dedx_get_composition(int target, float composition[][2], unsigned int *len } float *_dedx_get_atima_data(int target, int *err) { - *err = 0; + const char *folder; char file[] = "atima_compos"; char path[DEDX_PATH_SIZE]; - const char *folder = _dedx_get_data_path(); char str[100]; float *compos; - - FILE *fp; unsigned int items; char **temp; + FILE *fp; + *err = DEDX_OK; + folder = _dedx_get_data_path(); strcpy(path, folder); strcat(path, file); fp = fopen(path, "r"); if (fp == NULL) { - *err = 10; + *err = DEDX_ERR_NO_COMPOSITION; return NULL; } compos = (float *) malloc(sizeof(float) * 4); diff --git a/libdedx/dedx_mstar.c b/libdedx/dedx_mstar.c index 9c37e94..a129bb7 100644 --- a/libdedx/dedx_mstar.c +++ b/libdedx/dedx_mstar.c @@ -28,7 +28,7 @@ void _evaluate_compound_state_mstar(dedx_config *config, int *err) { else config->mstar_mode = 'd'; } - *err = 0; + *err = DEDX_OK; } void _dedx_convert_energy_to_mstar( diff --git a/libdedx/dedx_periodic_table.c b/libdedx/dedx_periodic_table.c index af619ce..481782e 100644 --- a/libdedx/dedx_periodic_table.c +++ b/libdedx/dedx_periodic_table.c @@ -4,22 +4,22 @@ float _dedx_get_atom_charge(int id, int *err) { if (id < 113) { return id; } - *err = 204; + *err = DEDX_ERR_NOT_AN_ELEMENT; return -1; } float _dedx_get_atom_mass(int id, int *err) { - *err = 0; + *err = DEDX_OK; if (id < 113) return dedx_amu[id - 1]; - *err = 204; + *err = DEDX_ERR_NOT_AN_ELEMENT; return -1; } int _dedx_get_nucleon(int id, int *err) { - *err = 0; + *err = DEDX_OK; if (id < 113) return dedx_nucl[id - 1]; - *err = 204; + *err = DEDX_ERR_NOT_AN_ELEMENT; return -1; } \ No newline at end of file diff --git a/libdedx/dedx_periodic_table.h b/libdedx/dedx_periodic_table.h index 10bfd31..2c654a9 100644 --- a/libdedx/dedx_periodic_table.h +++ b/libdedx/dedx_periodic_table.h @@ -1,6 +1,8 @@ #ifndef DEDX_PERIODIC_TABLE_H_INCLUDED #define DEDX_PERIODIC_TABLE_H_INCLUDED +#include "dedx_error.h" + static const float dedx_amu[112] = { 1.00794, 4.002602, 6.941, 9.012182, 10.811, 12.0107, 14.0067, 15.9994, 18.9984032, 20.1797, 22.98976928, 24.3050, 26.9815386, 28.0855, 30.973762, 32.065, 35.453, 39.948, 39.0983, 40.078, diff --git a/libdedx/dedx_tools.c b/libdedx/dedx_tools.c index fe8b02e..b79d416 100644 --- a/libdedx/dedx_tools.c +++ b/libdedx/dedx_tools.c @@ -96,7 +96,7 @@ double _dedx_find_min(double (*func)(double x, _dedx_tools_settings *set), _dedx } double dedx_get_inverse_csda(dedx_workspace *ws, dedx_config *config, float range, int *err) { if (config->ion_a <= 0) { - *err = 209; + *err = DEDX_ERR_ION_A_REQUIRED; return -1; } double acc = 1e-5; @@ -122,7 +122,7 @@ double dedx_get_inverse_csda(dedx_workspace *ws, dedx_config *config, float rang } double dedx_get_inverse_stp(dedx_workspace *ws, dedx_config *config, float stp, int side, int *err) { if (config->ion_a <= 0) { - *err = 209; + *err = DEDX_ERR_ION_A_REQUIRED; return -1; } double acc = 1e-5; @@ -163,7 +163,7 @@ double dedx_get_inverse_stp(dedx_workspace *ws, dedx_config *config, float stp, } double dedx_get_csda(dedx_workspace *ws, dedx_config *config, float energy, int *err) { if (config->ion_a <= 0) { - *err = 209; + *err = DEDX_ERR_ION_A_REQUIRED; return -1; } double calculation_error = 0; diff --git a/libdedx/dedx_validate.c b/libdedx/dedx_validate.c index 2e185c0..1ad1a70 100644 --- a/libdedx/dedx_validate.c +++ b/libdedx/dedx_validate.c @@ -17,7 +17,7 @@ int _dedx_validate_rho(dedx_config *config, int *err) { if (config->rho <= 0.0 && config->target != 0) { config->rho = _dedx_read_density(config->target, err); } else if (config->rho <= 0.0 && config->target == 0 && config->program >= 100) { - *err = 208; + *err = DEDX_ERR_RHO_REQUIRED; } return 0; } @@ -64,7 +64,7 @@ int _dedx_evaluate_compound(dedx_config *config, int *err) { if (*err != 0) return -1; if (compos_len == 0) { - *err = 201; + *err = DEDX_ERR_TARGET_NOT_FOUND; return -1; } config->elements_id = (int *) malloc(sizeof(int) * compos_len); From a5b63bed9caa528b8f9e1177c7a196cf9fc494eb Mon Sep 17 00:00:00 2001 From: Niels Bassler Date: Tue, 31 Mar 2026 14:10:39 +0200 Subject: [PATCH 3/8] formatting fixes --- .clang-format | 1 + libdedx/dedx.c | 11 +++++++++ libdedx/dedx.h | 5 ++++ libdedx/dedx_error.h | 46 +++++++++++++++++------------------ libdedx/dedx_periodic_table.c | 2 +- libdedx/dedx_spline.c | 2 ++ libdedx/dedx_split.c | 2 ++ libdedx/dedx_tools.c | 8 +++++- libdedx/dedx_validate.c | 6 +++++ libdedx/dedx_wrappers.c | 2 +- 10 files changed, 59 insertions(+), 26 deletions(-) diff --git a/.clang-format b/.clang-format index a466e36..9683d77 100644 --- a/.clang-format +++ b/.clang-format @@ -18,6 +18,7 @@ BraceWrapping: AllowShortFunctionsOnASingleLine: None AllowShortBlocksOnASingleLine: false +SeparateDefinitionBlocks: Always SpaceAfterCStyleCast: true SpaceBeforeParens: ControlStatements diff --git a/libdedx/dedx.c b/libdedx/dedx.c index efd4eee..3bc69fe 100644 --- a/libdedx/dedx.c +++ b/libdedx/dedx.c @@ -74,6 +74,7 @@ dedx_workspace *dedx_allocate_workspace(unsigned int count, int *err) { temp->active_datasets = 0; return temp; } + void dedx_free_workspace(dedx_workspace *workspace, int *err) { int i = 0; *err = DEDX_OK; @@ -84,6 +85,7 @@ void dedx_free_workspace(dedx_workspace *workspace, int *err) { free(workspace->loaded_data); free(workspace); } + int _dedx_load_data(dedx_workspace *ws, stopping_data *data, float *energy, int prog, int *err) { int active_dataset = ws->active_datasets; *err = DEDX_OK; @@ -100,6 +102,7 @@ int _dedx_load_data(dedx_workspace *ws, stopping_data *data, float *energy, int ws->active_datasets++; return active_dataset; } + /*Check the whether the energy are inside the boundary*/ int _dedx_check_energy_bounds(_dedx_lookup_data *data, float energy) { int length = data->datapoints; @@ -215,9 +218,11 @@ void dedx_get_version(int *major, int *minor, int *patch) { *patch = DEDX_VERSION_PATCH; return; } + void dedx_get_composition(int target, float composition[][2], unsigned int *comp_len, int *err) { _dedx_get_composition(target, composition, comp_len, err); } + float dedx_get_i_value(int target, int *err) { return _dedx_get_i_value(target, DEDX_GAS, err); } @@ -226,6 +231,7 @@ const int *dedx_get_program_list(void) { /* returns a list of available programs, terminated with -1 */ return dedx_available_programs; } + const int *dedx_get_material_list(int program) { /* returns a list of available materials, terminated with -1 */ if (program == DEDX_BETHE_EXT00 || program == DEDX_DEFAULT) @@ -283,6 +289,7 @@ float dedx_get_min_energy(int program, int ion) { } return energy_min; } + float dedx_get_max_energy(int program, int ion) { float energy_max = 0; @@ -387,6 +394,7 @@ void dedx_load_config(dedx_workspace *ws, dedx_config *config, int *err) { config->cfg_id = cfg_id; config->loaded = 1; } + int _dedx_load_config_clean(dedx_workspace *ws, dedx_config *config, int *err) { float energy[_DEDX_MAXELEMENTS]; int cfg; @@ -501,6 +509,7 @@ int _dedx_find_data(stopping_data *data, dedx_config *config, float *energy, int } return 0; } + int _dedx_load_compound(dedx_workspace *ws, dedx_config *config, int *err) { int i = 0; int j = 0; @@ -583,6 +592,7 @@ int _dedx_load_bethe_2(stopping_data *data, dedx_config *config, float *energy, free(bethe); return 0; } + int _dedx_load_atima(stopping_data *data, dedx_config *config, float *energy, int *err) { *err = DEDX_OK; return 0; @@ -603,6 +613,7 @@ float dedx_get_stp(dedx_workspace *ws, dedx_config *config, float energy, int *e return _dedx_evaluate_spline( ws->loaded_data[id]->base, energy, &(ws->loaded_data[id]->acc), ws->loaded_data[id]->n); } + void dedx_free_config(dedx_config *config, int *err) { if (config != NULL) { if (config->elements_id != NULL) diff --git a/libdedx/dedx.h b/libdedx/dedx.h index e7846da..14ec68b 100644 --- a/libdedx/dedx.h +++ b/libdedx/dedx.h @@ -45,6 +45,7 @@ enum { DEDX_DEFAULT = 100, /**< Default program (Bethe formula) */ DEDX_BETHE_EXT00 /**< Bethe formula with extensions */ }; + /** @} */ /** @@ -56,6 +57,7 @@ enum { DEDX_GAS, /**< Force gas state */ DEDX_CONDENSED /**< Force condensed state */ }; + /** @} */ /** @@ -73,6 +75,7 @@ enum { DEDX_MSTAR_MODE_D = 'd', DEDX_MSTAR_MODE_DEFAULT = 'b' /**< Recommended by Helmut Paul */ }; + /** @} */ /** @@ -368,6 +371,7 @@ enum { DEDX_WATER_VAPOR, DEDX_XYLENE }; + /** @} */ /* ions_and_materials */ /** @defgroup special_ions Special particle identifiers @@ -503,6 +507,7 @@ typedef struct { int datapoints; _dedx_lookup_accelerator acc; } _dedx_lookup_data; + /** @endcond */ /** diff --git a/libdedx/dedx_error.h b/libdedx/dedx_error.h index 1e16ef1..a8784e4 100644 --- a/libdedx/dedx_error.h +++ b/libdedx/dedx_error.h @@ -11,45 +11,45 @@ */ /** No error. */ -#define DEDX_OK 0 +#define DEDX_OK 0 /** @defgroup err_file File I/O errors (1–11) * @{ */ -#define DEDX_ERR_NO_COMPOS_FILE 1 /**< compos.txt not found */ -#define DEDX_ERR_NO_GAS_FILE 2 /**< gas_states.dat not found */ -#define DEDX_ERR_NO_CHARGE_FILE 3 /**< effective_charge.dat not found */ -#define DEDX_ERR_NO_BINARY_DATA 4 /**< binary stopping-power data file inaccessible */ -#define DEDX_ERR_NO_BINARY_ENERGY 5 /**< binary energy-grid file inaccessible */ -#define DEDX_ERR_WRITE_FAILED 6 /**< cannot write to disk */ -#define DEDX_ERR_NO_ENERGY_FILE 7 /**< energy .dat source file unreadable */ -#define DEDX_ERR_NO_DATA_FILE 8 /**< stopping-power .dat source file unreadable */ -#define DEDX_ERR_NO_NAMES_FILE 9 /**< short_names file unreadable (reserved) */ -#define DEDX_ERR_NO_COMPOSITION 10 /**< elemental composition file unreadable */ -#define DEDX_ERR_NO_ATIMA_FILE 11 /**< ATIMA composition file unreadable (reserved) */ +#define DEDX_ERR_NO_COMPOS_FILE 1 /**< compos.txt not found */ +#define DEDX_ERR_NO_GAS_FILE 2 /**< gas_states.dat not found */ +#define DEDX_ERR_NO_CHARGE_FILE 3 /**< effective_charge.dat not found */ +#define DEDX_ERR_NO_BINARY_DATA 4 /**< binary stopping-power data file inaccessible */ +#define DEDX_ERR_NO_BINARY_ENERGY 5 /**< binary energy-grid file inaccessible */ +#define DEDX_ERR_WRITE_FAILED 6 /**< cannot write to disk */ +#define DEDX_ERR_NO_ENERGY_FILE 7 /**< energy .dat source file unreadable */ +#define DEDX_ERR_NO_DATA_FILE 8 /**< stopping-power .dat source file unreadable */ +#define DEDX_ERR_NO_NAMES_FILE 9 /**< short_names file unreadable (reserved) */ +#define DEDX_ERR_NO_COMPOSITION 10 /**< elemental composition file unreadable */ +#define DEDX_ERR_NO_ATIMA_FILE 11 /**< ATIMA composition file unreadable (reserved) */ /** @} */ /** @defgroup err_bounds Bounds errors (101) * @{ */ -#define DEDX_ERR_ENERGY_OUT_OF_RANGE 101 /**< requested energy outside tabulated range */ +#define DEDX_ERR_ENERGY_OUT_OF_RANGE 101 /**< requested energy outside tabulated range */ /** @} */ /** @defgroup err_data Data and configuration errors (201–210) * @{ */ -#define DEDX_ERR_TARGET_NOT_FOUND 201 /**< target not found in composition table */ -#define DEDX_ERR_COMBINATION_NOT_FOUND 202 /**< ion/target combination not in data file */ -#define DEDX_ERR_INVALID_DATASET_ID 203 /**< dataset ID does not exist in workspace */ -#define DEDX_ERR_NOT_AN_ELEMENT 204 /**< ID does not correspond to an atomic element */ -#define DEDX_ERR_ESTAR_NOT_IMPL 205 /**< ESTAR program is not implemented */ +#define DEDX_ERR_TARGET_NOT_FOUND 201 /**< target not found in composition table */ +#define DEDX_ERR_COMBINATION_NOT_FOUND 202 /**< ion/target combination not in data file */ +#define DEDX_ERR_INVALID_DATASET_ID 203 /**< dataset ID does not exist in workspace */ +#define DEDX_ERR_NOT_AN_ELEMENT 204 /**< ID does not correspond to an atomic element */ +#define DEDX_ERR_ESTAR_NOT_IMPL 205 /**< ESTAR program is not implemented */ #define DEDX_ERR_ION_NOT_SUPPORTED_MSTAR 206 /**< ion not supported for MSTAR (reserved) */ -#define DEDX_ERR_ION_NOT_SUPPORTED 207 /**< ion not supported by requested program */ -#define DEDX_ERR_RHO_REQUIRED 208 /**< target density rho must be provided */ -#define DEDX_ERR_ION_A_REQUIRED 209 /**< nucleon number ion_a must be provided */ -#define DEDX_ERR_INVALID_I_VALUE 210 /**< mean excitation potential must be > 0 */ +#define DEDX_ERR_ION_NOT_SUPPORTED 207 /**< ion not supported by requested program */ +#define DEDX_ERR_RHO_REQUIRED 208 /**< target density rho must be provided */ +#define DEDX_ERR_ION_A_REQUIRED 209 /**< nucleon number ion_a must be provided */ +#define DEDX_ERR_INVALID_I_VALUE 210 /**< mean excitation potential must be > 0 */ /** @} */ /** @defgroup err_memory Memory errors (301) * @{ */ -#define DEDX_ERR_NO_MEMORY 301 /**< memory allocation failed */ +#define DEDX_ERR_NO_MEMORY 301 /**< memory allocation failed */ /** @} */ #endif /* DEDX_ERROR_H_INCLUDED */ diff --git a/libdedx/dedx_periodic_table.c b/libdedx/dedx_periodic_table.c index 481782e..2670c8b 100644 --- a/libdedx/dedx_periodic_table.c +++ b/libdedx/dedx_periodic_table.c @@ -22,4 +22,4 @@ int _dedx_get_nucleon(int id, int *err) { return dedx_nucl[id - 1]; *err = DEDX_ERR_NOT_AN_ELEMENT; return -1; -} \ No newline at end of file +} diff --git a/libdedx/dedx_spline.c b/libdedx/dedx_spline.c index d7f5629..98bc31f 100644 --- a/libdedx/dedx_spline.c +++ b/libdedx/dedx_spline.c @@ -15,6 +15,7 @@ along with libdedx. If not, see . */ #include "dedx_spline.h" + int _dedx_linear_search(_dedx_spline_base *coef, float value) { int i; for (i = 0; i < _DEDX_MAXELEMENTS; i++) { @@ -24,6 +25,7 @@ int _dedx_linear_search(_dedx_spline_base *coef, float value) { } return i; } + int _dedx_binary_search(_dedx_spline_base *coef, float value, int n) { int head = n - 1; int tail = 0; diff --git a/libdedx/dedx_split.c b/libdedx/dedx_split.c index fa7ccc8..658bd88 100644 --- a/libdedx/dedx_split.c +++ b/libdedx/dedx_split.c @@ -17,6 +17,7 @@ #include "dedx_split.h" #include + char **_dedx_split(char *string, char splitCaracter, unsigned int *items, unsigned int strLength) { int i = 0; int j = 0; @@ -53,6 +54,7 @@ char **_dedx_split(char *string, char splitCaracter, unsigned int *items, unsign (*items)++; return words; } + void _dedx_free_split_temp(char **temp) { int i = 0; for (i = 0; i < 10; i++) diff --git a/libdedx/dedx_tools.c b/libdedx/dedx_tools.c index b79d416..3b3d785 100644 --- a/libdedx/dedx_tools.c +++ b/libdedx/dedx_tools.c @@ -12,6 +12,7 @@ typedef struct { dedx_workspace *ws; dedx_config *cfg; } _dedx_tools_settings; + double _dedx_adapt24(double (*func)(double x, _dedx_tools_settings *set), _dedx_tools_settings *set, double a, @@ -41,6 +42,7 @@ double _dedx_adapt24(double (*func)(double x, _dedx_tools_settings *set), return ql + qr; } } + double _dedx_adapt(double (*func)(double x, _dedx_tools_settings *set), _dedx_tools_settings *set, double a, @@ -65,6 +67,7 @@ double _dedx_find_min_stp_func(double x, _dedx_tools_settings *set) { return INFINITY; return stp; } + double _dedx_find_min(double (*func)(double x, _dedx_tools_settings *set), _dedx_tools_settings *set, double acc) { double x[] = {0.01, 10}; double f[] = {func(x[0], set), func(x[1], set)}; @@ -94,6 +97,7 @@ double _dedx_find_min(double (*func)(double x, _dedx_tools_settings *set), _dedx } return (x[0] + x[1]) / 2; } + double dedx_get_inverse_csda(dedx_workspace *ws, dedx_config *config, float range, int *err) { if (config->ion_a <= 0) { *err = DEDX_ERR_ION_A_REQUIRED; @@ -120,6 +124,7 @@ double dedx_get_inverse_csda(dedx_workspace *ws, dedx_config *config, float rang } return (min + max) / 2; } + double dedx_get_inverse_stp(dedx_workspace *ws, dedx_config *config, float stp, int side, int *err) { if (config->ion_a <= 0) { *err = DEDX_ERR_ION_A_REQUIRED; @@ -161,6 +166,7 @@ double dedx_get_inverse_stp(dedx_workspace *ws, dedx_config *config, float stp, // free(cfg); might be used later again return (x1 + x2) / 2; } + double dedx_get_csda(dedx_workspace *ws, dedx_config *config, float energy, int *err) { if (config->ion_a <= 0) { *err = DEDX_ERR_ION_A_REQUIRED; @@ -244,4 +250,4 @@ int convert_units(const int old_unit, new_values[i] = old_values[i] * conversion_rate; } return err; -} \ No newline at end of file +} diff --git a/libdedx/dedx_validate.c b/libdedx/dedx_validate.c index 1ad1a70..3888ab3 100644 --- a/libdedx/dedx_validate.c +++ b/libdedx/dedx_validate.c @@ -13,6 +13,7 @@ int _dedx_set_names(dedx_config *config, int *err) { config->program_name = dedx_get_program_name(config->program); return 0; } + int _dedx_validate_rho(dedx_config *config, int *err) { if (config->rho <= 0.0 && config->target != 0) { config->rho = _dedx_read_density(config->target, err); @@ -21,6 +22,7 @@ int _dedx_validate_rho(dedx_config *config, int *err) { } return 0; } + int _dedx_evaluate_i_pot(dedx_config *config, int *err) { int i; if (config->elements_i_value == NULL && config->target != 0) { @@ -50,6 +52,7 @@ int _dedx_evaluate_i_pot(dedx_config *config, int *err) { } return 0; } + int _dedx_evaluate_compound(dedx_config *config, int *err) { int i = 0; if (config->target > 0 && config->target <= 99) { @@ -101,6 +104,7 @@ int _dedx_evaluate_compound(dedx_config *config, int *err) { } return 0; } + int _dedx_validate_config(dedx_config *config, int *err) { _dedx_validate_rho(config, err); if (*err != 0) @@ -122,6 +126,7 @@ int _dedx_validate_config(dedx_config *config, int *err) { } return 0; } + int _dedx_validate_state(dedx_config *config, int *err) { if (config->compound_state == DEDX_DEFAULT_STATE) { if (_dedx_target_is_gas(config->target, err)) { @@ -132,6 +137,7 @@ int _dedx_validate_state(dedx_config *config, int *err) { } return 0; } + int _dedx_calculate_element_i_pot(dedx_config *config, int *err) { int i; float charge_avg = 0; diff --git a/libdedx/dedx_wrappers.c b/libdedx/dedx_wrappers.c index 74a44b6..01014eb 100644 --- a/libdedx/dedx_wrappers.c +++ b/libdedx/dedx_wrappers.c @@ -185,4 +185,4 @@ int dedx_get_csda_range_table(const int program, dedx_free_workspace(ws, &err); return err; -} \ No newline at end of file +} From d31dbb22757eab6e2e8cf98ae968e6a543f665df Mon Sep 17 00:00:00 2001 From: Niels Bassler Date: Tue, 31 Mar 2026 14:24:51 +0200 Subject: [PATCH 4/8] copilot fixes --- CONTRIBUTING.md | 11 +++++ examples/dedx_get.c | 1 + examples/dedx_get_sample_csv.c | 2 +- examples/scripting/invoke_func.c | 24 +++++++++++ examples/scripting/invoke_func.h | 4 ++ examples/scripting/main.c | 2 + libdedx/dedx.c | 10 +++++ libdedx/dedx_file.c | 1 + libdedx/dedx_file_access.c | 74 +++++++++++++------------------- 9 files changed, 85 insertions(+), 44 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 09964eb..077fb03 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,3 +32,14 @@ int foo(int x) { Declarations at the top of an inner block (e.g. inside an `if` or `for`) are fine when the variable is genuinely local to that scope. + +## Thread safety + +libdedx is currently **not thread-safe**. There is no synchronization around +the static path cache in `_dedx_get_data_path()`, nor around workspace mutation +in `dedx_load_config()` / `_dedx_load_data()`. Do not share a `dedx_workspace` +across threads without external locking. + +The intended fix is to replace the `done` flag in `_dedx_get_data_path()` with +C11 `call_once()`, and audit the rest of the library for shared mutable state. +This is tracked as a known issue. diff --git a/examples/dedx_get.c b/examples/dedx_get.c index 9eb4b92..1f49b57 100644 --- a/examples/dedx_get.c +++ b/examples/dedx_get.c @@ -3,6 +3,7 @@ #include #include #include + /* gcc -g -lm dedx_get.c -o dedx -Wall -ldedx*/ int main(int argc, char *argv[]) { diff --git a/examples/dedx_get_sample_csv.c b/examples/dedx_get_sample_csv.c index 37465b0..f3fa185 100644 --- a/examples/dedx_get_sample_csv.c +++ b/examples/dedx_get_sample_csv.c @@ -47,4 +47,4 @@ int main() { fclose(file); return 0; -} \ No newline at end of file +} diff --git a/examples/scripting/invoke_func.c b/examples/scripting/invoke_func.c index bb27f13..afc57e4 100644 --- a/examples/scripting/invoke_func.c +++ b/examples/scripting/invoke_func.c @@ -41,10 +41,12 @@ int get_data_type(data_item *item); char *get_variable_name(char *params, int *offset); void add_function(char *cmd, int (*func_p)(char *params)); + int set_output(FILE *out) { fp_out = out; return 0; } + int write_line(char *str) { fprintf(fp_out, "%s", str); return 0; @@ -66,6 +68,7 @@ int get_stp(data_item *config, data_item *energy, float *stp) { return 0; } + data_item *create_data_item(char *name) { data_item *curr = get_data_item(name); if (curr != NULL) { @@ -78,6 +81,7 @@ data_item *create_data_item(char *name) { data_head = curr; return curr; } + data_item *get_data_item(char *name) { data_item *curr = data_head; while (curr != NULL) { @@ -88,9 +92,11 @@ data_item *get_data_item(char *name) { } return NULL; } + int get_data_type(data_item *item) { return item->type; } + char *get_variable_name(char *params, int *offset) { char *name = (char *) calloc(20, sizeof(char)); int i = 0; @@ -103,6 +109,7 @@ char *get_variable_name(char *params, int *offset) { *offset = i + 1; return name; } + int build_functions() { add_function("CONFIG", &config); add_function("CLONE", &clone); @@ -111,6 +118,7 @@ int build_functions() { add_function("PRINT", &print); return 0; } + int invoke_function(char *cmd, char *params) { func_item *curr = func_head; do { @@ -122,6 +130,7 @@ int invoke_function(char *cmd, char *params) { } while (curr != NULL); return -1; } + void add_function(char *cmd, int (*func_p)(char *params)) { func_item *curr = (func_item *) malloc(sizeof(func_item)); strcpy(curr->cmd, cmd); @@ -129,6 +138,7 @@ void add_function(char *cmd, int (*func_p)(char *params)) { curr->next = func_head; func_head = curr; } + int clone(char *params) { char a[20]; char b[20]; @@ -172,6 +182,7 @@ int clone(char *params) { } return 0; } + int clone_config(data_item *a, data_item *b) { memcpy(a->config, b->config, sizeof(dedx_config)); dedx_config *a_conf = a->config; @@ -179,6 +190,7 @@ int clone_config(data_item *a, data_item *b) { clone_dedx_config(a_conf, b_conf); return 0; } + int clone_dedx_config(dedx_config *a_conf, dedx_config *b_conf) { memcpy(a_conf, b_conf, sizeof(dedx_config)); int length = b_conf->elements_length; @@ -200,12 +212,14 @@ int clone_dedx_config(dedx_config *a_conf, dedx_config *b_conf) { } return 0; } + int clone_energy(data_item *a, data_item *b) { a->energy = malloc(sizeof(float) * b->e_length); b->e_length = a->e_length; memcpy(a->energy, b->energy, sizeof(float) * b->e_length); return 0; } + int set(char *params) { int i = 0; int offset = 0; @@ -233,6 +247,7 @@ int set(char *params) { } return 0; } + int energy(char *params) { int offset = 0; char *name = get_variable_name(params, &offset); @@ -245,6 +260,7 @@ int energy(char *params) { set_energy(&(item->energy), &(item->e_length), ¶ms[offset]); return 0; } + int set_energy(float **energy, int *n, char *params) { int i; int j = 0; @@ -274,6 +290,7 @@ int set_energy(float **energy, int *n, char *params) { *n = items; return 0; } + int print(char *params) { int offset = 0; int i; @@ -318,6 +335,7 @@ int print(char *params) { write_line(text); return 0; } + int replace_signs(char *str) { int i = 0; int j = 0; @@ -343,6 +361,7 @@ int replace_signs(char *str) { } return 0; } + int print_list(char *text, int argv, char **args) { int i, j, k; @@ -389,6 +408,7 @@ int print_list(char *text, int argv, char **args) { print_values(text, argv, items); return 0; } + int print_values(char *text, int items_n, data_item ***items) { int i, j, k; int dim = 0; @@ -439,6 +459,7 @@ int print_values(char *text, int items_n, data_item ***items) { } return 0; } + int config(char *params) { int offset = 0; char *name; @@ -457,6 +478,7 @@ int config(char *params) { } return 0; } + int set_config_value(dedx_config *config, char *name, char *value) { if (strcmp("prog", name) == 0) { config->prog = atoi(value); @@ -473,6 +495,7 @@ int set_config_value(dedx_config *config, char *name, char *value) { } return 0; } + int set_config_list(dedx_config *config, char *name, char *list) { char params[10][20]; int i = 0; @@ -516,6 +539,7 @@ int set_config_list(dedx_config *config, char *name, char *list) { config->elements_length = items; return 0; } + int set_config(dedx_config *config, char *params) { int i = 1; int j = 0; diff --git a/examples/scripting/invoke_func.h b/examples/scripting/invoke_func.h index 06e5d28..f07162c 100644 --- a/examples/scripting/invoke_func.h +++ b/examples/scripting/invoke_func.h @@ -2,12 +2,15 @@ #define INVOKE_FUNC_DEF #include #include + enum { DEDX_SCRIPT_NONE = 0, DEDX_SCRIPT_CONFIG, DEDX_SCRIPT_ENERGY }; + struct func_struct { char cmd[20]; int (*func_p)(char *params); struct func_struct *next; }; + struct data_struct { char name[20]; dedx_config *config; @@ -18,6 +21,7 @@ struct data_struct { int type; struct data_struct *next; }; + int build_functions(); int invoke_function(char *cmd, char *params); int set_output(FILE *output); diff --git a/examples/scripting/main.c b/examples/scripting/main.c index 2877b59..46c2c37 100644 --- a/examples/scripting/main.c +++ b/examples/scripting/main.c @@ -40,6 +40,7 @@ int main(int argv, char *argc[]) { fclose(out); return 0; } + int parser(FILE *in, FILE *out) { build_functions(); set_output(out); @@ -59,6 +60,7 @@ int parser(FILE *in, FILE *out) { } return 0; } + /*Remove Comments, lineshift, tabs, white spaces, */ int clean(FILE *in, FILE *out) { char line[read_c]; diff --git a/libdedx/dedx.c b/libdedx/dedx.c index 3bc69fe..58a6e3e 100644 --- a/libdedx/dedx.c +++ b/libdedx/dedx.c @@ -63,9 +63,19 @@ dedx_workspace *dedx_allocate_workspace(unsigned int count, int *err) { return NULL; } temp->loaded_data = malloc(count * sizeof(_dedx_lookup_data *)); + if (temp->loaded_data == NULL) { + *err = DEDX_ERR_NO_MEMORY; + free(temp); + return NULL; + } for (i = 0; i < count; i++) { temp->loaded_data[i] = malloc(sizeof(_dedx_lookup_data)); if (temp->loaded_data[i] == NULL) { + int j; + for (j = 0; j < i; j++) + free(temp->loaded_data[j]); + free(temp->loaded_data); + free(temp); *err = DEDX_ERR_NO_MEMORY; return NULL; } diff --git a/libdedx/dedx_file.c b/libdedx/dedx_file.c index fd9e5c2..e5dfdd3 100644 --- a/libdedx/dedx_file.c +++ b/libdedx/dedx_file.c @@ -48,6 +48,7 @@ char *_dedx_get_program_file(int program) { } return path; } + char *_dedx_get_energy_file(int program) { char *path; switch (program) { diff --git a/libdedx/dedx_file_access.c b/libdedx/dedx_file_access.c index a467954..c4ce6db 100644 --- a/libdedx/dedx_file_access.c +++ b/libdedx/dedx_file_access.c @@ -20,7 +20,12 @@ /* Resolve the data directory once per process. * Prefers DEDX_DATA_PATH_LOCAL (build tree) if it contains the sentinel file, * otherwise falls back to DEDX_DATA_PATH (install prefix). - * Result is cached in a static buffer; never changes after the first call. */ + * Result is cached in a static buffer; never changes after the first call. + * + * NOTE: not thread-safe. The done/resolved statics are unprotected against + * concurrent first calls. The library as a whole is not thread-safe; this + * function should be fixed with call_once() as part of a broader thread-safety + * effort. See https://github.com/APTG/libdedx/issues (thread-safety issue). */ static const char *_dedx_get_data_path(void) { static char resolved[DEDX_PATH_SIZE]; static int done = 0; @@ -28,12 +33,11 @@ static const char *_dedx_get_data_path(void) { char probe[DEDX_PATH_SIZE]; if (!done) { - strcpy(probe, DEDX_DATA_PATH_LOCAL); - strcat(probe, "icru_pstarEng.dat"); + snprintf(probe, sizeof(probe), "%s%s", DEDX_DATA_PATH_LOCAL, "icru_pstarEng.dat"); if (stat(probe, &st) == 0) - strcpy(resolved, DEDX_DATA_PATH_LOCAL); + snprintf(resolved, sizeof(resolved), "%s", DEDX_DATA_PATH_LOCAL); else - strcpy(resolved, DEDX_DATA_PATH); + snprintf(resolved, sizeof(resolved), "%s", DEDX_DATA_PATH); done = 1; } return resolved; @@ -54,10 +58,14 @@ void _dedx_convert_to_binary(char *path, char *output, int *err) { fp = fopen(path, "r"); out = fopen(output, "wb+"); if (fp == NULL || out == NULL) { - if (out == NULL) + if (out == NULL) { *err = DEDX_ERR_WRITE_FAILED; - else + if (fp != NULL) + fclose(fp); + } else { *err = DEDX_ERR_NO_DATA_FILE; + fclose(out); + } return; } while (!feof(fp)) { @@ -96,17 +104,11 @@ void _dedx_read_binary_data(stopping_data *data, int prog, int ion, int target, *err = DEDX_OK; folder = _dedx_get_data_path(); - path[0] = '\0'; - strcat(path, folder); - strcat(path, _dedx_get_program_file(prog)); - strcat(path, ".bin"); + snprintf(path, sizeof(path), "%s%s.bin", folder, _dedx_get_program_file(prog)); fp = fopen(path, "rb"); if (fp == NULL) { - input_path[0] = '\0'; - strcat(input_path, folder); - strcat(input_path, _dedx_get_program_file(prog)); - strcat(input_path, ".dat"); + snprintf(input_path, sizeof(input_path), "%s%s.dat", folder, _dedx_get_program_file(prog)); _dedx_convert_to_binary(input_path, path, err); if (*err != DEDX_OK) { *err = DEDX_ERR_NO_BINARY_DATA; @@ -141,10 +143,14 @@ void _dedx_convert_energy_binary(char *path, char *output, int *err) { // TODO: Next line wont work after installation, unless user is root. out = fopen(output, "wb+"); if (fp == NULL || out == NULL) { - if (out == NULL) + if (out == NULL) { *err = DEDX_ERR_WRITE_FAILED; - else + if (fp != NULL) + fclose(fp); + } else { *err = DEDX_ERR_NO_ENERGY_FILE; + fclose(out); + } return; } @@ -170,17 +176,11 @@ void _dedx_read_energy_data(float *energy, int prog, int *err) { *err = DEDX_OK; folder = _dedx_get_data_path(); - path[0] = '\0'; - strcat(path, folder); - strcat(path, _dedx_get_energy_file(prog)); - strcat(path, ".bin"); + snprintf(path, sizeof(path), "%s%s.bin", folder, _dedx_get_energy_file(prog)); fp = fopen(path, "rb"); if (fp == NULL) { - input_path[0] = '\0'; - strcat(input_path, folder); - strcat(input_path, _dedx_get_energy_file(prog)); - strcat(input_path, ".dat"); + snprintf(input_path, sizeof(input_path), "%s%s.dat", folder, _dedx_get_energy_file(prog)); _dedx_convert_energy_binary(input_path, path, err); if (*err != DEDX_OK) { *err = DEDX_ERR_NO_BINARY_ENERGY; @@ -202,7 +202,6 @@ float _dedx_read_effective_charge(int id, int *err) { char line[100]; char **temp; unsigned int items; - char file[] = "effective_charge.dat"; char path[DEDX_PATH_SIZE]; FILE *fp; float charge = -1; @@ -214,8 +213,7 @@ float _dedx_read_effective_charge(int id, int *err) { folder = _dedx_get_data_path(); items = 0; temp = NULL; - strcpy(path, folder); - strcat(path, file); + snprintf(path, sizeof(path), "%s%s", folder, "effective_charge.dat"); fp = fopen(path, "r"); if (fp == NULL) { @@ -242,15 +240,13 @@ size_t _dedx_target_is_gas(int target, int *err) { const char *folder; size_t is_gas; char str[100]; - char file[] = "gas_states.dat"; char path[DEDX_PATH_SIZE]; FILE *fp; *err = DEDX_OK; is_gas = 0; folder = _dedx_get_data_path(); - strcpy(path, folder); - strcat(path, file); + snprintf(path, sizeof(path), "%s%s", folder, "gas_states.dat"); fp = fopen(path, "r"); if (fp == NULL) { *err = DEDX_ERR_NO_GAS_FILE; @@ -272,7 +268,6 @@ float _dedx_read_density(int id, int *err) { float density; char str[100]; char path[DEDX_PATH_SIZE]; - char file[] = "compos.txt"; unsigned int items; char **temp; FILE *fp; @@ -281,8 +276,7 @@ float _dedx_read_density(int id, int *err) { density = 1.0; items = 0; folder = _dedx_get_data_path(); - strcpy(path, folder); - strcat(path, file); + snprintf(path, sizeof(path), "%s%s", folder, "compos.txt"); fp = fopen(path, "r"); if (fp == NULL) { @@ -311,7 +305,6 @@ float _dedx_read_density(int id, int *err) { float _dedx_get_i_value(int target, int state, int *err) { const char *folder; float pot; - char file[] = "compos.txt"; char path[DEDX_PATH_SIZE]; char str[100]; char **temp; @@ -321,8 +314,7 @@ float _dedx_get_i_value(int target, int state, int *err) { pot = 0.0; items = 0; folder = _dedx_get_data_path(); - strcpy(path, folder); - strcat(path, file); + snprintf(path, sizeof(path), "%s%s", folder, "compos.txt"); fp = fopen(path, "r"); if (fp == NULL) { @@ -355,7 +347,6 @@ float _dedx_get_i_value(int target, int state, int *err) { void _dedx_get_composition(int target, float composition[][2], unsigned int *length, int *err) { const char *folder; - char file[] = "composition"; char path[DEDX_PATH_SIZE]; char str[100]; float f_temp; @@ -366,8 +357,7 @@ void _dedx_get_composition(int target, float composition[][2], unsigned int *len *err = DEDX_OK; *length = 0; folder = _dedx_get_data_path(); - strcpy(path, folder); - strcat(path, file); + snprintf(path, sizeof(path), "%s%s", folder, "composition"); fp = fopen(path, "r"); if (fp == NULL) { @@ -399,7 +389,6 @@ void _dedx_get_composition(int target, float composition[][2], unsigned int *len float *_dedx_get_atima_data(int target, int *err) { const char *folder; - char file[] = "atima_compos"; char path[DEDX_PATH_SIZE]; char str[100]; float *compos; @@ -409,8 +398,7 @@ float *_dedx_get_atima_data(int target, int *err) { *err = DEDX_OK; folder = _dedx_get_data_path(); - strcpy(path, folder); - strcat(path, file); + snprintf(path, sizeof(path), "%s%s", folder, "atima_compos"); fp = fopen(path, "r"); if (fp == NULL) { From 0770063b9017f09b5ce5237093ecd2664a20f314 Mon Sep 17 00:00:00 2001 From: Niels Bassler Date: Tue, 31 Mar 2026 14:35:42 +0200 Subject: [PATCH 5/8] fix bad examples, add them to tests --- CMakeLists.txt | 3 +-- examples/CMakeLists.txt | 7 +++++++ examples/dedx_csda.c | 46 ++++++++++++++++++++++++++++++++++------- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4587baa..3d90492 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,10 +55,9 @@ option(DEDX_BUILD_BINARY_TABLE "Build the binary data tables (requires a working if(DEDX_BUILD_BINARY_TABLE) add_subdirectory(buildbins) endif() +enable_testing() add_subdirectory(examples) add_subdirectory(libdedx) - -enable_testing() add_subdirectory(tests) # add uninstall target according to CMAKE FAQ: diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index fa81083..95cb24b 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -4,6 +4,7 @@ add_executable(dedx_list dedx_list.c) add_executable(dedx_bethe dedx_bethe.c) add_executable(dedx_use_wrappers dedx_use_wrappers.c) add_executable(dedx_get_sample_csv dedx_get_sample_csv.c) +add_executable(dedx_csda dedx_csda.c) target_link_libraries (dedx_example dedx) target_link_libraries (getdedx dedx) @@ -11,6 +12,7 @@ target_link_libraries (dedx_list dedx) target_link_libraries (dedx_bethe dedx) target_link_libraries (dedx_use_wrappers dedx) target_link_libraries (dedx_get_sample_csv dedx) +target_link_libraries (dedx_csda dedx) # Visual Studio does not need or want you to explicitly request linking the math library. # You must avoid adding it as a link library when building for Windows. @@ -22,6 +24,7 @@ IF (NOT WIN32) target_link_libraries (dedx_bethe m) target_link_libraries (dedx_use_wrappers m) target_link_libraries (dedx_get_sample_csv m) + target_link_libraries (dedx_csda m) ENDIF() # some of the examples need data/ folder in the same location as generated executable @@ -29,4 +32,8 @@ add_custom_command(TARGET dedx_example PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/libdedx/data $/data) +foreach(example dedx_example dedx_bethe dedx_list dedx_use_wrappers dedx_get_sample_csv dedx_csda) + add_test(NAME ${example} COMMAND ${example}) +endforeach() + install (TARGETS getdedx DESTINATION bin) \ No newline at end of file diff --git a/examples/dedx_csda.c b/examples/dedx_csda.c index 42e6dd2..eb37b86 100644 --- a/examples/dedx_csda.c +++ b/examples/dedx_csda.c @@ -1,14 +1,46 @@ +#include #include #include +#include int main() { int err = 0; - int program = 2; // PSTAR - int ion = 1; // Proton - int target = 276; // Water - double A = 1; // Nucleid number of ion - float energy = 100; // Energy per nucleos in MeV - float csda = dedx_get_csda(program, ion, A, target, energy, &err); - printf("Calculated csda %6.3Ecm^2/g\n", csda); + float energy = 100.0f; /* MeV/u */ + double csda; + dedx_workspace *ws; + dedx_config *cfg; + + ws = dedx_allocate_workspace(1, &err); + if (err != DEDX_OK) { + fprintf(stderr, "failed to allocate workspace: err=%d\n", err); + return 1; + } + + cfg = (dedx_config *) calloc(1, sizeof(dedx_config)); + cfg->program = DEDX_PSTAR; + cfg->ion = DEDX_PROTON; + cfg->ion_a = 1; /* nucleon number — required by dedx_get_csda */ + cfg->target = DEDX_WATER; + + dedx_load_config(ws, cfg, &err); + if (err != DEDX_OK) { + fprintf(stderr, "failed to load config: err=%d\n", err); + dedx_free_config(cfg, &err); + dedx_free_workspace(ws, &err); + return 1; + } + + csda = dedx_get_csda(ws, cfg, energy, &err); + if (err != DEDX_OK) { + fprintf(stderr, "dedx_get_csda failed: err=%d\n", err); + dedx_free_config(cfg, &err); + dedx_free_workspace(ws, &err); + return 1; + } + + printf("CSDA range at %g MeV/u: %6.3E cm^2/g\n", energy, csda); + + dedx_free_config(cfg, &err); + dedx_free_workspace(ws, &err); return 0; } From 0f4ff2991272422b9aa05495231fd69807e3d8a5 Mon Sep 17 00:00:00 2001 From: Niels Bassler Date: Tue, 31 Mar 2026 14:40:07 +0200 Subject: [PATCH 6/8] clang format --- Windows/dedx.h | 1 + libdedx/dedx_atima.c | 4 ++++ libdedx/dedx_bethe.c | 3 +++ libdedx/dedx_bethe.h | 1 + libdedx/dedx_calculate_charge.c | 2 ++ libdedx/tools/dedx_math.c | 1 + 6 files changed, 12 insertions(+) diff --git a/Windows/dedx.h b/Windows/dedx.h index 0afdc44..a70043e 100644 --- a/Windows/dedx.h +++ b/Windows/dedx.h @@ -1,5 +1,6 @@ #ifndef DEDX_H_INCLUDED #define DEDX_H_INCLUDED + // #include "dedx_workspace.h" /* available data tables */ enum { diff --git a/libdedx/dedx_atima.c b/libdedx/dedx_atima.c index 6e408d5..47693c5 100644 --- a/libdedx/dedx_atima.c +++ b/libdedx/dedx_atima.c @@ -28,6 +28,7 @@ float _dedx_calculate_atima_energy(float energy, dedx_config *config) { } return dedx; } + float _dedx_bethek(float energy, int PZ, int PA, int TZ, float TA, float pot, float rho) { float e = energy / PA; float e1 = energy / (1000 * PA); @@ -53,9 +54,11 @@ float _dedx_bethek(float energy, int PZ, int PA, int TZ, float TA, float pot, fl f6 = 2 * log(gamma) - bsq; return 0; } + float _dedx_bf4(int TZ, float eta, float zpeff) { return 0; } + float _dedx_dedxela(float energy, int PZ, int PA, int TZ, float TA) { float sn, a; float epsil = 32.53 * TA * energy / (PZ * TZ * (PA + TA) * (pow(PZ, 0.23) + pow(TZ, .23))); @@ -69,6 +72,7 @@ float _dedx_dedxela(float energy, int PZ, int PA, int TZ, float TA) { sn = sn * .1 * DEDX_N_AVO / TA; return sn; } + float _dedx_sezi(float energy, int PZ, int PA, int TZ, float TA) { float dedx = 0; ; diff --git a/libdedx/dedx_bethe.c b/libdedx/dedx_bethe.c index 3dbdc43..5d71573 100644 --- a/libdedx/dedx_bethe.c +++ b/libdedx/dedx_bethe.c @@ -65,6 +65,7 @@ float _dedx_calculate_bethe_energy( return dedx; } + float _dedx_mm(float PT, _dedx_bethe_struct bet, _dedx_gold_struct gold, int *err) { double T = PT; float dedx; @@ -133,6 +134,7 @@ float _dedx_mm(float PT, _dedx_bethe_struct bet, _dedx_gold_struct gold, int *er * (log((1.022E+06 / bet.potentiale) * beta_gamma) - beta_2 - delta / 2.0); return dedx; } + void _dedx_gold_section(_dedx_bethe_struct bet, _dedx_gold_struct *gold, int *err) { double e_min = gold->e_min; @@ -231,6 +233,7 @@ void _dedx_gold_section(_dedx_bethe_struct bet, _dedx_gold_struct *gold, int *er } } } + float _dedx_m(float PT, _dedx_bethe_struct bet, int *err) { double T = PT; double mass = 940 * bet.PA0; diff --git a/libdedx/dedx_bethe.h b/libdedx/dedx_bethe.h index 72d8a4d..bf8b03c 100644 --- a/libdedx/dedx_bethe.h +++ b/libdedx/dedx_bethe.h @@ -3,6 +3,7 @@ #include "dedx.h" #include "dedx_file_access.h" + // #include "dedx_gold_struct.h" // #include "dedx_bethe_struct.h" diff --git a/libdedx/dedx_calculate_charge.c b/libdedx/dedx_calculate_charge.c index 9b070e1..95a658f 100644 --- a/libdedx/dedx_calculate_charge.c +++ b/libdedx/dedx_calculate_charge.c @@ -1,6 +1,7 @@ #include "dedx_calculate_charge.h" #include "dedx_periodic_table.h" + float _dedx_get_avg_charge(float composition[][2], int length) { int i = 0; int err = 0; @@ -15,6 +16,7 @@ float _dedx_get_avg_charge(float composition[][2], int length) { } return charge; } + float _dedx_get_weight_charge(float composition[][2], int length) { int err = 0; float charge = 0.0; diff --git a/libdedx/tools/dedx_math.c b/libdedx/tools/dedx_math.c index 906f838..75a1117 100644 --- a/libdedx/tools/dedx_math.c +++ b/libdedx/tools/dedx_math.c @@ -1,4 +1,5 @@ #include "dedx_math.h" + float _dedx_max(float a, float b) { if (a > b) return a; From 660bebccb4239b1e829a558f0a0ef53c1390f583 Mon Sep 17 00:00:00 2001 From: Niels Bassler Date: Tue, 31 Mar 2026 15:01:01 +0200 Subject: [PATCH 7/8] Add LCOV exclusion comments and enhance tests for nitrogen stopping power --- libdedx/dedx.c | 4 ++-- libdedx/dedx_file_access.c | 10 +++++----- tests/test_pstar.c | 7 +++++++ 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/libdedx/dedx.c b/libdedx/dedx.c index 58a6e3e..aec8a7f 100644 --- a/libdedx/dedx.c +++ b/libdedx/dedx.c @@ -70,7 +70,7 @@ dedx_workspace *dedx_allocate_workspace(unsigned int count, int *err) { } for (i = 0; i < count; i++) { temp->loaded_data[i] = malloc(sizeof(_dedx_lookup_data)); - if (temp->loaded_data[i] == NULL) { + if (temp->loaded_data[i] == NULL) { /* LCOV_EXCL_START */ int j; for (j = 0; j < i; j++) free(temp->loaded_data[j]); @@ -78,7 +78,7 @@ dedx_workspace *dedx_allocate_workspace(unsigned int count, int *err) { free(temp); *err = DEDX_ERR_NO_MEMORY; return NULL; - } + } /* LCOV_EXCL_STOP */ } temp->datasets = count; temp->active_datasets = 0; diff --git a/libdedx/dedx_file_access.c b/libdedx/dedx_file_access.c index c4ce6db..022aef3 100644 --- a/libdedx/dedx_file_access.c +++ b/libdedx/dedx_file_access.c @@ -37,7 +37,7 @@ static const char *_dedx_get_data_path(void) { if (stat(probe, &st) == 0) snprintf(resolved, sizeof(resolved), "%s", DEDX_DATA_PATH_LOCAL); else - snprintf(resolved, sizeof(resolved), "%s", DEDX_DATA_PATH); + snprintf(resolved, sizeof(resolved), "%s", DEDX_DATA_PATH); /* LCOV_EXCL_LINE */ done = 1; } return resolved; @@ -57,7 +57,7 @@ void _dedx_convert_to_binary(char *path, char *output, int *err) { *err = DEDX_OK; fp = fopen(path, "r"); out = fopen(output, "wb+"); - if (fp == NULL || out == NULL) { + if (fp == NULL || out == NULL) { /* LCOV_EXCL_START */ if (out == NULL) { *err = DEDX_ERR_WRITE_FAILED; if (fp != NULL) @@ -67,7 +67,7 @@ void _dedx_convert_to_binary(char *path, char *output, int *err) { fclose(out); } return; - } + } /* LCOV_EXCL_STOP */ while (!feof(fp)) { if (fgets(line, 100, fp) == NULL) { } @@ -142,7 +142,7 @@ void _dedx_convert_energy_binary(char *path, char *output, int *err) { fp = fopen(path, "r"); // TODO: Next line wont work after installation, unless user is root. out = fopen(output, "wb+"); - if (fp == NULL || out == NULL) { + if (fp == NULL || out == NULL) { /* LCOV_EXCL_START */ if (out == NULL) { *err = DEDX_ERR_WRITE_FAILED; if (fp != NULL) @@ -152,7 +152,7 @@ void _dedx_convert_energy_binary(char *path, char *output, int *err) { fclose(out); } return; - } + } /* LCOV_EXCL_STOP */ if (fgets(line, 100, fp) == NULL) { } diff --git a/tests/test_pstar.c b/tests/test_pstar.c index 84843ac..916548c 100644 --- a/tests/test_pstar.c +++ b/tests/test_pstar.c @@ -26,5 +26,12 @@ int main(void) { failures += check_stp(DEDX_PSTAR, DEDX_PROTON, DEDX_ALANINE, 78.0f, 8.617e0f); failures += check_stp(DEDX_PSTAR, DEDX_PROTON, DEDX_ALANINE, 1000.0f, 2.148e0f); + // Proton stopping power in nitrogen (gas target — exercises _dedx_target_is_gas) + // Reference values from NIST PSTAR database + failures += check_stp(DEDX_PSTAR, DEDX_PROTON, DEDX_NITROGEN, 0.07f, 7.624e2f); + failures += check_stp(DEDX_PSTAR, DEDX_PROTON, DEDX_NITROGEN, 1.0f, 2.260e2f); + failures += check_stp(DEDX_PSTAR, DEDX_PROTON, DEDX_NITROGEN, 10.0f, 4.043e1f); + failures += check_stp(DEDX_PSTAR, DEDX_PROTON, DEDX_NITROGEN, 100.0f, 6.485e0f); + return failures; } From 9b4378384c45c5cf8358eb08a8a86252f9491afe Mon Sep 17 00:00:00 2001 From: Niels Bassler Date: Tue, 31 Mar 2026 15:14:21 +0200 Subject: [PATCH 8/8] Refactor error handling and add LCOV exclusion comments in dedx_mstar, dedx_periodic_table, and dedx_validate; add test cases for error codes --- libdedx/dedx_mstar.c | 4 +- libdedx/dedx_periodic_table.c | 12 +++--- libdedx/dedx_validate.c | 4 +- tests/test_error_codes.c | 71 +++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 10 deletions(-) create mode 100644 tests/test_error_codes.c diff --git a/libdedx/dedx_mstar.c b/libdedx/dedx_mstar.c index a129bb7..9bbf2dc 100644 --- a/libdedx/dedx_mstar.c +++ b/libdedx/dedx_mstar.c @@ -16,7 +16,7 @@ */ #include "dedx_mstar.h" -void _evaluate_compound_state_mstar(dedx_config *config, int *err) { +void _evaluate_compound_state_mstar(dedx_config *config, int *err) { /* LCOV_EXCL_START */ if (config->compound_state == DEDX_GAS) { if (config->mstar_mode == 'a') config->mstar_mode = 'g'; @@ -29,7 +29,7 @@ void _evaluate_compound_state_mstar(dedx_config *config, int *err) { config->mstar_mode = 'd'; } *err = DEDX_OK; -} +} /* LCOV_EXCL_STOP */ void _dedx_convert_energy_to_mstar( stopping_data *in, stopping_data *out, char state, dedx_config *config, float *energy) { diff --git a/libdedx/dedx_periodic_table.c b/libdedx/dedx_periodic_table.c index 2670c8b..ef42600 100644 --- a/libdedx/dedx_periodic_table.c +++ b/libdedx/dedx_periodic_table.c @@ -4,22 +4,22 @@ float _dedx_get_atom_charge(int id, int *err) { if (id < 113) { return id; } - *err = DEDX_ERR_NOT_AN_ELEMENT; - return -1; + *err = DEDX_ERR_NOT_AN_ELEMENT; /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ } float _dedx_get_atom_mass(int id, int *err) { *err = DEDX_OK; if (id < 113) return dedx_amu[id - 1]; - *err = DEDX_ERR_NOT_AN_ELEMENT; - return -1; + *err = DEDX_ERR_NOT_AN_ELEMENT; /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ } int _dedx_get_nucleon(int id, int *err) { *err = DEDX_OK; if (id < 113) return dedx_nucl[id - 1]; - *err = DEDX_ERR_NOT_AN_ELEMENT; - return -1; + *err = DEDX_ERR_NOT_AN_ELEMENT; /* LCOV_EXCL_LINE */ + return -1; /* LCOV_EXCL_LINE */ } diff --git a/libdedx/dedx_validate.c b/libdedx/dedx_validate.c index 3888ab3..ab7a7a1 100644 --- a/libdedx/dedx_validate.c +++ b/libdedx/dedx_validate.c @@ -66,10 +66,10 @@ int _dedx_evaluate_compound(dedx_config *config, int *err) { _dedx_get_composition(config->target, composition, &compos_len, err); if (*err != 0) return -1; - if (compos_len == 0) { + if (compos_len == 0) { /* LCOV_EXCL_START */ *err = DEDX_ERR_TARGET_NOT_FOUND; return -1; - } + } /* LCOV_EXCL_STOP */ config->elements_id = (int *) malloc(sizeof(int) * compos_len); config->elements_mass_fraction = (float *) malloc(sizeof(float) * compos_len); for (i = 0; i < compos_len; i++) { diff --git a/tests/test_error_codes.c b/tests/test_error_codes.c new file mode 100644 index 0000000..d9d8789 --- /dev/null +++ b/tests/test_error_codes.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include + +static int check_err(int got, int expected, const char *label) { + if (got != expected) { + fprintf(stderr, "FAIL %s: got err=%d, expected %d\n", label, got, expected); + return 1; + } + return 0; +} + +int main(void) { + int failures = 0; + int err = 0; + dedx_workspace *ws; + dedx_config *cfg; + + /* dedx_get_csda requires ion_a > 0 */ + ws = dedx_allocate_workspace(1, &err); + cfg = calloc(1, sizeof(dedx_config)); + cfg->program = DEDX_PSTAR; + cfg->ion = DEDX_PROTON; + cfg->target = DEDX_WATER; + /* ion_a intentionally left at 0 */ + err = 0; + dedx_get_csda(ws, cfg, 1.0f, &err); + failures += check_err(err, DEDX_ERR_ION_A_REQUIRED, "csda without ion_a"); + dedx_free_config(cfg, &err); + dedx_free_workspace(ws, &err); + + /* dedx_get_inverse_csda requires ion_a > 0 */ + ws = dedx_allocate_workspace(1, &err); + cfg = calloc(1, sizeof(dedx_config)); + cfg->program = DEDX_PSTAR; + cfg->ion = DEDX_PROTON; + cfg->target = DEDX_WATER; + err = 0; + dedx_get_inverse_csda(ws, cfg, 10.0f, &err); + failures += check_err(err, DEDX_ERR_ION_A_REQUIRED, "inverse_csda without ion_a"); + dedx_free_config(cfg, &err); + dedx_free_workspace(ws, &err); + + /* dedx_get_inverse_stp requires ion_a > 0 */ + ws = dedx_allocate_workspace(1, &err); + cfg = calloc(1, sizeof(dedx_config)); + cfg->program = DEDX_PSTAR; + cfg->ion = DEDX_PROTON; + cfg->target = DEDX_WATER; + err = 0; + dedx_get_inverse_stp(ws, cfg, 100.0f, -1, &err); + failures += check_err(err, DEDX_ERR_ION_A_REQUIRED, "inverse_stp without ion_a"); + dedx_free_config(cfg, &err); + dedx_free_workspace(ws, &err); + + /* BETHE with target=0 and no rho: density is required */ + ws = dedx_allocate_workspace(1, &err); + cfg = calloc(1, sizeof(dedx_config)); + cfg->program = DEDX_DEFAULT; + cfg->ion = DEDX_PROTON; + cfg->target = 0; + /* rho intentionally left at 0 */ + err = 0; + dedx_load_config(ws, cfg, &err); + failures += check_err(err, DEDX_ERR_RHO_REQUIRED, "BETHE custom target without rho"); + dedx_free_config(cfg, &err); + dedx_free_workspace(ws, &err); + + return failures; +}