Selaa lähdekoodia

feat: print long long decimals

greatbridf 3 vuotta sitten
vanhempi
commit
1298cee68d
1 muutettua tiedostoa jossa 116 lisäystä ja 2 poistoa
  1. 116 2
      src/kernel/stdio.c

+ 116 - 2
src/kernel/stdio.c

@@ -3,6 +3,62 @@
 #include <types/size.h>
 #include <types/stdint.h>
 
+#define __32bit_system
+
+#ifdef __32bit_system
+uint64_t do_div(uint64_t a, uint64_t b, uint64_t* remainder)
+{
+    uint64_t r = 0, q = 0;
+    int32_t i;
+    for (i = 0; i < 64; i++) {
+        r = (r << 1) + (a >> 63);
+        a <<= 1;
+        q <<= 1;
+        if (r >= b) {
+            r -= b;
+            q += 1;
+        }
+    }
+    if (remainder)
+        *remainder = r;
+    return q;
+}
+
+int64_t do_div_s(int64_t a, int64_t b, uint64_t* remainder)
+{
+    int32_t qf = 0, rf = 0;
+    if (a < 0) {
+        qf = rf = 1;
+        a = -a;
+    }
+    if (b < 0) {
+        qf ^= 1;
+        b = -b;
+    }
+
+    int64_t quotient = do_div(a, b, (uint64_t*)remainder);
+
+    if (qf)
+        quotient = -quotient;
+    if (remainder && rf)
+        *remainder = -*remainder;
+
+    return quotient;
+}
+
+int64_t __divdi3(int64_t a, int64_t b)
+{
+    return do_div_s(a, b, (uint64_t*)0);
+}
+
+int64_t __moddi3(int64_t a, int64_t b)
+{
+    uint64_t remainder = 0;
+    do_div_s(a, b, &remainder);
+    return remainder;
+}
+#endif
+
 // where n is in the range of [0, 9]
 static inline char d_to_c(int32_t n)
 {
@@ -49,7 +105,7 @@ static inline char X_to_c(int32_t n)
     }
 
 ssize_t
-snprint_decimal(
+snprint_decimal32(
     char* buf,
     size_t buf_size,
     int32_t num)
@@ -89,6 +145,47 @@ snprint_decimal(
     return n_write;
 }
 
+ssize_t
+snprint_decimal64(
+    char* buf,
+    size_t buf_size,
+    int64_t num)
+{
+    ssize_t n_write = 0;
+
+    if (num < 0) {
+        do_write_if_free(buf, buf_size, '-');
+        ++n_write;
+        num *= (-1);
+    }
+
+    char* orig_buf = buf;
+
+    do {
+        do_write_if_free(buf, buf_size, d_to_c(num % 10));
+        num /= 10;
+        ++n_write;
+    } while (num != 0);
+
+    // prepend trailing '\0'
+    if (buf_size > 0)
+        *buf = 0x00;
+
+    // move buf pointer to the last digit of number
+    --buf;
+
+    // reverse output
+    while (orig_buf < buf) {
+        char c = *buf;
+        *buf = *orig_buf;
+        *orig_buf = c;
+        --buf;
+        ++orig_buf;
+    }
+
+    return n_write;
+}
+
 ssize_t
 snprint_hex(
     char* buf,
@@ -166,7 +263,7 @@ snprintf(
 
             // int32 decimal
             case 'd':
-                n_tmp_write = snprint_decimal(buf, buf_size, *(int32_t*)arg_ptr);
+                n_tmp_write = snprint_decimal32(buf, buf_size, *(int32_t*)arg_ptr);
                 arg_ptr += sizeof(int32_t);
                 break;
 
@@ -180,6 +277,23 @@ snprintf(
                 arg_ptr += sizeof(uint32_t);
                 break;
 
+            // long decimal
+            case 'l':
+                switch (*(++fmt)) {
+                // long long aka int64
+                case 'l':
+                    ++fmt;
+                    n_tmp_write = snprint_decimal64(buf, buf_size, *(int64_t*)arg_ptr);
+                    arg_ptr += sizeof(int64_t);
+                    break;
+                // long int aka int32
+                case 'd':
+                    n_tmp_write = snprint_decimal32(buf, buf_size, *(int32_t*)arg_ptr);
+                    arg_ptr += sizeof(int32_t);
+                    break;
+                }
+                break;
+
             // c string
             case 's':
                 n_tmp_write = snprintf(buf, buf_size, *(const char**)arg_ptr);