Add new function that handles converting the relative path with '../' with one that has no '../'.
Use this to build the object paths by adding the full relative directory path for the build files.
Note that this could be a problem with possible directory structure conflicts in some situations.
Utilize a new cache `cache_relative` for the processing of the relative path.
Add additional debug reporting to improve the error reporting details with the programs, like `ar`, fail.
Add note how future FLL versions (0.9 and later) should have something like `fl_path_canonical()`.
I need to also follow this commit up with an investigation to see if any of these `../` can get outside the project root.
There is a need for a project root parameter for situations where different paths are specified, such as specifying `--sources`.
Alternatively, I might have to restrict all `../` to the sources directory and then move all of my `tests/` directory files within the `sources/` directoreis for all projects.
This also gives me reason to consider adding IKI support to enhance the build settings.
I am on the fence on actually doing this or not.
for (j = 0; j < sources[i]->used; ++j) {
+ if (!sources[i]->array[j].used) continue;
+
fake_string_dynamic_reset(&main->cache_1);
fake_string_dynamic_reset(&main->cache_2);
+ fake_string_dynamic_reset(&main->cache_argument);
+
+ fake_build_path_source_string(data, data_build, &data_build->setting.path_sources_library, &main->cache_2);
+ if (F_status_is_error(main->setting.state.status)) return 0;
- fake_build_get_file_name_without_extension(data, sources[i]->array[j], &main->cache_1);
+ main->setting.state.status = f_file_name_directory(sources[i]->array[j], &main->cache_argument);
if (F_status_is_error(main->setting.state.status)) {
fake_print_error(&main->program.error, F_status_debug_source_d);
return 0;
}
- main->setting.state.status = f_file_name_directory(sources[i]->array[j], &main->cache_2);
+ fake_path_relative_within(data, main->cache_2, main->cache_argument, &main->cache_1);
- if (F_status_is_error(main->setting.state.status)) {
- fake_print_error(&main->program.error, F_status_debug_source_d);
+ if (main->setting.state.status == F_relative_not) {
+ fake_string_dynamic_reset(&main->cache_1);
+ fake_string_dynamic_reset(&main->cache_2);
+
+ fake_build_get_file_name_without_extension(data, sources[i]->array[j], &main->cache_1);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+
+ return 0;
+ }
+
+ main->setting.state.status = f_file_name_directory(sources[i]->array[j], &main->cache_2);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+ return 0;
+ }
+ }
+ else if (F_status_is_error(main->setting.state.status)) {
return 0;
+ } else {
+ fake_string_dynamic_reset(&main->cache_2);
+
+ main->setting.state.status = f_file_name_directory(main->cache_1, &main->cache_2);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+
+ return 0;
+ }
+
+ main->setting.state.status = f_string_dynamic_append_assure(f_path_separator_s, &main->cache_1);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+
+ return 0;
+ }
+
+ fake_build_get_file_name_without_extension(data, sources[i]->array[j], &main->cache_1);
+ if (F_status_is_error(main->setting.state.status)) return 0;
}
fake_string_dynamic_reset(&main->cache_argument);
fake_string_dynamic_reset(&main->cache_argument);
fake_string_dynamics_reset_to(&main->cache_arguments, minimum);
- fake_build_path_source_string(data, data_build, &data_build->setting.path_sources_library, &main->cache_1);
+ fake_build_path_source_string(data, data_build, &data_build->setting.path_sources_library, &main->cache_2);
if (F_status_is_error(main->setting.state.status)) return 0;
- main->setting.state.status = f_string_dynamic_append_nulless(sources[i]->array[j], &main->cache_1);
+ main->setting.state.status = f_file_name_directory(sources[i]->array[j], &main->cache_argument);
if (F_status_is_error(main->setting.state.status)) {
fake_print_error(&main->program.error, F_status_debug_source_d);
return 0;
}
- fake_build_get_file_name_without_extension(data, sources[i]->array[j], &main->cache_2);
+ fake_path_relative_within(data, main->cache_2, main->cache_argument, &main->cache_1);
- if (F_status_is_error(main->setting.state.status)) {
- fake_print_error(&main->program.error, F_status_debug_source_d);
+ if (main->setting.state.status == F_relative_not) {
+ fake_string_dynamic_reset(&main->cache_1);
+
+ main->setting.state.status = f_string_dynamic_append_nulless(main->cache_2, &main->cache_1);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+
+ return 0;
+ }
+ main->setting.state.status = f_string_dynamic_append_nulless(sources[i]->array[j], &main->cache_1);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+
+ return 0;
+ }
+ }
+ else if (F_status_is_error(main->setting.state.status)) {
return 0;
+ } else {
+ fake_string_dynamic_reset(&main->cache_argument);
+
+ main->setting.state.status = f_file_name_directory(main->cache_1, &main->cache_argument);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+
+ return 0;
+ }
+
+ main->setting.state.status = f_string_dynamic_append_assure(f_path_separator_s, &main->cache_1);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+
+ return 0;
+ }
+
+ main->setting.state.status = f_file_name_base(sources[i]->array[j], &main->cache_1);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+
+ return 0;
+ }
}
- main->setting.state.status = f_file_name_directory(sources[i]->array[j], &main->cache_argument);
+ fake_string_dynamic_reset(&main->cache_2);
+
+ fake_build_get_file_name_without_extension(data, main->cache_1, &main->cache_2);
if (F_status_is_error(main->setting.state.status)) {
fake_print_error(&main->program.error, F_status_debug_source_d);
}
if (main->cache_argument.used) {
+ main->setting.state.status = f_string_dynamic_append_assure(f_path_separator_s, &main->cache_argument);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+
+ return 0;
+ }
+
main->setting.state.status = f_string_dynamic_prepend(data->path_build_objects_static, &main->cache_argument);
if (F_status_is_error(main->setting.state.status)) {
return 0;
}
+ main->setting.state.status = f_string_dynamic_terminate_after(&main->cache_argument);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+
+ return 0;
+ }
+
main->setting.state.status = f_directory_exists(main->cache_argument);
if (main->setting.state.status == F_false) {
extern "C" {
#endif
+#ifndef _di_fake_path_relative_within_
+ void fake_path_relative_within(fake_data_t * const data, const f_string_static_t within, const f_string_static_t path, f_string_dynamic_t * const relative) {
+
+ if (!data || !data->main || !relative) return;
+
+ fake_main_t * const main = data->main;
+
+ f_number_unsigned_t at = 0;
+
+ relative->used = 0;
+
+ while (at < path.used && !path.string[at]) ++at;
+
+ if (path.string[at] == f_path_separator_s.string[0]) {
+ main->setting.state.status = F_status_set_error(F_absolute);
+
+ return;
+ }
+
+ if (path.string[at] != f_path_separator_current_s.string[0]) {
+ main->setting.state.status = F_relative_not;
+
+ return;
+ }
+
+ {
+ f_number_unsigned_t original = at++;
+
+ while (at < path.used && !path.string[at]) ++at;
+
+ if (path.string[at] != f_path_separator_current_s.string[0]) {
+ main->setting.state.status = F_relative_not;
+
+ return;
+ }
+
+ ++at;
+
+ while (at < path.used && !path.string[at]) ++at;
+
+ if (path.string[at] != f_path_separator_s.string[0]) {
+ main->setting.state.status = F_relative_not;
+
+ return;
+ }
+
+ at = original;
+ }
+
+ fake_string_dynamic_reset(&main->cache_relative);
+ fake_string_dynamic_reset(relative);
+
+ main->setting.state.status = f_string_dynamic_append_nulless(within, &main->cache_relative);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+
+ return;
+ }
+
+ main->setting.state.status = f_string_dynamic_append_assure(f_path_separator_s, &main->cache_relative);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+
+ return;
+ }
+
+ uint8_t previous_1 = f_path_separator_s.string[0];
+ uint8_t previous_2 = 0;
+
+ f_number_unsigned_t size_chunk = 0;
+ f_number_unsigned_t position = 0;
+
+ main->setting.state.status = f_string_dynamic_append(main->cache_relative, relative);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+
+ return;
+ }
+
+ for (at = 0; at < path.used; ++at) {
+
+ if (!size_chunk && path.string[at] == f_path_separator_current_s.string[0]) {
+ if (!previous_1 || previous_1 == f_path_separator_s.string[0]) {
+ previous_1 = f_path_separator_current_s.string[0];
+ previous_2 = 0;
+
+ continue;
+ }
+
+ if (previous_1 == f_path_separator_current_s.string[0]) {
+ if (previous_2) {
+ previous_1 = 0;
+ previous_2 = 0;
+ size_chunk = 3;
+ position = at - 2;
+ }
+ else {
+ previous_2 = f_path_separator_current_s.string[0];
+ }
+ }
+ }
+ else if (path.string[at] == f_path_separator_s.string[0]) {
+ if (previous_1 == f_path_separator_s.string[0]) {
+ size_chunk = 0;
+ position = 0;
+
+ continue;
+ }
+
+ if (previous_1 == f_path_separator_current_s.string[0]) {
+ if (previous_2 == f_path_separator_current_s.string[0]) {
+ if (relative->used > 1) {
+ for (--relative->used; relative->used > 0; --relative->used) {
+ if (relative->string[relative->used - 1] == f_path_separator_s.string[0]) break;
+ } // for
+ }
+ }
+ }
+ else {
+ if (++size_chunk) {
+ main->setting.state.status = f_string_append_nulless(path.string + position, size_chunk, relative);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+
+ return;
+ }
+ }
+ }
+
+ previous_1 = f_path_separator_s.string[0];
+ previous_2 = 0;
+ size_chunk = 0;
+ position = 0;
+ }
+ else {
+ if (!size_chunk) {
+ position = at;
+
+ if (previous_2) {
+ position -= 2;
+ size_chunk = 2;
+ }
+ else if (previous_1 && previous_1 != f_path_separator_s.string[0]) {
+ --position;
+ size_chunk = 1;
+ }
+ }
+
+ if (previous_1) {
+ previous_1 = 0;
+ previous_2 = 0;
+ }
+
+ ++size_chunk;
+ }
+ } // for
+
+ if (previous_2 == f_path_separator_current_s.string[0]) {
+ if (relative->used > 1) {
+ for (--relative->used; relative->used > 0; --relative->used) {
+ if (relative->string[relative->used - 1] == f_path_separator_s.string[0]) break;
+ } // for
+ }
+ }
+ else if (!(previous_1 == f_path_separator_current_s.string[0] || previous_1 == f_path_separator_s.string[0])) {
+ if (size_chunk) {
+ main->setting.state.status = f_string_append_nulless(path.string + position, size_chunk, relative);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ fake_print_error(&main->program.error, F_status_debug_source_d);
+
+ return;
+ }
+ }
+ }
+
+ // Assure there is no trailing forward slash, unless it is the first slash.
+ if (relative->used > 1 && relative->string[relative->used - 1] == f_path_separator_s.string[0]) {
+ --relative->used;
+ }
+
+ main->setting.state.status = F_okay;
+ }
+#endif // _di_fake_path_relative_within_
+
#ifndef _di_fake_setting_load_
void fake_setting_load(const f_console_arguments_t arguments, fake_main_t * const main) {
extern "C" {
#endif
+/**
+ * For paths that are prefixed with '../', convert them into a path within a given directory.
+ *
+ * Relative paths are assumed to be relative to the "within" canonical path, such as: 'sources/c' rather than either '../../sources/c' or '/tmp/project/sources/c' where '/tmp/project/' is the "within" canonical path.
+ *
+ * If the '../' path traverses outside of the "within" path, then this is considered an error.
+ *
+ * @todo Some of this behavior needs to be into fl_path project as fl_path_canonical_relative() for 0.9 and greater (cannot be done in 0.8 due to API freeze).
+ *
+ * @param data
+ * The program data.
+ *
+ * This alters data.main.cache_relative.
+ *
+ * This alters data.main.setting.state.status:
+ * F_okay on success.
+ * F_relative_not on success and the path is not prefixed with '../'.
+ *
+ * F_absolute (with error bit) If path is an absolute path.
+ * F_too_small (with error bit) If the resulting relative path would end up outside the "within" directory path.
+ *
+ * Errors (with error bit) from: fl_path_canonical().
+ * @param within
+ * This must already be a canonical path.
+ * The directory in which non-absolute paths are relative to.
+ * This should not be "/" because then the resulting relative path would just be a normal full path (not relative).
+ * This need not be NULL terminated.
+ * @param path
+ * The source path to determine what the relative canonical file path is.
+ * NULLs within the path are not copied to the relative canonical file path.
+ * This need not be NULL terminated.
+ * @param relative
+ * The (allocated) relative canonical file path.
+ * This will be NULL terminated at relative.used + 1.
+ */
+#ifndef _di_fake_path_relative_within_
+ extern void fake_path_relative_within(fake_data_t * const data, const f_string_static_t within, const f_string_static_t path, f_string_dynamic_t * const relative);
+#endif // _di_fake_path_relative_within_
+
/**
* Perform the standard program setting load process.
*
f_memory_array_resize(0, sizeof(f_char_t), (void **) &main->cache_1.string, &main->cache_1.used, &main->cache_1.size);
f_memory_array_resize(0, sizeof(f_char_t), (void **) &main->cache_2.string, &main->cache_2.used, &main->cache_2.size);
f_memory_array_resize(0, sizeof(f_char_t), (void **) &main->cache_argument.string, &main->cache_argument.used, &main->cache_argument.size);
+ f_memory_array_resize(0, sizeof(f_char_t), (void **) &main->cache_relative.string, &main->cache_relative.used, &main->cache_relative.size);
f_memory_arrays_resize(0, sizeof(f_string_dynamic_t), (void **) &main->cache_arguments.array, &main->cache_arguments.used, &main->cache_arguments.size, &f_string_dynamics_delete_callback);
* - cache_2: A string cache.
* - cache_argument: A string cache for some argument.
* - cache_argument: A string cache for some path.
+ * - cache_relative: A string cache for building relative canonical paths.
* - cache_arguments: An array of strings cache for arguments.
* - cache_map: A string map cache.
* - cache_iki: IKI data cache.
f_string_dynamic_t cache_1;
f_string_dynamic_t cache_2;
f_string_dynamic_t cache_argument;
+ f_string_dynamic_t cache_relative;
f_string_dynamics_t cache_arguments;
f_string_map_t cache_map;
f_iki_data_t cache_iki;
.cache_1 = f_string_dynamic_t_initialize, \
.cache_2 = f_string_dynamic_t_initialize, \
.cache_argument = f_string_dynamic_t_initialize, \
+ .cache_relative = f_string_dynamic_t_initialize, \
.cache_arguments = f_string_dynamics_t_initialize, \
.cache_map = f_string_map_t_initialize, \
.cache_iki = f_iki_data_t_initialize, \
}
}
- fake_make_operate_process_return(data_make, return_code);
+ fake_make_operate_process_return(data_make, return_code, F_status_debug_source_d);
return;
}
#endif // _di_fake_make_operate_process_execute_
#ifndef _di_fake_make_operate_process_return_
- void fake_make_operate_process_return(fake_make_data_t * const data_make, const int return_code) {
+ void fake_make_operate_process_return(fake_make_data_t * const data_make, const int return_code, const f_string_t debug) {
if (!data_make || !data_make->main) return;
return;
}
- fake_make_print_error_program_failed(&main->program.error, return_code);
+ fake_make_print_error_program_failed(&main->program.error, return_code, debug);
main->setting.state.status = (data_make->setting_make.fail == fake_make_operation_fail_exit_e) ? F_status_set_error(F_failure) : F_failure;
* Errors (with error bit) from: f_string_dynamic_append().
* @param return_code
* The return code to process.
+ * @param debug
+ * (optional) The debug details, such as file, line number, and function.
+ *
+ * Set to NULL to disable.
*
* @see f_conversion_number_signed_to_string()
* @see f_string_append()
* @see f_string_dynamic_append()
*/
#ifndef _di_fake_make_operate_process_return_
- extern void fake_make_operate_process_return(fake_make_data_t * const data_make, const int return_code);
+ extern void fake_make_operate_process_return(fake_make_data_t * const data_make, const int return_code, const f_string_t debug);
#endif // _di_fake_make_operate_process_return_
/**
fake_build_operate(data_make->data, main->cache_arguments.used ? &main->cache_arguments : 0, F_false, data_make->setting_make.stage);
if (F_status_set_fine(main->setting.state.status) == F_interrupt) return;
- fake_make_operate_process_return(data_make, F_status_is_error(main->setting.state.status) ? 1 : 0);
+ fake_make_operate_process_return(data_make, F_status_is_error(main->setting.state.status) ? 1 : 0, F_status_debug_source_d);
}
#endif // _di_fake_make_operate_process_type_build_
fake_clean_operate(data_make->data);
if (F_status_set_fine(main->setting.state.status) == F_interrupt) return;
- fake_make_operate_process_return(data_make, F_status_is_error(main->setting.state.status) ? 1 : 0);
+ fake_make_operate_process_return(data_make, F_status_is_error(main->setting.state.status) ? 1 : 0, F_status_debug_source_d);
}
#endif // _di_fake_make_operate_process_type_clean_
const int result = fake_execute(data_make->data, data_make->environment, data_make->setting_build.build_compiler);
if (main->setting.state.status == F_child) return result;
- fake_make_operate_process_return(data_make, result);
+ fake_make_operate_process_return(data_make, result, F_status_debug_source_d);
return result;
}
const int result = fake_execute(data_make->data, data_make->environment, data_make->setting_build.build_indexer);
if (main->setting.state.status == F_child) return result;
- fake_make_operate_process_return(data_make, result);
+ fake_make_operate_process_return(data_make, result, F_status_debug_source_d);
return result;
}
fake_skeleton_operate(data_make->data);
if (F_status_set_fine(main->setting.state.status) == F_interrupt) return;
- fake_make_operate_process_return(data_make, F_status_is_error(main->setting.state.status) ? 1 : 0);
+ fake_make_operate_process_return(data_make, F_status_is_error(main->setting.state.status) ? 1 : 0, F_status_debug_source_d);
}
#endif // _di_fake_make_operate_process_type_skeleton_
#endif // _di_fake_make_print_error_pop_last_path_
#ifndef _di_fake_make_print_error_program_failed_
- f_status_t fake_make_print_error_program_failed(fl_print_t * const print, const int return_code) {
+ f_status_t fake_make_print_error_program_failed(fl_print_t * const print, const int return_code, const f_string_t debug) {
if (!print) return F_status_set_error(F_output_not);
if (print->verbosity < f_console_verbosity_error_e) return F_output_not;
f_file_stream_lock(print->to);
fl_print_format("%[%QFailed with return code %]", print->to, print->context, print->prefix, print->context);
- fl_print_format("%[%i%]", print->to, print->notable, return_code, print->notable);
- fl_print_format("%[.%]%r", print->to, print->context, print->context, f_string_eol_s);
+ fl_print_format("%[%i%]%[", print->to, print->notable, return_code, print->notable, print->context, print->context);
+
+ if (debug && *debug) {
+ fl_print_format(macro_fll_error_s(019_debug_open), print->to, print->context);
+ fl_print_format(f_string_format_S_single_s.string, print->to, print->notable, debug, print->notable);
+ fl_print_format(macro_fll_error_s(020_debug_close), print->to, print->context);
+ }
+
+ fl_print_format(".%]%r", print->to, print->context, f_string_eol_s);
f_file_stream_unlock(print->to);
* This does not alter print.custom.setting.state.status.
* @param return_code
* The return code from the program.
+ * @param debug
+ * (optional) The debug details, such as file, line number, and function.
+ *
+ * Set to NULL to disable.
*
* @return
* F_okay on success.
* F_output_not (with error bit) if setting is NULL.
*/
#ifndef _di_fake_make_print_error_program_failed_
- extern f_status_t fake_make_print_error_program_failed(fl_print_t * const print, const int return_code);
+ extern f_status_t fake_make_print_error_program_failed(fl_print_t * const print, const int return_code, const f_string_t debug);
#endif // _di_fake_make_print_error_program_failed_
/**