]> Kevux Git Server - fll/commitdiff
Security: The va_list has undefined behavior when passed into functions.
authorKevin Day <thekevinday@gmail.com>
Sat, 26 Feb 2022 16:50:26 +0000 (10:50 -0600)
committerKevin Day <thekevinday@gmail.com>
Sat, 26 Feb 2022 16:50:26 +0000 (10:50 -0600)
When the va_list is started using va_start(), the va_arg() must be called within the same function.
This is a design problem with how va_list and its respective functions are implemented.
The man pages directly document that passing an already started va_list to a function and then calling va_arg() is undefined.

The va_list, being a macro, might also be a pointer.
This makes passing it as a pointer (or with "const") risky.

Due to the mentioned undefined states and risks, this is considered and treated as a security issue.

Move the va_XXX() logic into a single function.
This unfortunately means some functions have to be expanded out into the code and deleted.
The code now, unfortunately, has more nested as a result of having to add more loops within the same function.

The va_copy() macro is used and so the ap list state is no longer changed outside of the function.

level_1/fl_print/c/print.c
level_1/fl_print/c/print.h
level_1/fl_print/c/private-print.c
level_1/fl_print/c/private-print.h
level_2/fll_print/c/print.c
level_2/fll_print/c/print.h

index 42c5032fbf408261db38f0ffc2cb8b4766ee69d4..e0ceb907af4d6df4721b3891c2f11c55bebbd78c 100644 (file)
@@ -18,20 +18,7 @@ extern "C" {
 
     va_start(ap, stream);
 
-    for (f_string_t current = string; *current; ++current) {
-
-      if (*current == f_string_ascii_percent_s.string[0]) {
-        ++current;
-
-        current = private_fl_print_format_convert(current, stream, &ap, &status);
-        if (F_status_is_error(status)) break;
-      }
-      else {
-        if (!fputc_unlocked(*current, stream)) {
-          break;
-        }
-      }
-    } // for
+    private_fl_print_format_convert(string, stream, ap, &status);
 
     va_end(ap);
 
@@ -42,10 +29,9 @@ extern "C" {
 #endif // _di_fl_print_format_
 
 #ifndef _di_fl_print_format_convert_
-  f_string_t fl_print_format_convert(const f_string_t string, FILE * const stream, va_list * const ap, f_status_t * const status) {
+  f_string_t fl_print_format_convert(const f_string_t string, FILE * const stream, va_list ap, f_status_t * const status) {
     #ifndef _di_level_1_parameter_checking_
       if (!stream) return 0;
-      if (!ap) return 0;
     #endif // _di_level_1_parameter_checking_
 
     return private_fl_print_format_convert(string, stream, ap, status);
@@ -53,30 +39,15 @@ extern "C" {
 #endif // _di_fl_print_format_convert_
 
 #ifndef _di_fl_print_string_va_
-  f_status_t fl_print_string_va(const f_string_t string, FILE * const stream, va_list * const ap) {
+  f_status_t fl_print_string_va(const f_string_t string, FILE * const stream, va_list ap) {
     #ifndef _di_level_1_parameter_checking_
       if (!string) return F_status_set_error(F_parameter);
       if (!stream) return F_status_set_error(F_parameter);
-      if (!ap) return F_status_set_error(F_parameter);
     #endif // _di_level_1_parameter_checking_
 
     f_status_t status = F_none;
 
-    for (f_string_t current = string; *current; ++current) {
-
-      if (*current == f_string_ascii_percent_s.string[0]) {
-        ++current;
-
-        current = private_fl_print_format_convert(current, stream, ap, &status);
-        if (F_status_is_error(status)) break;
-      }
-      else {
-        if (!fputc_unlocked(*current, stream)) {
-          break;
-        }
-      }
-    } // for
-
+    private_fl_print_format_convert(string, stream, ap, &status);
     if (F_status_is_error(status)) return status;
 
     return F_none;
index 4107a087abb2bd964b134b720bf7689e475f8f21..ad6a0b9b6a8a780114045149f5931baa80b3089f 100644 (file)
@@ -209,8 +209,9 @@ extern "C" {
  * @see fprintf()
  * @see fputc_unlocked()
  * @see snprintf()
- * @see va_start()
+ * @see va_copy()
  * @see va_end()
+ * @see va_start()
  *
  * @see f_conversion_number_signed_print()
  * @see f_conversion_number_unsigned_print()
@@ -280,7 +281,7 @@ extern "C" {
  * @see f_print_terminated()
  */
 #ifndef _di_fl_print_format_convert_
-  extern f_string_t fl_print_format_convert(const f_string_t string, FILE * const stream, va_list * const ap, f_status_t * const status);
+  extern f_string_t fl_print_format_convert(const f_string_t string, FILE * const stream, va_list ap, f_status_t * const status);
 #endif // _di_fl_print_format_convert_
 
 /**
@@ -315,8 +316,9 @@ extern "C" {
  *   Errors (with error bit) from: f_print_terminated().
  *
  * @see fputc_unlocked()
- * @see va_start()
+ * @see va_copy()
  * @see va_end()
+ * @see va_start()
  *
  * @see f_conversion_number_signed_print()
  * @see f_conversion_number_unsigned_print()
@@ -328,7 +330,7 @@ extern "C" {
  * @see fl_print_format()
  */
 #ifndef _di_fl_print_string_va_
-  extern f_status_t fl_print_string_va(const f_string_t string, FILE * const stream, va_list * const ap);
+  extern f_status_t fl_print_string_va(const f_string_t string, FILE * const stream, va_list ap);
 #endif // _di_fl_print_string_va_
 
 /**
index d5b50da429a95782d9ee93bb6dd7e091fe0d7108..e98cc4e9c16bc8232791c1469897c1657b17e0e5 100644 (file)
@@ -6,1157 +6,1199 @@ extern "C" {
 #endif
 
 #if !defined(_di_fl_print_format_) || !defined(_di_fl_print_format_convert_)
-  f_string_t private_fl_print_format_convert(f_string_t string, FILE * const stream, va_list * const ap, f_status_t * const status) {
+  f_string_t private_fl_print_format_convert(f_string_t string, FILE * const stream, va_list ap, f_status_t * const status) {
 
-    const f_string_t start = string;
-
-    // An unpaired '%' character must not be at the end of the string.
-    if (!*string) {
-      *status = F_status_set_error(F_eos);
-
-      return string;
-    }
-
-    *status = F_none;
-
-    uint8_t base = 10;
-    uint32_t flag = 0;
-    uint8_t type = 0;
-
-    unsigned int width = 1;
-    unsigned int precision = 1;
+    // Due to the technical design of the va_list, this must be created, copied, and ended within this function.
+    va_list apl;
+    va_copy(apl, ap);
 
     for (; *string; ++string) {
 
-      if (*string < 0x2c) {
-        if (*string == f_string_ascii_space_s.string[0]) {
-          flag |= F_print_format_flag_sign_pad_d;
+      if (*string == f_string_ascii_percent_s.string[0]) {
+        ++string;
 
-          continue;
-        }
-        else if (*string == f_string_ascii_exclamation_s.string[0]) {
-          base = 2;
+        const f_string_t start = string;
 
-          continue;
-        }
-        else if (*string == f_string_ascii_pound_s.string[0]) {
-          flag |= F_print_format_flag_convert_d;
+        // An unpaired '%' character must not be at the end of the string.
+        if (!*string) {
+          *status = F_status_set_error(F_eos);
 
-          continue;
-        }
-        else if (*string == f_string_ascii_dollar_s.string[0]) {
+          va_end(apl);
 
-          // If followed immediately by a '$' this is ignored.
-          // Use '%$' to separate, such as '%l%$l' would allow for '0l' to be printed where '%ll' would interpret the 'l', resulting in a long long.
           return string;
         }
-        else if (*string == f_string_ascii_percent_s.string[0]) {
 
-          // The first percent found represents a literal '%' to be printed, otherwise return as invalid.
-          if (string == start) {
-            if (fwrite_unlocked(f_string_ascii_percent_s.string, 1, f_string_ascii_percent_s.used, stream) < f_string_ascii_percent_s.used) {
-              *status = F_status_set_error(F_output);
-            }
-          }
-          else {
-            *status = F_status_set_error(F_valid_not);
-          }
+        *status = F_none;
 
-          return string;
-        }
-        else if (*string == f_string_ascii_ampersand_s.string[0]) {
-          base = 12;
+        uint8_t base = 10;
+        uint32_t flag = 0;
+        uint8_t type = 0;
 
-          continue;
-        }
-        else if (*string == f_string_ascii_asterisk_s.string[0]) {
-          flag |= F_print_format_flag_width_d | F_print_format_flag_width_value_d;
-          continue;
-        }
-        else if (*string == f_string_ascii_plus_s.string[0]) {
-          flag |= F_print_format_flag_sign_always_d;
+        unsigned int width = 1;
+        unsigned int precision = 1;
 
-          continue;
-        }
-        else {
-          *status = F_status_set_error(F_valid_not);
+        for (; *string; ++string) {
 
-          return string;
-        }
-      }
-      else if (*string < 0x41) {
-        if (*string == f_string_ascii_minus_s.string[0]) {
-          flag |= F_print_format_flag_align_left_d;
-
-          continue;
-        }
-        else if (*string == f_string_ascii_period_s.string[0]) {
-          if (!*(string + 1)) {
-            *status = F_status_set_error(F_eos);
-
-            return string;
-          }
-
-          ++string;
-
-          if (*string == f_string_ascii_asterisk_s.string[0]) {
-            flag |= F_print_format_flag_precision_d | F_print_format_flag_precision_value_d;
-          }
-          else if (*string < 0x30 || *string > 0x39) {
-            *status = F_status_set_error(F_valid_not);
-
-            return string;
-          }
-          else {
-            string = private_fl_print_convert_number(string, ap, &precision, status);
-            if (F_status_is_error(*status)) return string;
-
-            flag |= F_print_format_flag_precision_d;
-          }
-
-          continue;
-        }
-        else if (*string == f_string_ascii_slash_forward_s.string[0]) {
-          flag |= F_print_format_flag_range_d;
-
-          continue;
-        }
-        else if (*string > 0x2f && *string < 0x3a) {
-          if (!(flag & F_print_format_flag_width_d)) {
-            if (*string == f_string_ascii_0_s.string[0]) {
-              flag |= F_print_format_flag_zeros_leading_d;
+          if (*string < 0x2c) {
+            if (*string == f_string_ascii_space_s.string[0]) {
+              flag |= F_print_format_flag_sign_pad_d;
 
               continue;
             }
+            else if (*string == f_string_ascii_exclamation_s.string[0]) {
+              base = 2;
 
-            flag |= F_print_format_flag_width_d;
-
-            string = private_fl_print_convert_number(string, ap, &width, status);
-            if (F_status_is_error(*status)) return string;
-
-            continue;
-          }
-          else {
-            *status = F_status_set_error(F_valid_not);
-
-            return string;
-          }
-        }
-        else if (*string == f_string_ascii_colon_s.string[0]) {
-          flag |= F_print_format_flag_ignore_range_d;
-
-          continue;
-        }
-        else if (*string == f_string_ascii_colon_semi_s.string[0]) {
-          flag |= F_print_format_flag_ignore_index_d;
-
-          continue;
-        }
-        else if (*string == f_string_ascii_equal_s.string[0]) {
-          flag |= F_print_format_flag_trim_d;
-
-          continue;
-        }
-        else if (*string == f_string_ascii_sign_at_s.string[0]) {
-          base = 8;
-
-          continue;
-        }
-        else {
-          *status = F_status_set_error(F_valid_not);
-
-          return string;
-        }
-      }
-      else if (*string < 0x56) {
-        if (*string == f_string_ascii_C_s.string[0]) {
-          char value[1] = { (char) va_arg(*ap, int) };
-
-          *status = f_print_safely(value, 1, stream);
+              continue;
+            }
+            else if (*string == f_string_ascii_pound_s.string[0]) {
+              flag |= F_print_format_flag_convert_d;
 
-          return string;
-        }
-        else if (*string == f_string_ascii_D_s.string[0]) {
-          type = f_print_format_type_double_32_e;
-          flag |= F_print_format_flag_uppercase_d;
+              continue;
+            }
+            else if (*string == f_string_ascii_dollar_s.string[0]) {
 
-          if (*(string + 1)) {
-            if (*(string + 1) == f_string_ascii_L_s.string[0]) {
-              type = f_print_format_type_double_64_e;
+              // If followed immediately by a '$' this is ignored.
+              // Use '%$' to separate, such as '%l%$l' would allow for '0l' to be printed where '%ll' would interpret the 'l', resulting in a long long.
+              break;
+            }
+            else if (*string == f_string_ascii_percent_s.string[0]) {
 
-              if (*(string + 2) == f_string_ascii_e_s.string[0]) {
-                flag |= F_print_format_flag_exponent_d;
-                string += 2;
-              }
-              else if (*(string + 2) == f_string_ascii_E_s.string[0]) {
-                flag |= F_print_format_flag_exponent_d | F_print_format_flag_exponent_upper_d;
-                string += 2;
-              }
-              else if (*(string + 2) == f_string_ascii_g_s.string[0]) {
-                flag |= F_print_format_flag_exponent_either_d;
-                string += 2;
-              }
-              else if (*(string + 2) == f_string_ascii_G_s.string[0]) {
-                flag |= F_print_format_flag_exponent_either_d | F_print_format_flag_exponent_upper_d;
-                string += 2;
+              // The first percent found represents a literal '%' to be printed, otherwise return as invalid.
+              if (string == start) {
+                if (fwrite_unlocked(f_string_ascii_percent_s.string, 1, f_string_ascii_percent_s.used, stream) < f_string_ascii_percent_s.used) {
+                  *status = F_status_set_error(F_output);
+                }
               }
               else {
-                ++string;
+                *status = F_status_set_error(F_valid_not);
               }
+
+              break;
             }
-            else if (*(string + 1) == f_string_ascii_e_s.string[0]) {
-              flag |= F_print_format_flag_exponent_d;
-              ++string;
-            }
-            else if (*(string + 1) == f_string_ascii_E_s.string[0]) {
-              flag |= F_print_format_flag_exponent_d | F_print_format_flag_exponent_upper_d;
-              ++string;
-            }
-            else if (*(string + 1) == f_string_ascii_g_s.string[0]) {
-              flag |= F_print_format_flag_exponent_either_d;
-              ++string;
-            }
-            else if (*(string + 1) == f_string_ascii_G_s.string[0]) {
-              flag |= F_print_format_flag_exponent_either_d | F_print_format_flag_exponent_upper_d;
-              ++string;
-            }
-          }
-        }
-        else if (*string == f_string_ascii_I_s.string[0]) {
-          type = f_print_format_type_signed_32_e;
-          flag |= F_print_format_flag_uppercase_d;
+            else if (*string == f_string_ascii_ampersand_s.string[0]) {
+              base = 12;
 
-          if (*(string + 1) == f_string_ascii_I_s.string[0]) {
-            if (*(string + 2) == f_string_ascii_I_s.string[0]) {
-              type = f_print_format_type_signed_8_e;
-              string += 2;
+              continue;
             }
-            else {
-              type = f_print_format_type_signed_16_e;
-              ++string;
+            else if (*string == f_string_ascii_asterisk_s.string[0]) {
+              flag |= F_print_format_flag_width_d | F_print_format_flag_width_value_d;
+              continue;
             }
-          }
-          else if (*(string + 1) == f_string_ascii_L_s.string[0]) {
-            if (*(string + 2) == f_string_ascii_L_s.string[0]) {
-              type = f_print_format_type_signed_128_e;
-              string += 2;
+            else if (*string == f_string_ascii_plus_s.string[0]) {
+              flag |= F_print_format_flag_sign_always_d;
+
+              continue;
             }
             else {
-              type = f_print_format_type_signed_64_e;
-              ++string;
+              *status = F_status_set_error(F_valid_not);
+
+              break;
             }
           }
-          else if (*(string + 1) == f_string_ascii_N_s.string[0]) {
-            type = f_print_format_type_signed_number_e;
-            flag |= F_print_format_flag_uppercase_d;
-            ++string;
-          }
-        }
-        else if (*string == f_string_ascii_Q_s.string[0]) {
-          const f_string_static_t value = va_arg(*ap, f_string_static_t);
-
-          if (flag & F_print_format_flag_range_d) {
-            const f_string_range_t partial = va_arg(*ap, f_string_range_t);
-
-            if (flag & F_print_format_flag_ignore_index_d) {
-              const f_array_lengths_t except_at = va_arg(*ap, f_array_lengths_t);
-              f_string_ranges_t except_in = f_string_ranges_t_initialize;
-
-              if (flag & F_print_format_flag_ignore_range_d) {
-                except_in = va_arg(*ap, f_string_ranges_t);
-              }
+          else if (*string < 0x41) {
+            if (*string == f_string_ascii_minus_s.string[0]) {
+              flag |= F_print_format_flag_align_left_d;
 
-              if (partial.start > partial.stop) {
-                *status = F_data_not;
+              continue;
+            }
+            else if (*string == f_string_ascii_period_s.string[0]) {
+              if (!*(string + 1)) {
+                *status = F_status_set_error(F_eos);
 
-                return string;
+                break;
               }
 
-              f_array_length_t length = (partial.stop - partial.start) + 1;
+              ++string;
 
-              if (length + partial.start > value.used) {
-                length = value.used - partial.start;
+              if (*string == f_string_ascii_asterisk_s.string[0]) {
+                flag |= F_print_format_flag_precision_d | F_print_format_flag_precision_value_d;
               }
+              else if (*string < 0x30 || *string > 0x39) {
+                *status = F_status_set_error(F_valid_not);
 
-              if (flag & F_print_format_flag_trim_d) {
-                *status = private_fl_print_trim_except_in_safely(value.string, partial.start, length, except_at, except_in, stream);
+                break;
               }
               else {
-                *status = f_print_except_in_safely(value.string, partial.start, length, except_at, except_in, stream);
-              }
-            }
-            else if (flag & F_print_format_flag_ignore_range_d) {
-              const f_array_lengths_t except_at = f_array_lengths_t_initialize;
-              const f_string_ranges_t except_in = va_arg(*ap, f_string_ranges_t);
+                for (precision = 0; *string; ++string) {
 
-              if (partial.start > partial.stop) {
-                *status = F_data_not;
+                  if (*string > 0x2f && *string < 0x3a) {
+                    precision *= 10;
+                    precision += 0xf & *string;
+                  }
+                  else if (*string == f_string_ascii_asterisk_s.string[0]) {
+                    precision = va_arg(apl, unsigned int);
 
-                return string;
-              }
+                    break;
+                  }
+                  else {
 
-              f_array_length_t length = (partial.stop - partial.start) + 1;
+                    // Do not leave string on the non-digit and non-asterisk character.
+                    --string;
 
-              if (length + partial.start > value.used) {
-                length = value.used - partial.start;
-              }
+                    break;
+                  }
+                } // for
 
-              if (flag & F_print_format_flag_trim_d) {
-                *status = private_fl_print_trim_except_in_safely(value.string, partial.start, length, except_at, except_in, stream);
-              }
-              else {
-                *status = f_print_except_in_safely(value.string, partial.start, length, except_at, except_in, stream);
-              }
-            }
-            else {
-              const f_array_lengths_t except_at = f_array_lengths_t_initialize;
-              const f_string_ranges_t except_in = f_string_ranges_t_initialize;
-
-              if (partial.start > partial.stop) {
-                *status = F_data_not;
-
-                return string;
-              }
+                // Do not leave string on the terminating NULL.
+                if (!string) {
+                  --string;
+                }
 
-              f_array_length_t length = (partial.stop - partial.start) + 1;
+                if (F_status_is_error(*status)) break;
 
-              if (length + partial.start > value.used) {
-                length = value.used - partial.start;
+                flag |= F_print_format_flag_precision_d;
               }
 
-              if (flag & F_print_format_flag_trim_d) {
-                *status = private_fl_print_trim_safely(value.string + partial.start, length, stream);
-              }
-              else {
-                *status = f_print_safely(value.string + partial.start, length, stream);
-              }
-            }
-          }
-          else if (flag & F_print_format_flag_ignore_index_d) {
-            const f_array_lengths_t except_at = va_arg(*ap, f_array_lengths_t);
-            f_string_ranges_t except_in = f_string_ranges_t_initialize;
-
-            if (flag & F_print_format_flag_ignore_range_d) {
-              except_in = va_arg(*ap, f_string_ranges_t);
+              continue;
             }
+            else if (*string == f_string_ascii_slash_forward_s.string[0]) {
+              flag |= F_print_format_flag_range_d;
 
-            if (flag & F_print_format_flag_trim_d) {
-              *status = private_fl_print_trim_except_in_safely(value.string, 0, value.used, except_at, except_in, stream);
-            }
-            else {
-              *status = f_print_except_in_dynamic_safely(value, except_at, except_in, stream);
+              continue;
             }
-          }
-          else if (flag & F_print_format_flag_ignore_range_d) {
-            const f_array_lengths_t except_at = f_array_lengths_t_initialize;
-            const f_string_ranges_t except_in = va_arg(*ap, f_string_ranges_t);
+            else if (*string > 0x2f && *string < 0x3a) {
+              if (!(flag & F_print_format_flag_width_d)) {
+                if (*string == f_string_ascii_0_s.string[0]) {
+                  flag |= F_print_format_flag_zeros_leading_d;
 
-            if (flag & F_print_format_flag_trim_d) {
-              *status = private_fl_print_trim_except_in_safely(value.string, 0, value.used, except_at, except_in, stream);
-            }
-            else {
-              *status = f_print_except_in_dynamic_safely(value, except_at, except_in, stream);
-            }
-          }
-          else {
-            if (flag & F_print_format_flag_trim_d) {
-              *status = private_fl_print_trim_safely(value.string, value.used, stream);
-            }
-            else {
-              *status = f_print_dynamic_safely(value, stream);
-            }
-          }
+                  continue;
+                }
 
-          return string;
-        }
-        else if (*string == f_string_ascii_R_s.string[0]) {
-          const f_string_static_t value = va_arg(*ap, f_string_static_t);
+                flag |= F_print_format_flag_width_d;
 
-          if (flag & F_print_format_flag_range_d) {
-            const f_string_range_t partial = va_arg(*ap, f_string_range_t);
+                {
+                  for (width = 0; *string; ++string) {
 
-            if (flag & F_print_format_flag_ignore_index_d) {
-              const f_array_lengths_t except_at = va_arg(*ap, f_array_lengths_t);
-              f_string_ranges_t except_in = f_string_ranges_t_initialize;
+                    if (*string > 0x2f && *string < 0x3a) {
+                      width *= 10;
+                      width += 0xf & *string;
+                    }
+                    else if (*string == f_string_ascii_asterisk_s.string[0]) {
+                      width = va_arg(apl, unsigned int);
 
-              if (flag & F_print_format_flag_ignore_range_d) {
-                except_in = va_arg(*ap, f_string_ranges_t);
-              }
+                      break;
+                    }
+                    else {
 
-              if (partial.start > partial.stop) {
-                *status = F_data_not;
+                      // Do not leave string on the non-digit and non-asterisk character.
+                      --string;
 
-                return string;
-              }
+                      break;
+                    }
+                  } // for
 
-              f_array_length_t length = (partial.stop - partial.start) + 1;
+                  // Do not leave string on the terminating NULL.
+                  if (!string) {
+                    --string;
+                  }
+                }
 
-              if (length + partial.start > value.used) {
-                length = value.used - partial.start;
-              }
+                if (F_status_is_error(*status)) break;
 
-              if (flag & F_print_format_flag_trim_d) {
-                *status = private_fl_print_trim_except_in_raw_safely(value.string, partial.start, length, except_at, except_in, stream);
+                continue;
               }
               else {
-                *status = f_print_except_in_raw_safely(value.string, partial.start, length, except_at, except_in, stream);
+                *status = F_status_set_error(F_valid_not);
+
+                break;
               }
             }
-            else if (flag & F_print_format_flag_ignore_range_d) {
-              const f_array_lengths_t except_at = f_array_lengths_t_initialize;
-              const f_string_ranges_t except_in = va_arg(*ap, f_string_ranges_t);
+            else if (*string == f_string_ascii_colon_s.string[0]) {
+              flag |= F_print_format_flag_ignore_range_d;
 
-              if (partial.start > partial.stop) {
-                *status = F_data_not;
+              continue;
+            }
+            else if (*string == f_string_ascii_colon_semi_s.string[0]) {
+              flag |= F_print_format_flag_ignore_index_d;
 
-                return string;
-              }
+              continue;
+            }
+            else if (*string == f_string_ascii_equal_s.string[0]) {
+              flag |= F_print_format_flag_trim_d;
 
-              f_array_length_t length = (partial.stop - partial.start) + 1;
+              continue;
+            }
+            else if (*string == f_string_ascii_sign_at_s.string[0]) {
+              base = 8;
 
-              if (length + partial.start > value.used) {
-                length = value.used - partial.start;
+              continue;
+            }
+            else {
+              *status = F_status_set_error(F_valid_not);
+
+              break;
+            }
+          }
+          else if (*string < 0x56) {
+            if (*string == f_string_ascii_C_s.string[0]) {
+              char value[1] = { (char) va_arg(apl, int) };
+
+              *status = f_print_safely(value, 1, stream);
+
+              break;
+            }
+            else if (*string == f_string_ascii_D_s.string[0]) {
+              type = f_print_format_type_double_32_e;
+              flag |= F_print_format_flag_uppercase_d;
+
+              if (*(string + 1)) {
+                if (*(string + 1) == f_string_ascii_L_s.string[0]) {
+                  type = f_print_format_type_double_64_e;
+
+                  if (*(string + 2) == f_string_ascii_e_s.string[0]) {
+                    flag |= F_print_format_flag_exponent_d;
+                    string += 2;
+                  }
+                  else if (*(string + 2) == f_string_ascii_E_s.string[0]) {
+                    flag |= F_print_format_flag_exponent_d | F_print_format_flag_exponent_upper_d;
+                    string += 2;
+                  }
+                  else if (*(string + 2) == f_string_ascii_g_s.string[0]) {
+                    flag |= F_print_format_flag_exponent_either_d;
+                    string += 2;
+                  }
+                  else if (*(string + 2) == f_string_ascii_G_s.string[0]) {
+                    flag |= F_print_format_flag_exponent_either_d | F_print_format_flag_exponent_upper_d;
+                    string += 2;
+                  }
+                  else {
+                    ++string;
+                  }
+                }
+                else if (*(string + 1) == f_string_ascii_e_s.string[0]) {
+                  flag |= F_print_format_flag_exponent_d;
+                  ++string;
+                }
+                else if (*(string + 1) == f_string_ascii_E_s.string[0]) {
+                  flag |= F_print_format_flag_exponent_d | F_print_format_flag_exponent_upper_d;
+                  ++string;
+                }
+                else if (*(string + 1) == f_string_ascii_g_s.string[0]) {
+                  flag |= F_print_format_flag_exponent_either_d;
+                  ++string;
+                }
+                else if (*(string + 1) == f_string_ascii_G_s.string[0]) {
+                  flag |= F_print_format_flag_exponent_either_d | F_print_format_flag_exponent_upper_d;
+                  ++string;
+                }
               }
-
-              if (flag & F_print_format_flag_trim_d) {
-                *status = private_fl_print_trim_except_in_raw_safely(value.string, partial.start, length, except_at, except_in, stream);
+            }
+            else if (*string == f_string_ascii_I_s.string[0]) {
+              type = f_print_format_type_signed_32_e;
+              flag |= F_print_format_flag_uppercase_d;
+
+              if (*(string + 1) == f_string_ascii_I_s.string[0]) {
+                if (*(string + 2) == f_string_ascii_I_s.string[0]) {
+                  type = f_print_format_type_signed_8_e;
+                  string += 2;
+                }
+                else {
+                  type = f_print_format_type_signed_16_e;
+                  ++string;
+                }
               }
-              else {
-                *status = f_print_except_in_raw_safely(value.string, partial.start, length, except_at, except_in, stream);
+              else if (*(string + 1) == f_string_ascii_L_s.string[0]) {
+                if (*(string + 2) == f_string_ascii_L_s.string[0]) {
+                  type = f_print_format_type_signed_128_e;
+                  string += 2;
+                }
+                else {
+                  type = f_print_format_type_signed_64_e;
+                  ++string;
+                }
+              }
+              else if (*(string + 1) == f_string_ascii_N_s.string[0]) {
+                type = f_print_format_type_signed_number_e;
+                flag |= F_print_format_flag_uppercase_d;
+                ++string;
               }
             }
-            else {
-              const f_array_lengths_t except_at = f_array_lengths_t_initialize;
-              const f_string_ranges_t except_in = f_string_ranges_t_initialize;
-
-              if (partial.start > partial.stop) {
-                *status = F_data_not;
-
-                return string;
+            else if (*string == f_string_ascii_Q_s.string[0]) {
+              const f_string_static_t value = va_arg(apl, f_string_static_t);
+
+              if (flag & F_print_format_flag_range_d) {
+                const f_string_range_t partial = va_arg(apl, f_string_range_t);
+
+                if (flag & F_print_format_flag_ignore_index_d) {
+                  const f_array_lengths_t except_at = va_arg(apl, f_array_lengths_t);
+                  f_string_ranges_t except_in = f_string_ranges_t_initialize;
+
+                  if (flag & F_print_format_flag_ignore_range_d) {
+                    except_in = va_arg(apl, f_string_ranges_t);
+                  }
+
+                  if (partial.start > partial.stop) {
+                    *status = F_data_not;
+
+                    break;
+                  }
+
+                  f_array_length_t length = (partial.stop - partial.start) + 1;
+
+                  if (length + partial.start > value.used) {
+                    length = value.used - partial.start;
+                  }
+
+                  if (flag & F_print_format_flag_trim_d) {
+                    *status = private_fl_print_trim_except_in_safely(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                  else {
+                    *status = f_print_except_in_safely(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                }
+                else if (flag & F_print_format_flag_ignore_range_d) {
+                  const f_array_lengths_t except_at = f_array_lengths_t_initialize;
+                  const f_string_ranges_t except_in = va_arg(apl, f_string_ranges_t);
+
+                  if (partial.start > partial.stop) {
+                    *status = F_data_not;
+
+                    break;
+                  }
+
+                  f_array_length_t length = (partial.stop - partial.start) + 1;
+
+                  if (length + partial.start > value.used) {
+                    length = value.used - partial.start;
+                  }
+
+                  if (flag & F_print_format_flag_trim_d) {
+                    *status = private_fl_print_trim_except_in_safely(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                  else {
+                    *status = f_print_except_in_safely(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                }
+                else {
+                  const f_array_lengths_t except_at = f_array_lengths_t_initialize;
+                  const f_string_ranges_t except_in = f_string_ranges_t_initialize;
+
+                  if (partial.start > partial.stop) {
+                    *status = F_data_not;
+
+                    break;
+                  }
+
+                  f_array_length_t length = (partial.stop - partial.start) + 1;
+
+                  if (length + partial.start > value.used) {
+                    length = value.used - partial.start;
+                  }
+
+                  if (flag & F_print_format_flag_trim_d) {
+                    *status = private_fl_print_trim_safely(value.string + partial.start, length, stream);
+                  }
+                  else {
+                    *status = f_print_safely(value.string + partial.start, length, stream);
+                  }
+                }
               }
-
-              f_array_length_t length = (partial.stop - partial.start) + 1;
-
-              if (length + partial.start > value.used) {
-                length = value.used - partial.start;
+              else if (flag & F_print_format_flag_ignore_index_d) {
+                const f_array_lengths_t except_at = va_arg(apl, f_array_lengths_t);
+                f_string_ranges_t except_in = f_string_ranges_t_initialize;
+
+                if (flag & F_print_format_flag_ignore_range_d) {
+                  except_in = va_arg(apl, f_string_ranges_t);
+                }
+
+                if (flag & F_print_format_flag_trim_d) {
+                  *status = private_fl_print_trim_except_in_safely(value.string, 0, value.used, except_at, except_in, stream);
+                }
+                else {
+                  *status = f_print_except_in_dynamic_safely(value, except_at, except_in, stream);
+                }
               }
-
-              if (flag & F_print_format_flag_trim_d) {
-                *status = private_fl_print_trim_raw_safely(value.string + partial.start, length, stream);
+              else if (flag & F_print_format_flag_ignore_range_d) {
+                const f_array_lengths_t except_at = f_array_lengths_t_initialize;
+                const f_string_ranges_t except_in = va_arg(apl, f_string_ranges_t);
+
+                if (flag & F_print_format_flag_trim_d) {
+                  *status = private_fl_print_trim_except_in_safely(value.string, 0, value.used, except_at, except_in, stream);
+                }
+                else {
+                  *status = f_print_except_in_dynamic_safely(value, except_at, except_in, stream);
+                }
               }
               else {
-                *status = f_print_raw_safely(value.string + partial.start, length, stream);
+                if (flag & F_print_format_flag_trim_d) {
+                  *status = private_fl_print_trim_safely(value.string, value.used, stream);
+                }
+                else {
+                  *status = f_print_dynamic_safely(value, stream);
+                }
               }
-            }
-          }
-          else if (flag & F_print_format_flag_ignore_index_d) {
-            const f_array_lengths_t except_at = va_arg(*ap, f_array_lengths_t);
-            f_string_ranges_t except_in = f_string_ranges_t_initialize;
 
-            if (flag & F_print_format_flag_ignore_range_d) {
-              except_in = va_arg(*ap, f_string_ranges_t);
+              break;
             }
+            else if (*string == f_string_ascii_R_s.string[0]) {
+              const f_string_static_t value = va_arg(apl, f_string_static_t);
 
-            if (flag & F_print_format_flag_trim_d) {
-              *status = private_fl_print_trim_except_in_raw_safely(value.string, 0, value.used, except_at, except_in, stream);
-            }
-            else {
-              *status = f_print_except_in_dynamic_raw_safely(value, except_at, except_in, stream);
-            }
-          }
-          else if (flag & F_print_format_flag_ignore_range_d) {
-            const f_array_lengths_t except_at = f_array_lengths_t_initialize;
-            const f_string_ranges_t except_in = va_arg(*ap, f_string_ranges_t);
+              if (flag & F_print_format_flag_range_d) {
+                const f_string_range_t partial = va_arg(apl, f_string_range_t);
 
-            if (flag & F_print_format_flag_trim_d) {
-              *status = private_fl_print_trim_except_in_raw_safely(value.string, 0, value.used, except_at, except_in, stream);
-            }
-            else {
-              *status = f_print_except_in_dynamic_raw_safely(value, except_at, except_in, stream);
-            }
-          }
-          else {
-            if (flag & F_print_format_flag_trim_d) {
-              *status = private_fl_print_trim_raw_safely(value.string, value.used, stream);
-            }
-            else {
-              *status = f_print_dynamic_raw_safely(value, stream);
-            }
-          }
+                if (flag & F_print_format_flag_ignore_index_d) {
+                  const f_array_lengths_t except_at = va_arg(apl, f_array_lengths_t);
+                  f_string_ranges_t except_in = f_string_ranges_t_initialize;
 
-          return string;
-        }
-        else if (*string == f_string_ascii_S_s.string[0]) {
-          const f_string_t value = va_arg(*ap, f_string_t);
+                  if (flag & F_print_format_flag_ignore_range_d) {
+                    except_in = va_arg(apl, f_string_ranges_t);
+                  }
 
-          *status = f_print_safely_terminated(value, stream);
+                  if (partial.start > partial.stop) {
+                    *status = F_data_not;
 
-          return string;
-        }
-        else if (*string == f_string_ascii_U_s.string[0]) {
-          type = f_print_format_type_unsigned_32_e;
-          flag |= F_print_format_flag_uppercase_d;
+                    break;
+                  }
 
-          if (*(string + 1) == f_string_ascii_I_s.string[0]) {
-            if (*(string + 2) == f_string_ascii_I_s.string[0]) {
-              type = f_print_format_type_unsigned_8_e;
-              string += 2;
-            }
-            else {
-              type = f_print_format_type_unsigned_16_e;
-              ++string;
-            }
-          }
-          else if (*(string + 1) == f_string_ascii_L_s.string[0]) {
-            if (*(string + 2) == f_string_ascii_L_s.string[0]) {
-              type = f_print_format_type_unsigned_128_e;
-              string += 2;
-            }
-            else {
-              type = f_print_format_type_unsigned_64_e;
-              ++string;
-            }
-          }
-          else if (*(string + 1) == f_string_ascii_N_s.string[0]) {
-            type = f_print_format_type_unsigned_number_e;
-            ++string;
-          }
-        }
-        else {
-          *status = F_status_set_error(F_valid_not);
+                  f_array_length_t length = (partial.stop - partial.start) + 1;
 
-          return string;
-        }
-      }
-      else if (*string < 0x60) {
-        if (*string == f_string_ascii_Z_s.string[0]) {
-          type = f_print_format_type_size_e;
-          flag |= F_print_format_flag_uppercase_d;
-        }
-        else if (*string == f_string_ascii_bracket_open_s.string[0]) {
-          const f_color_set_t value = va_arg(*ap, f_color_set_t);
+                  if (length + partial.start > value.used) {
+                    length = value.used - partial.start;
+                  }
 
-          if (value.before) {
-            *status = f_print_dynamic_raw(*value.before, stream);
-          }
+                  if (flag & F_print_format_flag_trim_d) {
+                    *status = private_fl_print_trim_except_in_raw_safely(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                  else {
+                    *status = f_print_except_in_raw_safely(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                }
+                else if (flag & F_print_format_flag_ignore_range_d) {
+                  const f_array_lengths_t except_at = f_array_lengths_t_initialize;
+                  const f_string_ranges_t except_in = va_arg(apl, f_string_ranges_t);
 
-          return string;
-        }
-        else if (*string == f_string_ascii_bracket_close_s.string[0]) {
-          const f_color_set_t value = va_arg(*ap, f_color_set_t);
+                  if (partial.start > partial.stop) {
+                    *status = F_data_not;
 
-          if (value.after) {
-            *status = f_print_dynamic_raw(*value.after, stream);
-          }
+                    break;
+                  }
 
-          return string;
-        }
-        else if (*string == f_string_ascii_caret_s.string[0]) {
-          base = 10;
+                  f_array_length_t length = (partial.stop - partial.start) + 1;
 
-          continue;
-        }
-        else if (*string == f_string_ascii_underscore_s.string[0]) {
-          base = 16;
+                  if (length + partial.start > value.used) {
+                    length = value.used - partial.start;
+                  }
 
-          continue;
-        }
-        else {
-          *status = F_status_set_error(F_valid_not);
+                  if (flag & F_print_format_flag_trim_d) {
+                    *status = private_fl_print_trim_except_in_raw_safely(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                  else {
+                    *status = f_print_except_in_raw_safely(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                }
+                else {
+                  const f_array_lengths_t except_at = f_array_lengths_t_initialize;
+                  const f_string_ranges_t except_in = f_string_ranges_t_initialize;
 
-          return string;
-        }
-      }
-      else if (*string < 0x72) {
-        if (*string == f_string_ascii_c_s.string[0]) {
-          const char value = (char) va_arg(*ap, uint32_t);
+                  if (partial.start > partial.stop) {
+                    *status = F_data_not;
 
-          if (!fputc_unlocked(value, stream)) {
-            *status = F_status_set_error(F_output);
-          }
+                    break;
+                  }
 
-          return string;
-        }
-        else if (*string == f_string_ascii_d_s.string[0]) {
-          type = f_print_format_type_double_32_e;
+                  f_array_length_t length = (partial.stop - partial.start) + 1;
 
-          if (*(string + 1)) {
-            if (*(string + 1) == f_string_ascii_L_s.string[0]) {
-              type = f_print_format_type_double_64_e;
+                  if (length + partial.start > value.used) {
+                    length = value.used - partial.start;
+                  }
 
-              if (*(string + 2) == f_string_ascii_e_s.string[0]) {
-                flag |= F_print_format_flag_exponent_d;
-                string += 2;
+                  if (flag & F_print_format_flag_trim_d) {
+                    *status = private_fl_print_trim_raw_safely(value.string + partial.start, length, stream);
+                  }
+                  else {
+                    *status = f_print_raw_safely(value.string + partial.start, length, stream);
+                  }
+                }
               }
-              else if (*(string + 2) == f_string_ascii_E_s.string[0]) {
-                flag |= F_print_format_flag_exponent_d | F_print_format_flag_exponent_upper_d;
-                string += 2;
+              else if (flag & F_print_format_flag_ignore_index_d) {
+                const f_array_lengths_t except_at = va_arg(apl, f_array_lengths_t);
+                f_string_ranges_t except_in = f_string_ranges_t_initialize;
+
+                if (flag & F_print_format_flag_ignore_range_d) {
+                  except_in = va_arg(apl, f_string_ranges_t);
+                }
+
+                if (flag & F_print_format_flag_trim_d) {
+                  *status = private_fl_print_trim_except_in_raw_safely(value.string, 0, value.used, except_at, except_in, stream);
+                }
+                else {
+                  *status = f_print_except_in_dynamic_raw_safely(value, except_at, except_in, stream);
+                }
               }
-              else if (*(string + 2) == f_string_ascii_g_s.string[0]) {
-                flag |= F_print_format_flag_exponent_either_d;
-                string += 2;
-              }
-              else if (*(string + 2) == f_string_ascii_G_s.string[0]) {
-                flag |= F_print_format_flag_exponent_either_d | F_print_format_flag_exponent_upper_d;
-                string += 2;
+              else if (flag & F_print_format_flag_ignore_range_d) {
+                const f_array_lengths_t except_at = f_array_lengths_t_initialize;
+                const f_string_ranges_t except_in = va_arg(apl, f_string_ranges_t);
+
+                if (flag & F_print_format_flag_trim_d) {
+                  *status = private_fl_print_trim_except_in_raw_safely(value.string, 0, value.used, except_at, except_in, stream);
+                }
+                else {
+                  *status = f_print_except_in_dynamic_raw_safely(value, except_at, except_in, stream);
+                }
               }
               else {
-                ++string;
+                if (flag & F_print_format_flag_trim_d) {
+                  *status = private_fl_print_trim_raw_safely(value.string, value.used, stream);
+                }
+                else {
+                  *status = f_print_dynamic_raw_safely(value, stream);
+                }
               }
-            }
-            else if (*(string + 1) == f_string_ascii_e_s.string[0]) {
-              flag |= F_print_format_flag_exponent_d;
-              ++string;
-            }
-            else if (*(string + 1) == f_string_ascii_E_s.string[0]) {
-              flag |= F_print_format_flag_exponent_d | F_print_format_flag_exponent_upper_d;
-              ++string;
-            }
-            else if (*(string + 1) == f_string_ascii_g_s.string[0]) {
-              flag |= F_print_format_flag_exponent_either_d;
-              ++string;
-            }
-            else if (*(string + 1) == f_string_ascii_G_s.string[0]) {
-              flag |= F_print_format_flag_exponent_either_d | F_print_format_flag_exponent_upper_d;
-              ++string;
-            }
-          }
-        }
-        else if (*string == f_string_ascii_i_s.string[0]) {
-          type = f_print_format_type_signed_32_e;
 
-          if (*(string + 1) == f_string_ascii_i_s.string[0]) {
-            if (*(string + 2) == f_string_ascii_i_s.string[0]) {
-              type = f_print_format_type_signed_8_e;
-              string += 2;
+              break;
             }
-            else {
-              type = f_print_format_type_signed_16_e;
-              ++string;
-            }
-          }
-          else if (*(string + 1) == f_string_ascii_l_s.string[0]) {
-            if (*(string + 2) == f_string_ascii_l_s.string[0]) {
-              type = f_print_format_type_signed_128_e;
-              string += 2;
-            }
-            else {
-              type = f_print_format_type_signed_64_e;
-              ++string;
-            }
-          }
-          else if (*(string + 1) == f_string_ascii_n_s.string[0]) {
-            type = f_print_format_type_signed_number_e;
-            ++string;
-          }
-        }
-        else if (*string == f_string_ascii_q_s.string[0]) {
-          const f_string_static_t value = va_arg(*ap, f_string_static_t);
-
-          if (flag & F_print_format_flag_range_d) {
-            const f_string_range_t partial = va_arg(*ap, f_string_range_t);
-
-            if (flag & F_print_format_flag_ignore_index_d) {
-              const f_array_lengths_t except_at = va_arg(*ap, f_array_lengths_t);
-              f_string_ranges_t except_in = f_string_ranges_t_initialize;
-
-              if (flag & F_print_format_flag_ignore_range_d) {
-                except_in = va_arg(*ap, f_string_ranges_t);
-              }
+            else if (*string == f_string_ascii_S_s.string[0]) {
+              const f_string_t value = va_arg(apl, f_string_t);
 
-              if (partial.start > partial.stop) {
-                *status = F_data_not;
+              *status = f_print_safely_terminated(value, stream);
 
-                return string;
-              }
-
-              f_array_length_t length = (partial.stop - partial.start) + 1;
-
-              if (length + partial.start > value.used) {
-                length = value.used - partial.start;
-              }
-
-              if (flag & F_print_format_flag_trim_d) {
-                *status = private_fl_print_trim_except_in(value.string, partial.start, length, except_at, except_in, stream);
-              }
-              else {
-                *status = f_print_except_in(value.string, partial.start, length, except_at, except_in, stream);
-              }
+              break;
             }
-            else if (flag & F_print_format_flag_ignore_range_d) {
-              const f_array_lengths_t except_at = f_array_lengths_t_initialize;
-              const f_string_ranges_t except_in = va_arg(*ap, f_string_ranges_t);
+            else if (*string == f_string_ascii_U_s.string[0]) {
+              type = f_print_format_type_unsigned_32_e;
+              flag |= F_print_format_flag_uppercase_d;
 
-              if (partial.start > partial.stop) {
-                *status = F_data_not;
-
-                return string;
+              if (*(string + 1) == f_string_ascii_I_s.string[0]) {
+                if (*(string + 2) == f_string_ascii_I_s.string[0]) {
+                  type = f_print_format_type_unsigned_8_e;
+                  string += 2;
+                }
+                else {
+                  type = f_print_format_type_unsigned_16_e;
+                  ++string;
+                }
               }
-
-              f_array_length_t length = (partial.stop - partial.start) + 1;
-
-              if (length + partial.start > value.used) {
-                length = value.used - partial.start;
+              else if (*(string + 1) == f_string_ascii_L_s.string[0]) {
+                if (*(string + 2) == f_string_ascii_L_s.string[0]) {
+                  type = f_print_format_type_unsigned_128_e;
+                  string += 2;
+                }
+                else {
+                  type = f_print_format_type_unsigned_64_e;
+                  ++string;
+                }
               }
-
-              if (flag & F_print_format_flag_trim_d) {
-                *status = private_fl_print_trim_except_in(value.string, partial.start, length, except_at, except_in, stream);
-              }
-              else {
-                *status = f_print_except_in(value.string, partial.start, length, except_at, except_in, stream);
+              else if (*(string + 1) == f_string_ascii_N_s.string[0]) {
+                type = f_print_format_type_unsigned_number_e;
+                ++string;
               }
             }
             else {
-              const f_array_lengths_t except_at = f_array_lengths_t_initialize;
-              const f_string_ranges_t except_in = va_arg(*ap, f_string_ranges_t);
+              *status = F_status_set_error(F_valid_not);
 
-              if (partial.start > partial.stop) {
-                *status = F_data_not;
+              break;
+            }
+          }
+          else if (*string < 0x60) {
+            if (*string == f_string_ascii_Z_s.string[0]) {
+              type = f_print_format_type_size_e;
+              flag |= F_print_format_flag_uppercase_d;
+            }
+            else if (*string == f_string_ascii_bracket_open_s.string[0]) {
+              const f_color_set_t value = va_arg(apl, f_color_set_t);
 
-                return string;
+              if (value.before) {
+                *status = f_print_dynamic_raw(*value.before, stream);
               }
 
-              f_array_length_t length = (partial.stop - partial.start) + 1;
+              break;
+            }
+            else if (*string == f_string_ascii_bracket_close_s.string[0]) {
+              const f_color_set_t value = va_arg(apl, f_color_set_t);
 
-              if (length + partial.start > value.used) {
-                length = value.used - partial.start;
+              if (value.after) {
+                *status = f_print_dynamic_raw(*value.after, stream);
               }
 
-              if (flag & F_print_format_flag_trim_d) {
-                *status = private_fl_print_trim(value.string + partial.start, length, stream);
-              }
-              else {
-                *status = f_print(value.string + partial.start, length, stream);
-              }
+              break;
             }
-          }
-          else if (flag & F_print_format_flag_ignore_index_d) {
-            const f_array_lengths_t except_at = va_arg(*ap, f_array_lengths_t);
-            f_string_ranges_t except_in = f_string_ranges_t_initialize;
+            else if (*string == f_string_ascii_caret_s.string[0]) {
+              base = 10;
 
-            if (flag & F_print_format_flag_ignore_range_d) {
-              except_in = va_arg(*ap, f_string_ranges_t);
+              continue;
             }
+            else if (*string == f_string_ascii_underscore_s.string[0]) {
+              base = 16;
 
-            if (flag & F_print_format_flag_trim_d) {
-              *status = private_fl_print_trim_except_in(value.string, 0, value.used, except_at, except_in, stream);
+              continue;
             }
             else {
-              *status = f_print_except_in_dynamic(value, except_at, except_in, stream);
-            }
-          }
-          else if (flag & F_print_format_flag_ignore_range_d) {
-            const f_array_lengths_t except_at = f_array_lengths_t_initialize;
-            const f_string_ranges_t except_in = va_arg(*ap, f_string_ranges_t);
+              *status = F_status_set_error(F_valid_not);
 
-            if (flag & F_print_format_flag_trim_d) {
-              *status = private_fl_print_trim_except_in(value.string, 0, value.used, except_at, except_in, stream);
-            }
-            else {
-              *status = f_print_except_in_dynamic(value, except_at, except_in, stream);
-            }
-          }
-          else {
-            if (flag & F_print_format_flag_trim_d) {
-              *status = private_fl_print_trim(value.string, value.used, stream);
-            }
-            else {
-              *status = f_print_dynamic(value, stream);
+              break;
             }
           }
+          else if (*string < 0x72) {
+            if (*string == f_string_ascii_c_s.string[0]) {
+              const char value = (char) va_arg(apl, uint32_t);
 
-          return string;
-        }
-        else {
-          *status = F_status_set_error(F_valid_not);
-
-          return string;
-        }
-      }
-      else {
-        if (*string == f_string_ascii_r_s.string[0]) {
-          const f_string_static_t value = va_arg(*ap, f_string_static_t);
-
-          if (flag & F_print_format_flag_range_d) {
-            const f_string_range_t partial = va_arg(*ap, f_string_range_t);
-
-            if (flag & F_print_format_flag_ignore_index_d) {
-              const f_array_lengths_t except_at = va_arg(*ap, f_array_lengths_t);
-              f_string_ranges_t except_in = f_string_ranges_t_initialize;
-
-              if (flag & F_print_format_flag_ignore_range_d) {
-                except_in = va_arg(*ap, f_string_ranges_t);
+              if (!fputc_unlocked(value, stream)) {
+                *status = F_status_set_error(F_output);
               }
 
-              if (partial.start > partial.stop) {
-                *status = F_data_not;
-
-                return string;
+              break;
+            }
+            else if (*string == f_string_ascii_d_s.string[0]) {
+              type = f_print_format_type_double_32_e;
+
+              if (*(string + 1)) {
+                if (*(string + 1) == f_string_ascii_L_s.string[0]) {
+                  type = f_print_format_type_double_64_e;
+
+                  if (*(string + 2) == f_string_ascii_e_s.string[0]) {
+                    flag |= F_print_format_flag_exponent_d;
+                    string += 2;
+                  }
+                  else if (*(string + 2) == f_string_ascii_E_s.string[0]) {
+                    flag |= F_print_format_flag_exponent_d | F_print_format_flag_exponent_upper_d;
+                    string += 2;
+                  }
+                  else if (*(string + 2) == f_string_ascii_g_s.string[0]) {
+                    flag |= F_print_format_flag_exponent_either_d;
+                    string += 2;
+                  }
+                  else if (*(string + 2) == f_string_ascii_G_s.string[0]) {
+                    flag |= F_print_format_flag_exponent_either_d | F_print_format_flag_exponent_upper_d;
+                    string += 2;
+                  }
+                  else {
+                    ++string;
+                  }
+                }
+                else if (*(string + 1) == f_string_ascii_e_s.string[0]) {
+                  flag |= F_print_format_flag_exponent_d;
+                  ++string;
+                }
+                else if (*(string + 1) == f_string_ascii_E_s.string[0]) {
+                  flag |= F_print_format_flag_exponent_d | F_print_format_flag_exponent_upper_d;
+                  ++string;
+                }
+                else if (*(string + 1) == f_string_ascii_g_s.string[0]) {
+                  flag |= F_print_format_flag_exponent_either_d;
+                  ++string;
+                }
+                else if (*(string + 1) == f_string_ascii_G_s.string[0]) {
+                  flag |= F_print_format_flag_exponent_either_d | F_print_format_flag_exponent_upper_d;
+                  ++string;
+                }
               }
-
-              f_array_length_t length = (partial.stop - partial.start) + 1;
-
-              if (length + partial.start > value.used) {
-                length = value.used - partial.start;
+            }
+            else if (*string == f_string_ascii_i_s.string[0]) {
+              type = f_print_format_type_signed_32_e;
+
+              if (*(string + 1) == f_string_ascii_i_s.string[0]) {
+                if (*(string + 2) == f_string_ascii_i_s.string[0]) {
+                  type = f_print_format_type_signed_8_e;
+                  string += 2;
+                }
+                else {
+                  type = f_print_format_type_signed_16_e;
+                  ++string;
+                }
               }
-
-              if (flag & F_print_format_flag_trim_d) {
-                *status = private_fl_print_trim_except_in_raw(value.string, partial.start, length, except_at, except_in, stream);
+              else if (*(string + 1) == f_string_ascii_l_s.string[0]) {
+                if (*(string + 2) == f_string_ascii_l_s.string[0]) {
+                  type = f_print_format_type_signed_128_e;
+                  string += 2;
+                }
+                else {
+                  type = f_print_format_type_signed_64_e;
+                  ++string;
+                }
               }
-              else {
-                *status = f_print_except_in_raw(value.string, partial.start, length, except_at, except_in, stream);
+              else if (*(string + 1) == f_string_ascii_n_s.string[0]) {
+                type = f_print_format_type_signed_number_e;
+                ++string;
               }
             }
-            else if (flag & F_print_format_flag_ignore_range_d) {
-              const f_array_lengths_t except_at = f_array_lengths_t_initialize;
-              const f_string_ranges_t except_in = va_arg(*ap, f_string_ranges_t);
-
-              if (partial.start > partial.stop) {
-                *status = F_data_not;
-
-                return string;
+            else if (*string == f_string_ascii_q_s.string[0]) {
+              const f_string_static_t value = va_arg(apl, f_string_static_t);
+
+              if (flag & F_print_format_flag_range_d) {
+                const f_string_range_t partial = va_arg(apl, f_string_range_t);
+
+                if (flag & F_print_format_flag_ignore_index_d) {
+                  const f_array_lengths_t except_at = va_arg(apl, f_array_lengths_t);
+                  f_string_ranges_t except_in = f_string_ranges_t_initialize;
+
+                  if (flag & F_print_format_flag_ignore_range_d) {
+                    except_in = va_arg(apl, f_string_ranges_t);
+                  }
+
+                  if (partial.start > partial.stop) {
+                    *status = F_data_not;
+
+                    break;
+                  }
+
+                  f_array_length_t length = (partial.stop - partial.start) + 1;
+
+                  if (length + partial.start > value.used) {
+                    length = value.used - partial.start;
+                  }
+
+                  if (flag & F_print_format_flag_trim_d) {
+                    *status = private_fl_print_trim_except_in(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                  else {
+                    *status = f_print_except_in(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                }
+                else if (flag & F_print_format_flag_ignore_range_d) {
+                  const f_array_lengths_t except_at = f_array_lengths_t_initialize;
+                  const f_string_ranges_t except_in = va_arg(apl, f_string_ranges_t);
+
+                  if (partial.start > partial.stop) {
+                    *status = F_data_not;
+
+                    break;
+                  }
+
+                  f_array_length_t length = (partial.stop - partial.start) + 1;
+
+                  if (length + partial.start > value.used) {
+                    length = value.used - partial.start;
+                  }
+
+                  if (flag & F_print_format_flag_trim_d) {
+                    *status = private_fl_print_trim_except_in(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                  else {
+                    *status = f_print_except_in(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                }
+                else {
+                  const f_array_lengths_t except_at = f_array_lengths_t_initialize;
+                  const f_string_ranges_t except_in = va_arg(apl, f_string_ranges_t);
+
+                  if (partial.start > partial.stop) {
+                    *status = F_data_not;
+
+                    break;
+                  }
+
+                  f_array_length_t length = (partial.stop - partial.start) + 1;
+
+                  if (length + partial.start > value.used) {
+                    length = value.used - partial.start;
+                  }
+
+                  if (flag & F_print_format_flag_trim_d) {
+                    *status = private_fl_print_trim(value.string + partial.start, length, stream);
+                  }
+                  else {
+                    *status = f_print(value.string + partial.start, length, stream);
+                  }
+                }
               }
-
-              f_array_length_t length = (partial.stop - partial.start) + 1;
-
-              if (length + partial.start > value.used) {
-                length = value.used - partial.start;
+              else if (flag & F_print_format_flag_ignore_index_d) {
+                const f_array_lengths_t except_at = va_arg(apl, f_array_lengths_t);
+                f_string_ranges_t except_in = f_string_ranges_t_initialize;
+
+                if (flag & F_print_format_flag_ignore_range_d) {
+                  except_in = va_arg(apl, f_string_ranges_t);
+                }
+
+                if (flag & F_print_format_flag_trim_d) {
+                  *status = private_fl_print_trim_except_in(value.string, 0, value.used, except_at, except_in, stream);
+                }
+                else {
+                  *status = f_print_except_in_dynamic(value, except_at, except_in, stream);
+                }
               }
-
-              if (flag & F_print_format_flag_trim_d) {
-                *status = private_fl_print_trim_except_in_raw(value.string, partial.start, length, except_at, except_in, stream);
+              else if (flag & F_print_format_flag_ignore_range_d) {
+                const f_array_lengths_t except_at = f_array_lengths_t_initialize;
+                const f_string_ranges_t except_in = va_arg(apl, f_string_ranges_t);
+
+                if (flag & F_print_format_flag_trim_d) {
+                  *status = private_fl_print_trim_except_in(value.string, 0, value.used, except_at, except_in, stream);
+                }
+                else {
+                  *status = f_print_except_in_dynamic(value, except_at, except_in, stream);
+                }
               }
               else {
-                *status = f_print_except_in_raw(value.string, partial.start, length, except_at, except_in, stream);
+                if (flag & F_print_format_flag_trim_d) {
+                  *status = private_fl_print_trim(value.string, value.used, stream);
+                }
+                else {
+                  *status = f_print_dynamic(value, stream);
+                }
               }
+
+              break;
             }
             else {
-              const f_array_lengths_t except_at = f_array_lengths_t_initialize;
-              const f_string_ranges_t except_in = va_arg(*ap, f_string_ranges_t);
-
-              if (partial.start > partial.stop) {
-                *status = F_data_not;
+              *status = F_status_set_error(F_valid_not);
 
-                return string;
+              break;
+            }
+          }
+          else {
+            if (*string == f_string_ascii_r_s.string[0]) {
+              const f_string_static_t value = va_arg(apl, f_string_static_t);
+
+              if (flag & F_print_format_flag_range_d) {
+                const f_string_range_t partial = va_arg(apl, f_string_range_t);
+
+                if (flag & F_print_format_flag_ignore_index_d) {
+                  const f_array_lengths_t except_at = va_arg(apl, f_array_lengths_t);
+                  f_string_ranges_t except_in = f_string_ranges_t_initialize;
+
+                  if (flag & F_print_format_flag_ignore_range_d) {
+                    except_in = va_arg(apl, f_string_ranges_t);
+                  }
+
+                  if (partial.start > partial.stop) {
+                    *status = F_data_not;
+
+                    break;
+                  }
+
+                  f_array_length_t length = (partial.stop - partial.start) + 1;
+
+                  if (length + partial.start > value.used) {
+                    length = value.used - partial.start;
+                  }
+
+                  if (flag & F_print_format_flag_trim_d) {
+                    *status = private_fl_print_trim_except_in_raw(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                  else {
+                    *status = f_print_except_in_raw(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                }
+                else if (flag & F_print_format_flag_ignore_range_d) {
+                  const f_array_lengths_t except_at = f_array_lengths_t_initialize;
+                  const f_string_ranges_t except_in = va_arg(apl, f_string_ranges_t);
+
+                  if (partial.start > partial.stop) {
+                    *status = F_data_not;
+
+                    break;
+                  }
+
+                  f_array_length_t length = (partial.stop - partial.start) + 1;
+
+                  if (length + partial.start > value.used) {
+                    length = value.used - partial.start;
+                  }
+
+                  if (flag & F_print_format_flag_trim_d) {
+                    *status = private_fl_print_trim_except_in_raw(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                  else {
+                    *status = f_print_except_in_raw(value.string, partial.start, length, except_at, except_in, stream);
+                  }
+                }
+                else {
+                  const f_array_lengths_t except_at = f_array_lengths_t_initialize;
+                  const f_string_ranges_t except_in = va_arg(apl, f_string_ranges_t);
+
+                  if (partial.start > partial.stop) {
+                    *status = F_data_not;
+
+                    break;
+                  }
+
+                  f_array_length_t length = (partial.stop - partial.start) + 1;
+
+                  if (length + partial.start > value.used) {
+                    length = value.used - partial.start;
+                  }
+
+                  if (flag & F_print_format_flag_trim_d) {
+                    *status = private_fl_print_trim_raw(value.string + partial.start, length, stream);
+                  }
+                  else {
+                    *status = f_print_raw(value.string + partial.start, length, stream);
+                  }
+                }
               }
-
-              f_array_length_t length = (partial.stop - partial.start) + 1;
-
-              if (length + partial.start > value.used) {
-                length = value.used - partial.start;
+              else if (flag & F_print_format_flag_ignore_index_d) {
+                const f_array_lengths_t except_at = va_arg(apl, f_array_lengths_t);
+                f_string_ranges_t except_in = f_string_ranges_t_initialize;
+
+                if (flag & F_print_format_flag_ignore_range_d) {
+                  except_in = va_arg(apl, f_string_ranges_t);
+                }
+
+                if (flag & F_print_format_flag_trim_d) {
+                  *status = private_fl_print_trim_except_in_raw(value.string, 0, value.used, except_at, except_in, stream);
+                }
+                else {
+                  *status = f_print_except_in_dynamic_raw(value, except_at, except_in, stream);
+                }
               }
-
-              if (flag & F_print_format_flag_trim_d) {
-                *status = private_fl_print_trim_raw(value.string + partial.start, length, stream);
+              else if (flag & F_print_format_flag_ignore_range_d) {
+                const f_array_lengths_t except_at = f_array_lengths_t_initialize;
+                const f_string_ranges_t except_in = va_arg(apl, f_string_ranges_t);
+
+                if (flag & F_print_format_flag_trim_d) {
+                  *status = private_fl_print_trim_except_in_raw(value.string, 0, value.used, except_at, except_in, stream);
+                }
+                else {
+                  *status = f_print_except_in_dynamic_raw(value, except_at, except_in, stream);
+                }
               }
               else {
-                *status = f_print_raw(value.string + partial.start, length, stream);
+                if (flag & F_print_format_flag_trim_d) {
+                  *status = private_fl_print_trim_raw(value.string, value.used, stream);
+                }
+                else {
+                  *status = f_print_dynamic_raw(value, stream);
+                }
               }
-            }
-          }
-          else if (flag & F_print_format_flag_ignore_index_d) {
-            const f_array_lengths_t except_at = va_arg(*ap, f_array_lengths_t);
-            f_string_ranges_t except_in = f_string_ranges_t_initialize;
 
-            if (flag & F_print_format_flag_ignore_range_d) {
-              except_in = va_arg(*ap, f_string_ranges_t);
+              break;
             }
+            else if (*string == f_string_ascii_s_s.string[0]) {
+              const f_string_t value = va_arg(apl, f_string_t);
 
-            if (flag & F_print_format_flag_trim_d) {
-              *status = private_fl_print_trim_except_in_raw(value.string, 0, value.used, except_at, except_in, stream);
-            }
-            else {
-              *status = f_print_except_in_dynamic_raw(value, except_at, except_in, stream);
-            }
-          }
-          else if (flag & F_print_format_flag_ignore_range_d) {
-            const f_array_lengths_t except_at = f_array_lengths_t_initialize;
-            const f_string_ranges_t except_in = va_arg(*ap, f_string_ranges_t);
+              *status = f_print_terminated(value, stream);
 
-            if (flag & F_print_format_flag_trim_d) {
-              *status = private_fl_print_trim_except_in_raw(value.string, 0, value.used, except_at, except_in, stream);
-            }
-            else {
-              *status = f_print_except_in_dynamic_raw(value, except_at, except_in, stream);
-            }
-          }
-          else {
-            if (flag & F_print_format_flag_trim_d) {
-              *status = private_fl_print_trim_raw(value.string, value.used, stream);
-            }
-            else {
-              *status = f_print_dynamic_raw(value, stream);
+              break;
             }
-          }
-
-          return string;
-        }
-        else if (*string == f_string_ascii_s_s.string[0]) {
-          const f_string_t value = va_arg(*ap, f_string_t);
+            else if (*string == f_string_ascii_u_s.string[0]) {
+              type = f_print_format_type_unsigned_32_e;
 
-          *status = f_print_terminated(value, stream);
-
-          return string;
-        }
-        else if (*string == f_string_ascii_u_s.string[0]) {
-          type = f_print_format_type_unsigned_32_e;
-
-          if (*(string + 1) == f_string_ascii_i_s.string[0]) {
-            if (*(string + 2) == f_string_ascii_i_s.string[0]) {
-              type = f_print_format_type_unsigned_8_e;
-              string += 2;
-            }
-            else {
-              type = f_print_format_type_unsigned_16_e;
-              ++string;
+              if (*(string + 1) == f_string_ascii_i_s.string[0]) {
+                if (*(string + 2) == f_string_ascii_i_s.string[0]) {
+                  type = f_print_format_type_unsigned_8_e;
+                  string += 2;
+                }
+                else {
+                  type = f_print_format_type_unsigned_16_e;
+                  ++string;
+                }
+              }
+              else if (*(string + 1) == f_string_ascii_l_s.string[0]) {
+                if (*(string + 2) == f_string_ascii_l_s.string[0]) {
+                  type = f_print_format_type_unsigned_128_e;
+                  string += 2;
+                }
+                else {
+                  type = f_print_format_type_unsigned_64_e;
+                  ++string;
+                }
+              }
+              else if (*(string + 1) == f_string_ascii_n_s.string[0]) {
+                type = f_print_format_type_unsigned_number_e;
+                ++string;
+              }
             }
-          }
-          else if (*(string + 1) == f_string_ascii_l_s.string[0]) {
-            if (*(string + 2) == f_string_ascii_l_s.string[0]) {
-              type = f_print_format_type_unsigned_128_e;
-              string += 2;
+            else if (*string == f_string_ascii_z_s.string[0]) {
+              type = f_print_format_type_size_e;
             }
             else {
-              type = f_print_format_type_unsigned_64_e;
-              ++string;
+              *status = F_status_set_error(F_valid_not);
+
+              break;
             }
           }
-          else if (*(string + 1) == f_string_ascii_n_s.string[0]) {
-            type = f_print_format_type_unsigned_number_e;
-            ++string;
-          }
-        }
-        else if (*string == f_string_ascii_z_s.string[0]) {
-          type = f_print_format_type_size_e;
-        }
-        else {
-          *status = F_status_set_error(F_valid_not);
-
-          return string;
-        }
-      }
-
-      f_conversion_data_t conversion_data = macro_f_conversion_data_t_initialize(base, 0, 1);
-
-      if (flag & F_print_format_flag_align_left_d) {
-        conversion_data.flag |= F_conversion_data_flag_align_left_d;
-      }
-
-      if (flag & F_print_format_flag_convert_d) {
-        conversion_data.flag |= F_conversion_data_flag_base_prepend_d;
-      }
-
-      if (flag & F_print_format_flag_sign_always_d) {
-        conversion_data.flag |= F_conversion_data_flag_sign_always_d;
-      }
-
-      if (flag & F_print_format_flag_sign_pad_d) {
-        conversion_data.flag |= F_conversion_data_flag_sign_pad_d;
-      }
-
-      if (flag & F_print_format_flag_uppercase_d) {
-        conversion_data.flag |= F_conversion_data_flag_base_upper_d;
-      }
-
-      if (flag & F_print_format_flag_zeros_leading_d) {
-        conversion_data.flag |= F_conversion_data_flag_zeros_leading_d;
-      }
-
-      if (flag & F_print_format_flag_width_value_d) {
-        width = va_arg(*ap, int);
-      }
 
-      if (flag & F_print_format_flag_precision_value_d) {
-        precision = va_arg(*ap, int);
-      }
+          f_conversion_data_t conversion_data = macro_f_conversion_data_t_initialize(base, 0, 1);
 
-      // @fixme precision and width can be used together, see: "'%10.2f'".
-      if (flag & F_print_format_flag_width_d) {
-        conversion_data.width = width;
-      }
-      else if (flag & F_print_format_flag_precision_d) {
-        conversion_data.width = precision;
-      }
+          if (flag & F_print_format_flag_align_left_d) {
+            conversion_data.flag |= F_conversion_data_flag_align_left_d;
+          }
 
-      if (type == f_print_format_type_signed_8_e) {
-        const int8_t value = (int8_t) va_arg(*ap, int);
+          if (flag & F_print_format_flag_convert_d) {
+            conversion_data.flag |= F_conversion_data_flag_base_prepend_d;
+          }
 
-        *status = f_conversion_number_signed_print((f_number_signed_t) value, conversion_data, stream);
-      }
-      else if (type == f_print_format_type_signed_16_e) {
-        const int16_t value = (int16_t) va_arg(*ap, int);
+          if (flag & F_print_format_flag_sign_always_d) {
+            conversion_data.flag |= F_conversion_data_flag_sign_always_d;
+          }
 
-        *status = f_conversion_number_signed_print((f_number_signed_t) value, conversion_data, stream);
-      }
-      else if (type == f_print_format_type_signed_32_e) {
-        *status = f_conversion_number_signed_print((f_number_signed_t) va_arg(*ap, int32_t), conversion_data, stream);
-      }
-      else if (type == f_print_format_type_signed_64_e) {
-        *status = f_conversion_number_signed_print((f_number_signed_t) va_arg(*ap, int64_t), conversion_data, stream);
-      }
-      else if (type == f_print_format_type_signed_128_e) {
-        *status = f_conversion_number_signed_print((f_number_signed_t) va_arg(*ap, f_int_128_t), conversion_data, stream);
-      }
-      else if (type == f_print_format_type_signed_number_e) {
-        *status = f_conversion_number_signed_print(va_arg(*ap, f_number_signed_t), conversion_data, stream);
-      }
-      else if (type == f_print_format_type_size_e) {
-        *status = f_conversion_number_unsigned_print((f_number_unsigned_t) va_arg(*ap, size_t), conversion_data, stream);
-      }
-      else if (type == f_print_format_type_unsigned_8_e) {
-        const uint8_t value = (uint8_t) va_arg(*ap, unsigned);
+          if (flag & F_print_format_flag_sign_pad_d) {
+            conversion_data.flag |= F_conversion_data_flag_sign_pad_d;
+          }
 
-        *status = f_conversion_number_unsigned_print((f_number_unsigned_t) value, conversion_data, stream);
-      }
-      else if (type == f_print_format_type_unsigned_16_e) {
-        const uint16_t value = (uint16_t) va_arg(*ap, unsigned);
+          if (flag & F_print_format_flag_uppercase_d) {
+            conversion_data.flag |= F_conversion_data_flag_base_upper_d;
+          }
 
-        *status = f_conversion_number_unsigned_print((f_number_unsigned_t) value, conversion_data, stream);
-      }
-      else if (type == f_print_format_type_unsigned_32_e) {
-        *status = f_conversion_number_unsigned_print((f_number_unsigned_t) va_arg(*ap, uint32_t), conversion_data, stream);
-      }
-      else if (type == f_print_format_type_unsigned_64_e) {
-        *status = f_conversion_number_unsigned_print((f_number_unsigned_t) va_arg(*ap, uint64_t), conversion_data, stream);
-      }
-      else if (type == f_print_format_type_unsigned_128_e) {
-        *status = f_conversion_number_unsigned_print((f_number_unsigned_t) va_arg(*ap, f_uint_128_t), conversion_data, stream);
-      }
-      else if (type == f_print_format_type_unsigned_number_e) {
-        *status = f_conversion_number_unsigned_print(va_arg(*ap, f_number_unsigned_t), conversion_data, stream);
-      }
-      else if (type == f_print_format_type_double_32_e || type == f_print_format_type_double_64_e) {
-        int f = 0;
-        char format[33];
-        char buffer[129];
+          if (flag & F_print_format_flag_zeros_leading_d) {
+            conversion_data.flag |= F_conversion_data_flag_zeros_leading_d;
+          }
 
-        memset(format, 0, 33);
-        memset(buffer, 0, 129);
+          if (flag & F_print_format_flag_width_value_d) {
+            width = va_arg(apl, int);
+          }
 
-        format[f++] = f_string_ascii_percent_s.string[0];
+          if (flag & F_print_format_flag_precision_value_d) {
+            precision = va_arg(apl, int);
+          }
 
-        if (flag & F_print_format_flag_sign_always_d) {
-          format[f++] = f_string_ascii_plus_s.string[0];
-        }
-        else if (flag & F_print_format_flag_sign_pad_d) {
-          format[f++] = f_string_ascii_space_s.string[0];
-        }
+          // @fixme precision and width can be used together, see: "'%10.2f'".
+          if (flag & F_print_format_flag_width_d) {
+            conversion_data.width = width;
+          }
+          else if (flag & F_print_format_flag_precision_d) {
+            conversion_data.width = precision;
+          }
 
-        if (flag & F_print_format_flag_align_left_d) {
-          format[f++] = f_string_ascii_minus_s.string[0];
-        }
+          if (type == f_print_format_type_signed_8_e) {
+            const int8_t value = (int8_t) va_arg(apl, signed int);
 
-        if (flag & F_print_format_flag_zeros_leading_d) {
-          format[f++] = f_string_ascii_0_s.string[0];
-        }
+            *status = f_conversion_number_signed_print((f_number_signed_t) value, conversion_data, stream);
+          }
+          else if (type == f_print_format_type_signed_16_e) {
+            const int16_t value = (int16_t) va_arg(apl, signed int);
 
-        if (flag & F_print_format_flag_width_d) {
-          format[f++] = f_string_ascii_asterisk_s.string[0];
-        }
+            *status = f_conversion_number_signed_print((f_number_signed_t) value, conversion_data, stream);
+          }
+          else if (type == f_print_format_type_signed_32_e) {
+            *status = f_conversion_number_signed_print((f_number_signed_t) va_arg(apl, int32_t), conversion_data, stream);
+          }
+          else if (type == f_print_format_type_signed_64_e) {
+            *status = f_conversion_number_signed_print((f_number_signed_t) va_arg(apl, int64_t), conversion_data, stream);
+          }
+          else if (type == f_print_format_type_signed_128_e) {
+            *status = f_conversion_number_signed_print((f_number_signed_t) va_arg(apl, f_int_128_t), conversion_data, stream);
+          }
+          else if (type == f_print_format_type_signed_number_e) {
+            *status = f_conversion_number_signed_print(va_arg(apl, f_number_signed_t), conversion_data, stream);
+          }
+          else if (type == f_print_format_type_size_e) {
+            *status = f_conversion_number_unsigned_print((f_number_unsigned_t) va_arg(apl, size_t), conversion_data, stream);
+          }
+          else if (type == f_print_format_type_unsigned_8_e) {
+            const uint8_t value = (uint8_t) va_arg(apl, unsigned int);
 
-        if (flag & F_print_format_flag_precision_d) {
-          format[f++] = f_string_ascii_period_s.string[0];
-          format[f++] = f_string_ascii_asterisk_s.string[0];
-        }
+            *status = f_conversion_number_unsigned_print((f_number_unsigned_t) value, conversion_data, stream);
+          }
+          else if (type == f_print_format_type_unsigned_16_e) {
+            const uint16_t value = (uint16_t) va_arg(apl, unsigned int);
 
-        if (flag & F_print_format_flag_exponent_d) {
-          if (flag & F_print_format_flag_exponent_upper_d) {
-            format[f++] = f_string_ascii_E_s.string[0];
+            *status = f_conversion_number_unsigned_print((f_number_unsigned_t) value, conversion_data, stream);
           }
-          else {
-            format[f++] = f_string_ascii_e_s.string[0];
+          else if (type == f_print_format_type_unsigned_32_e) {
+            *status = f_conversion_number_unsigned_print((f_number_unsigned_t) va_arg(apl, uint32_t), conversion_data, stream);
           }
-        }
-        else if (flag & F_print_format_flag_exponent_either_d) {
-          if (flag & F_print_format_flag_exponent_upper_d) {
-            format[f++] = f_string_ascii_G_s.string[0];
+          else if (type == f_print_format_type_unsigned_64_e) {
+            *status = f_conversion_number_unsigned_print((f_number_unsigned_t) va_arg(apl, uint64_t), conversion_data, stream);
           }
-          else {
-            format[f++] = f_string_ascii_g_s.string[0];
+          else if (type == f_print_format_type_unsigned_128_e) {
+            *status = f_conversion_number_unsigned_print((f_number_unsigned_t) va_arg(apl, f_uint_128_t), conversion_data, stream);
           }
-        }
-        else {
-          format[f++] = f_string_ascii_f_s.string[0];
-        }
+          else if (type == f_print_format_type_unsigned_number_e) {
+            *status = f_conversion_number_unsigned_print(va_arg(apl, f_number_unsigned_t), conversion_data, stream);
+          }
+          else if (type == f_print_format_type_double_32_e || type == f_print_format_type_double_64_e) {
+            unsigned int f = 0;
+            char format[33];
+            char buffer[129];
 
-        format[f] = 0;
+            memset(format, 0, 33);
+            memset(buffer, 0, 129);
 
-        if (type == f_print_format_type_double_32_e) {
-          const double value = va_arg(*ap, double);
+            format[f++] = f_string_ascii_percent_s.string[0];
 
-          if (flag & F_print_format_flag_width_d) {
-            if (flag & F_print_format_flag_precision_d) {
-              snprintf(buffer, 128, format, width, precision, value);
+            if (flag & F_print_format_flag_sign_always_d) {
+              format[f++] = f_string_ascii_plus_s.string[0];
             }
-            else {
-              snprintf(buffer, 128, format, width, value);
+            else if (flag & F_print_format_flag_sign_pad_d) {
+              format[f++] = f_string_ascii_space_s.string[0];
+            }
+
+            if (flag & F_print_format_flag_align_left_d) {
+              format[f++] = f_string_ascii_minus_s.string[0];
+            }
+
+            if (flag & F_print_format_flag_zeros_leading_d) {
+              format[f++] = f_string_ascii_0_s.string[0];
+            }
+
+            if (flag & F_print_format_flag_width_d) {
+              format[f++] = f_string_ascii_asterisk_s.string[0];
             }
-          }
-          else if (flag & F_print_format_flag_precision_d) {
-            snprintf(buffer, 128, format, precision, value);
-          }
-          else {
-            snprintf(buffer, 128, format, value);
-          }
-        }
-        else {
-          const long double value = va_arg(*ap, long double);
 
-          if (flag & F_print_format_flag_width_d) {
             if (flag & F_print_format_flag_precision_d) {
-              snprintf(buffer, 128, format, width, precision, value);
+              format[f++] = f_string_ascii_period_s.string[0];
+              format[f++] = f_string_ascii_asterisk_s.string[0];
+            }
+
+            if (flag & F_print_format_flag_exponent_d) {
+              if (flag & F_print_format_flag_exponent_upper_d) {
+                format[f++] = f_string_ascii_E_s.string[0];
+              }
+              else {
+                format[f++] = f_string_ascii_e_s.string[0];
+              }
+            }
+            else if (flag & F_print_format_flag_exponent_either_d) {
+              if (flag & F_print_format_flag_exponent_upper_d) {
+                format[f++] = f_string_ascii_G_s.string[0];
+              }
+              else {
+                format[f++] = f_string_ascii_g_s.string[0];
+              }
             }
             else {
-              snprintf(buffer, 128, format, width, value);
+              format[f++] = f_string_ascii_f_s.string[0];
             }
-          }
-          else if (flag & F_print_format_flag_precision_d) {
-            snprintf(buffer, 128, format, precision, value);
-          }
-          else {
-            snprintf(buffer, 128, format, value);
-          }
-        }
 
-        *status = f_print_terminated(buffer, stream);
-      }
+            if (type == f_print_format_type_double_32_e) {
+              const double value = va_arg(apl, double);
 
-      return string;
-    } // for
+              if (flag & F_print_format_flag_width_d) {
+                if (flag & F_print_format_flag_precision_d) {
+                  snprintf(buffer, 128, format, width, precision, value);
+                }
+                else {
+                  snprintf(buffer, 128, format, width, value);
+                }
+              }
+              else if (flag & F_print_format_flag_precision_d) {
+                snprintf(buffer, 128, format, precision, value);
+              }
+              else {
+                snprintf(buffer, 128, format, value);
+              }
+            }
+            else {
+              const long double value = va_arg(apl, long double);
+
+              if (flag & F_print_format_flag_width_d) {
+                if (flag & F_print_format_flag_precision_d) {
+                  snprintf(buffer, 128, format, width, precision, value);
+                }
+                else {
+                  snprintf(buffer, 128, format, width, value);
+                }
+              }
+              else if (flag & F_print_format_flag_precision_d) {
+                snprintf(buffer, 128, format, precision, value);
+              }
+              else {
+                snprintf(buffer, 128, format, value);
+              }
+            }
 
-    *status = F_status_set_error(F_valid_not);
+            *status = f_print_terminated(buffer, stream);
+          }
 
-    return string;
-  }
-#endif // !defined(_di_fl_print_format_) || !defined(_di_fl_print_format_convert_)
+          va_end(apl);
 
-#if !defined(_di_fl_print_format_) || !defined(_di_fl_print_format_convert_)
-  f_string_t private_fl_print_convert_number(f_string_t string, va_list *ap, unsigned int * const number, f_status_t * const status) {
+          break;
+        } // for
 
-    for (*number = 0; *string; ++string) {
+        if (F_status_is_error(*status)) break;
 
-      if (*string > 0x2f && *string < 0x3a) {
-        *number *= 10;
-        *number += 0xf & *string;
-      }
-      else if (*string == f_string_ascii_asterisk_s.string[0]) {
-        *number = va_arg(*ap, unsigned int);
+        if (!*string) {
+          *status = F_status_set_error(F_valid_not);
 
-        break;
+          break;
+        }
       }
       else {
-
-        // Do not leave string on the non-digit and non-asterisk character.
-        --string;
-
-        break;
+        if (!fputc_unlocked(*string, stream)) break;
       }
     } // for
 
-    // Do not leave string on the terminating NULL.
-    if (!string) {
-      --string;
-    }
+    va_end(apl);
 
     return string;
   }
index 551b42ea23aa91f03355677bd933449e55b15f4e..272c3d2a2065ff3b4eb01d4e51c72574780b9137 100644 (file)
@@ -72,31 +72,7 @@ extern "C" {
  * @see private_fl_print_convert_number()
  */
 #if !defined(_di_fl_print_format_) || !defined(_di_fl_print_format_convert_)
-  extern f_string_t private_fl_print_format_convert(f_string_t string, FILE * const stream, va_list * const ap, f_status_t * const status) F_attribute_visibility_internal_d;
-#endif // !defined(_di_fl_print_format_) || !defined(_di_fl_print_format_convert_)
-
-/**
- * Helper function for processing the number in a convert string.
- *
- * This should be called to convert numbers after a '%', such as the field with or precision.
- *
- * On return the string will point to either the last consecutive character representing a number or the asterisk.
- *
- * @param string
- *   The current character position within the string.
- * @param ap
- *   The variable arguments list.
- * @param number
- *   The converted number.
- *
- * @return
- *   F_true on success and end of string (NULL) is found.
- *   F_false on success without reaching the end of string (NULL).
- *
- * @see va_arg()
- */
-#if !defined(_di_fl_print_format_) || !defined(_di_fl_print_format_convert_)
-  extern f_string_t private_fl_print_convert_number(f_string_t string, va_list * const ap, unsigned int * const number, f_status_t * const status) F_attribute_visibility_internal_d;
+  extern f_string_t private_fl_print_format_convert(f_string_t string, FILE * const stream, va_list ap, f_status_t * const status) F_attribute_visibility_internal_d;
 #endif // !defined(_di_fl_print_format_) || !defined(_di_fl_print_format_convert_)
 
 /**
index ac44e02afed6ab3119e9d149edce2134e87bdcd1..aba71c8121e03c5d608814f80869bf020b824169 100644 (file)
@@ -468,7 +468,7 @@ extern "C" {
 
     va_start(ap, output);
 
-    const f_status_t status = fl_print_string_va(string, output, &ap);
+    const f_status_t status = fl_print_string_va(string, output, ap);
 
     va_end(ap);
 
@@ -479,7 +479,7 @@ extern "C" {
 #endif // _di_fll_print_format_
 
 #ifndef _di_fll_print_format_convert_
-  f_string_t fll_print_format_convert(const f_string_t string, FILE * const output, va_list * const ap, f_status_t * const status) {
+  f_string_t fll_print_format_convert(const f_string_t string, FILE * const output, va_list ap, f_status_t * const status) {
 
     flockfile(output);
 
@@ -557,7 +557,7 @@ extern "C" {
 #endif // _di_fll_print_safely_terminated_
 
 #ifndef _di_fll_print_string_va_
-  f_status_t fll_print_string_va(const f_string_t string, FILE * const output, va_list * const ap) {
+  f_status_t fll_print_string_va(const f_string_t string, FILE * const output, va_list ap) {
 
     flockfile(output);
 
index 45c662a5f09223831541a50fa7f6e0cccf9ed6ff..c8b598dc556a846266afb75ad7acc1ddde8308f5 100644 (file)
@@ -1013,7 +1013,7 @@ extern "C" {
  * @see fl_print_format_convert()
  */
 #ifndef _di_fll_print_format_convert_
-  extern f_string_t fll_print_format_convert(const f_string_t current, FILE * const output, va_list *ap, f_status_t *status);
+  extern f_string_t fll_print_format_convert(const f_string_t current, FILE * const output, va_list ap, f_status_t *status);
 #endif // _di_fll_print_format_convert_
 
 /**
@@ -1156,7 +1156,7 @@ extern "C" {
  * @see fl_print_string_va()
  */
 #ifndef _di_fll_print_string_va_
-  extern f_status_t fll_print_string_va(const f_string_t string, FILE * const output, va_list *ap);
+  extern f_status_t fll_print_string_va(const f_string_t string, FILE * const output, va_list ap);
 #endif // _di_fll_print_string_va_
 
 /**