LIB: Add tfm_vprintf support for left formatting

Add support to the vprintf implementation for left formatting. This
applies to both integer format specifiers and strings. The
implementation also allows us to tidy up the existing integer format
specifier parser.

Change-Id: If7bcc07712a14de76294b9a7a1f6f637380ed714
Signed-off-by: Jackson Cooper-Driver <jackson.cooper-driver@arm.com>
diff --git a/lib/tfm_vprintf/src/tfm_vprintf.c b/lib/tfm_vprintf/src/tfm_vprintf.c
index 3fa0c82..02164ee 100644
--- a/lib/tfm_vprintf/src/tfm_vprintf.c
+++ b/lib/tfm_vprintf/src/tfm_vprintf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2025, Arm Limited. All rights reserved.
+ * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -40,8 +40,19 @@
     output_func(priv, &c, 1);
 }
 
-static void output_str(tfm_log_output_str output_func, void *priv,
-                        const char *str, uint32_t len, bool calculate_length)
+static inline void output_padding_chars(tfm_log_output_str output_func, void *priv,
+                                        uint16_t num_padding, char pad_char)
+{
+    uint16_t i;
+
+    for (i = 0; i < num_padding; i++) {
+        output_char(output_func, priv, pad_char);
+    }
+}
+
+static void output_str(tfm_log_output_str output_func, void *priv, const char *str, uint32_t len,
+                       uint16_t num_padding, bool left_aligned, char pad_char,
+                       bool calculate_length)
 {
     const char *str_ptr = str;
 
@@ -52,20 +63,39 @@
         }
     }
 
+    if (num_padding > len) {
+        num_padding -= len;
+    } else {
+        num_padding = 0;
+    }
+
+    if (!left_aligned) {
+        output_padding_chars(output_func, priv, num_padding, pad_char);
+    }
+
     output_func(priv, str, len);
+
+    if (left_aligned) {
+        output_padding_chars(output_func, priv, num_padding, pad_char);
+    }
+}
+
+static void output_str_not_formatted(tfm_log_output_str output_func, void *priv, const char *str)
+{
+    output_str(output_func, priv, str, 0, 0, false, 0, true);
 }
 
 static void output_val(tfm_log_output_str output_func, void *priv, uint32_t val,
-                        uint16_t num_padding, bool zero_padding, uint8_t base, bool signed_specifier)
+                       uint16_t num_padding, bool zero_padding, bool left_aligned, uint8_t base,
+                       bool signed_specifier)
 {
-    uint8_t digit, chars_to_print;
-    uint16_t i;
+    uint8_t digit;
     /* uint32_t has maximum value of 4,294,967,295. Require enough space in buffer
-     * for 10 digits + null terminator + '-' */
-    char buf[12] = { 0 };
+     * for 10 digits + '-'. Note that the buffer does not need to be NULL terminated
+     * as we pass the string length to output_str */
+    char buf[11] = { 0 };
     char *const buf_end = &buf[sizeof(buf) - 1];
-    /* Leaving space for NULL terminator */
-    char *buf_ptr = buf_end - 1;
+    char *buf_ptr = buf_end;
     const char pad_char = zero_padding ? '0' : ' ';
     const char negative_char = '-';
     bool negative = false;
@@ -95,18 +125,8 @@
         }
     }
 
-    chars_to_print = (buf_end - 1) - buf_ptr;
-    if (num_padding > chars_to_print) {
-        num_padding -= chars_to_print;
-    } else {
-        num_padding = 0;
-    }
-
-    for (i = 0; i < num_padding; i++) {
-        output_char(output_func, priv, pad_char);
-    }
-
-    output_str(output_func, priv, buf_ptr + 1, chars_to_print, false);
+    output_str(output_func, priv, buf_ptr + 1, buf_end - buf_ptr, num_padding, left_aligned,
+               pad_char, false);
 }
 
 /* Basic vprintf, understands:
@@ -122,12 +142,14 @@
     bool formatting = false;
     uint16_t num_padding = 0;
     bool zero_padding = false;
+    bool left_aligned = false;
 
     while ((c = *fmt++) != '\0') {
         if (!formatting) {
             if (c == '%') {
                 zero_padding = false;
                 num_padding = 0;
+                left_aligned = false;
                 formatting = true;
             } else {
                 if (c == '\n') {
@@ -142,17 +164,24 @@
         case 'l':
             continue;
         case 'u':
-            output_val(output_func, priv, va_arg(args, uint32_t), num_padding, zero_padding, 10, false);
+            output_val(output_func, priv, va_arg(args, uint32_t), num_padding, zero_padding,
+                       left_aligned, 10, false);
             break;
         case 'd':
-            output_val(output_func, priv, va_arg(args, uint32_t), num_padding, zero_padding, 10, true);
+            output_val(output_func, priv, va_arg(args, uint32_t), num_padding, zero_padding,
+                       left_aligned, 10, true);
             break;
         case 'x':
-            output_val(output_func, priv, va_arg(args, uint32_t), num_padding, zero_padding, 16, false);
+            output_val(output_func, priv, va_arg(args, uint32_t), num_padding, zero_padding,
+                       left_aligned, 16, false);
             break;
         case 's':
-            output_str(output_func, priv, va_arg(args, char *), 0, true);
+            output_str(output_func, priv, va_arg(args, char *), 0, num_padding, left_aligned, ' ',
+                       true);
             break;
+        case '-':
+            left_aligned = true;
+            continue;
         case '0':
             if (num_padding == 0) {
                 zero_padding = true;
@@ -175,7 +204,7 @@
             output_char(output_func, priv, '%');
             break;
         default:
-            output_str(output_func, priv, "[Unsupported]", 0, true);
+            output_str_not_formatted(output_func, priv, "[Unsupported]");
         }
 
         formatting = false;
@@ -191,7 +220,7 @@
     log_level = fmt[0];
     fmt++;
 
-    output_str(output_func, priv, get_log_prefix(log_level), 0, true);
+    output_str_not_formatted(output_func, priv, get_log_prefix(log_level));
     output_char(output_func, priv, spacer);
 
     tfm_vprintf_internal(output_func, priv, fmt, args);