]> Kevux Git Server - fll/commitdiff
Bugfix: Static builds with '../' relative paths for objects do not build correctly.
authorKevin Day <Kevin@kevux.org>
Mon, 12 Jan 2026 02:47:31 +0000 (20:47 -0600)
committerKevin Day <Kevin@kevux.org>
Mon, 12 Jan 2026 03:01:19 +0000 (21:01 -0600)
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.

level_3/fake/c/main/build/library.c
level_3/fake/c/main/common.c
level_3/fake/c/main/common.h
level_3/fake/c/main/common/type.c
level_3/fake/c/main/common/type.h
level_3/fake/c/main/make/operate_process.c
level_3/fake/c/main/make/operate_process.h
level_3/fake/c/main/make/operate_process_type.c
level_3/fake/c/main/make/print/error.c
level_3/fake/c/main/make/print/error.h

index 3ef6720eb849049b5c2800a9d07e8335732a2852..b857e2e8ef8e31b859be19217a2786c385fcc467 100644 (file)
@@ -520,10 +520,16 @@ extern "C" {
 
         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);
@@ -531,12 +537,51 @@ extern "C" {
             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);
@@ -673,10 +718,10 @@ extern "C" {
         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);
@@ -684,15 +729,60 @@ extern "C" {
           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);
@@ -701,6 +791,14 @@ extern "C" {
         }
 
         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)) {
@@ -717,6 +815,14 @@ extern "C" {
             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) {
index 0fe00c097eadfd77ebc1bd2184df72f2390523f2..0b265af7ca2e5cb8ff1a021a79428ccca1e39b84 100644 (file)
@@ -4,6 +4,195 @@
 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) {
 
index 53617bfd74cd27aa8b4048ae044b80880f62412b..09261feb266d2a467bbe02828ff8cf769583d551 100644 (file)
 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.
  *
index 32b705e27bbb68bb6841500c9a3a1191ec969eda..b32ebf2bd5f4779c8318057818f029f3669d187f 100644 (file)
@@ -228,6 +228,7 @@ extern "C" {
     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);
 
index 6968e17ba09a77741c9101cc57db37aac8224ab1..4a74173159d344543e6a820d1d90c3b60ed957dd 100644 (file)
@@ -138,6 +138,7 @@ extern "C" {
  *   - 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.
@@ -153,6 +154,7 @@ extern "C" {
     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;
@@ -166,6 +168,7 @@ extern "C" {
     .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, \
index a1cb9bca823e476e6eb737e12bd14624ce024a3e..1d95e95a73a0ab88e8195b341af96fb70e50956b 100644 (file)
@@ -346,14 +346,14 @@ extern "C" {
       }
     }
 
-    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;
 
@@ -386,7 +386,7 @@ extern "C" {
         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;
 
index b797d8ee16defd663a9c3253e032a9dbae3152e4..a7406bac17d65943a3e4ccc783230358a5f81254 100644 (file)
@@ -209,13 +209,17 @@ extern "C" {
  *     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_
 
 /**
index 79f7106deccbb7d4373734dde5c06546bb4e88f7..650c97b77731c3635d765bdad73ce7f21e8aa9be 100644 (file)
@@ -39,7 +39,7 @@ extern "C" {
     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_
 
@@ -53,7 +53,7 @@ extern "C" {
     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_
 
@@ -67,7 +67,7 @@ extern "C" {
     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;
   }
@@ -1361,7 +1361,7 @@ extern "C" {
     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;
   }
@@ -1893,7 +1893,7 @@ extern "C" {
     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_
 
index 688b9aa54db4934ec8f2dcdd2a4cef25b325c457..e53b102dfc7564c52cc2ca2e54d960d635ca3bf2 100644 (file)
@@ -282,7 +282,7 @@ extern "C" {
 #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;
@@ -290,8 +290,15 @@ extern "C" {
     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);
 
index f82bccd4aff8a01224890d0eba97c73727426312..af5860e2f78a915b3ae99869c3fc0ec4d73d5898 100644 (file)
@@ -425,6 +425,10 @@ extern "C" {
  *   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.
@@ -433,7 +437,7 @@ extern "C" {
  *   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_
 
 /**