aboutsummaryrefslogtreecommitdiff
path: root/src/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'src/stdlib')
-rw-r--r--src/stdlib/arrays.c6
-rw-r--r--src/stdlib/arrays.h4
-rw-r--r--src/stdlib/bytes.c10
-rw-r--r--src/stdlib/datatypes.h8
-rw-r--r--src/stdlib/functiontype.c2
-rw-r--r--src/stdlib/integers.c14
-rw-r--r--src/stdlib/integers.h38
-rw-r--r--src/stdlib/metamethods.c4
-rw-r--r--src/stdlib/moments.c2
-rw-r--r--src/stdlib/mutexeddata.c3
-rw-r--r--src/stdlib/nums.h14
-rw-r--r--src/stdlib/optionals.h6
-rw-r--r--src/stdlib/paths.c86
-rw-r--r--src/stdlib/paths.h1
-rw-r--r--src/stdlib/patterns.c18
-rw-r--r--src/stdlib/patterns.h1
-rw-r--r--src/stdlib/print.c76
-rw-r--r--src/stdlib/print.h166
-rw-r--r--src/stdlib/rng.c17
-rw-r--r--src/stdlib/stdlib.c124
-rw-r--r--src/stdlib/stdlib.h41
-rw-r--r--src/stdlib/text.c29
-rw-r--r--src/stdlib/text.h6
23 files changed, 447 insertions, 229 deletions
diff --git a/src/stdlib/arrays.c b/src/stdlib/arrays.c
index cd403c5f..b7384504 100644
--- a/src/stdlib/arrays.c
+++ b/src/stdlib/arrays.c
@@ -57,7 +57,7 @@ public void Array$insert(Array_t *arr, const void *item, Int_t int_index, int64_
if (index < 1) index = 1;
else if (index > (int64_t)arr->length + 1)
- fail("Invalid insertion index %ld for an array with length %ld", index, arr->length);
+ fail("Invalid insertion index ", index, " for an array with length ", (int64_t)arr->length);
if (!arr->data) {
arr->free = 4;
@@ -105,7 +105,7 @@ public void Array$insert_all(Array_t *arr, Array_t to_insert, Int_t int_index, i
if (index < 1) index = 1;
else if (index > (int64_t)arr->length + 1)
- fail("Invalid insertion index %ld for an array with length %ld", index, arr->length);
+ fail("Invalid insertion index ", index, " for an array with length ", (int64_t)arr->length);
if ((int64_t)arr->free >= (int64_t)to_insert.length // Adequate free space
&& arr->data_refcount == 0 // Not aliased memory
@@ -322,7 +322,7 @@ public Array_t Array$sample(Array_t arr, Int_t int_n, Array_t weights, RNG_t rng
}
if (weights.length != arr.length)
- fail("Array has %ld elements, but there are %ld weights given", arr.length, weights.length);
+ fail("Array has ", (int64_t)arr.length, " elements, but there are ", (int64_t)weights.length, " weights given");
double total = 0.0;
for (int64_t i = 0; i < weights.length && i < arr.length; i++) {
diff --git a/src/stdlib/arrays.h b/src/stdlib/arrays.h
index dc7efee6..e286dfdb 100644
--- a/src/stdlib/arrays.h
+++ b/src/stdlib/arrays.h
@@ -14,7 +14,7 @@
const Array_t arr = arr_expr; int64_t index = index_expr; \
int64_t off = index + (index < 0) * (arr.length + 1) - 1; \
if (unlikely(off < 0 || off >= arr.length)) \
- fail_source(__SOURCE_FILE__, start, end, "Invalid array index: %s (array has length %ld)\n", Text$as_c_string(Int64$as_text(&index, no, NULL)), arr.length); \
+ fail_source(__SOURCE_FILE__, start, end, "Invalid array index: ", index, " (array has length ", (int64_t)arr.length, ")\n"); \
(item_type*)(arr.data + arr.stride * off);})
#define Array_get_unchecked(type, x, i) *({ const Array_t arr = x; int64_t index = i; \
int64_t off = index + (index < 0) * (arr.length + 1) - 1; \
@@ -23,7 +23,7 @@
Array_t *arr = arr_expr; int64_t index = index_expr; \
int64_t off = index + (index < 0) * (arr->length + 1) - 1; \
if (unlikely(off < 0 || off >= arr->length)) \
- fail_source(__SOURCE_FILE__, start, end, "Invalid array index: %s (array has length %ld)\n", Text$as_c_string(Int64$as_text(&index, no, NULL)), arr->length); \
+ fail_source(__SOURCE_FILE__, start, end, "Invalid array index: ", index, " (array has length ", (int64_t)arr->length, ")\n"); \
if (arr->data_refcount > 0) \
Array$compact(arr, sizeof(item_type)); \
(item_type*)(arr->data + arr->stride * off); })
diff --git a/src/stdlib/bytes.c b/src/stdlib/bytes.c
index b24a721b..09e19c40 100644
--- a/src/stdlib/bytes.c
+++ b/src/stdlib/bytes.c
@@ -32,24 +32,24 @@ public Text_t Byte$hex(Byte_t byte, bool uppercase, bool prefix) {
public PUREFUNC Byte_t Byte$from_int(Int_t i, bool truncate) {
if unlikely (truncate && Int$compare_value(i, I_small(0xFF)) > 0)
- fail("This value is too large to convert to a byte without truncation: %k", (Text_t[1]){Int$value_as_text(i)});
+ fail("This value is too large to convert to a byte without truncation: ", i);
else if unlikely (truncate && Int$compare_value(i, I_small(0)) < 0)
- fail("Negative values can't be converted to bytes: %k", (Text_t[1]){Int$value_as_text(i)});
+ fail("Negative values can't be converted to bytes: ", i);
return (i.small != 0);
}
public PUREFUNC Byte_t Byte$from_int64(Int64_t i, bool truncate) {
if unlikely (truncate && i != (Int64_t)(Byte_t)i)
- fail("This value can't be converted to a byte without truncation: %ld", i);
+ fail("This value can't be converted to a byte without truncation: ", i);
return (Byte_t)i;
}
public PUREFUNC Byte_t Byte$from_int32(Int32_t i, bool truncate) {
if unlikely (truncate && i != (Int32_t)(Byte_t)i)
- fail("This value can't be converted to a byte without truncation: %d", i);
+ fail("This value can't be converted to a byte without truncation: ", i);
return (Byte_t)i;
}
public PUREFUNC Byte_t Byte$from_int16(Int16_t i, bool truncate) {
if unlikely (truncate && i != (Int16_t)(Byte_t)i)
- fail("This value can't be converted to a byte without truncation: %d", i);
+ fail("This value can't be converted to a byte without truncation: ", i);
return (Byte_t)i;
}
diff --git a/src/stdlib/datatypes.h b/src/stdlib/datatypes.h
index b81ff741..40b4712a 100644
--- a/src/stdlib/datatypes.h
+++ b/src/stdlib/datatypes.h
@@ -34,6 +34,8 @@ typedef union {
mpz_t *big;
} Int_t;
+#define OptionalInt_t Int_t
+
typedef struct {
void *data;
// All of the following fields add up to 64 bits, which means that array
@@ -117,4 +119,10 @@ typedef struct MutexedData_s {
void *data;
} *MutexedData_t;
+#define OptionalBool_t uint8_t
+#define OptionalArray_t Array_t
+#define OptionalTable_t Table_t
+#define OptionalText_t Text_t
+#define OptionalClosure_t Closure_t
+
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/functiontype.c b/src/stdlib/functiontype.c
index b02739a2..8c864611 100644
--- a/src/stdlib/functiontype.c
+++ b/src/stdlib/functiontype.c
@@ -82,7 +82,7 @@ public Text_t Func$as_text(const void *fn, bool colorize, const TypeInfo_t *type
OptionalText_t filename = get_function_filename(*(void**)fn);
int64_t line_num = get_function_line_num(*(void**)fn);
if (filename.length >= 0)
- text = Text$format("%k [%k:%ld]", &text, &filename, line_num);
+ text = Texts(text, Text(" ["), filename, Text$format(":%ld]", line_num));
}
if (fn && colorize)
text = Text$concat(Text("\x1b[32;1m"), text, Text("\x1b[m"));
diff --git a/src/stdlib/integers.c b/src/stdlib/integers.c
index 4d5d0a80..c5764d46 100644
--- a/src/stdlib/integers.c
+++ b/src/stdlib/integers.c
@@ -6,6 +6,7 @@
#include <gmp.h>
#include <stdbool.h>
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include "arrays.h"
@@ -16,9 +17,18 @@
#include "text.h"
#include "types.h"
+public int Int$print(FILE *f, Int_t i) {
+ if (likely(i.small & 1L)) {
+ return fprintf(f, "%ld", (i.small)>>2L);
+ } else {
+ char *str = mpz_get_str(NULL, 10, *i.big);
+ return fputs(str, f);
+ }
+}
+
public Text_t Int$value_as_text(Int_t i) {
if (likely(i.small & 1L)) {
- return Text$format("%ld", (i.small)>>2L);
+ return Text$format("%ld", i.small>>2L);
} else {
char *str = mpz_get_str(NULL, 10, *i.big);
return Text$from_str(str);
@@ -416,7 +426,7 @@ public Int_t Int$prev_prime(Int_t x)
mpz_t p;
mpz_init_set_int(p, x);
if (unlikely(mpz_prevprime(p, p) == 0))
- fail("There is no prime number before %k", (Text_t[1]){Int$as_text(&x, false, &Int$info)});
+ fail("There is no prime number before ", x);
return Int$from_mpz(p);
}
#endif
diff --git a/src/stdlib/integers.h b/src/stdlib/integers.h
index e0586882..356e791c 100644
--- a/src/stdlib/integers.h
+++ b/src/stdlib/integers.h
@@ -7,6 +7,7 @@
#include <stdlib.h>
#include <gmp.h>
+#include "print.h"
#include "datatypes.h"
#include "stdlib.h"
#include "types.h"
@@ -87,8 +88,7 @@ void Int64$deserialize(FILE *in, void *outval, Array_t*, const TypeInfo_t*);
void Int32$serialize(const void *obj, FILE *out, Table_t*, const TypeInfo_t*);
void Int32$deserialize(FILE *in, void *outval, Array_t*, const TypeInfo_t*);
-#define OptionalInt_t Int_t
-
+int Int$print(FILE *f, Int_t i);
Text_t Int$as_text(const void *i, bool colorize, const TypeInfo_t *type);
Text_t Int$value_as_text(Int_t i);
PUREFUNC uint64_t Int$hash(const void *x, const TypeInfo_t *type);
@@ -283,7 +283,7 @@ MACROLIKE PUREFUNC Int_t Int$from_num(double n, bool truncate) {
mpz_t result;
mpz_init_set_d(result, n);
if (!truncate && unlikely(mpz_get_d(result) != n))
- fail("Could not convert to an integer without truncation: %g", n);
+ fail("Could not convert to an integer without truncation: ", n);
return Int$from_mpz(result);
}
MACROLIKE PUREFUNC Int_t Int$from_num32(float n, bool truncate) { return Int$from_num((double)n, truncate); }
@@ -304,20 +304,20 @@ MACROLIKE CONSTFUNC Int_t Int$from_bool(Bool_t b) { return I_small(b); }
MACROLIKE PUREFUNC Int64_t Int64$from_num(Num_t n, bool truncate) {
int64_t i64 = (int64_t)n;
if (!truncate && unlikely((Num_t)i64 != n))
- fail("Could not convert Num to Int64 without truncation: %g\n", n);
+ fail("Could not convert Num to Int64 without truncation: ", n);
return i64;
}
MACROLIKE PUREFUNC Int64_t Int64$from_num32(Num32_t n, bool truncate) {
int64_t i64 = (int64_t)n;
if (!truncate && unlikely((Num32_t)i64 != n))
- fail("Could not convert Num32 to Int64 without truncation: %g\n", (double)n);
+ fail("Could not convert Num32 to Int64 without truncation: ", n);
return i64;
}
MACROLIKE PUREFUNC Int64_t Int64$from_int(Int_t i, bool truncate) {
if likely (i.small & 1L)
return (int64_t)(i.small >> 2L);
if (!truncate && unlikely(!mpz_fits_slong_p(*i.big)))
- fail("Integer is too big to fit in a 64-bit integer: %k", (Text_t[1]){Int$value_as_text(i)});
+ fail("Integer is too big to fit in a 64-bit integer: ", i);
return mpz_get_si(*i.big);
}
MACROLIKE CONSTFUNC Int64_t Int64$from_int32(Int32_t i) { return (Int64_t)i; }
@@ -328,26 +328,26 @@ MACROLIKE CONSTFUNC Int64_t Int64$from_int8(Int8_t i) { return (Int64_t)i; }
MACROLIKE PUREFUNC Int32_t Int32$from_num(Num_t n, bool truncate) {
int32_t i32 = (int32_t)n;
if (!truncate && unlikely((Num_t)i32 != n))
- fail("Could not convert Num to Int32 without truncation: %g\n", n);
+ fail("Could not convert Num to Int32 without truncation: ", n);
return i32;
}
MACROLIKE PUREFUNC Int32_t Int32$from_num32(Num32_t n, bool truncate) {
int32_t i32 = (int32_t)n;
if (!truncate && unlikely((Num32_t)i32 != n))
- fail("Could not convert Num32 to Int32 without truncation: %g\n", (double)n);
+ fail("Could not convert Num32 to Int32 without truncation: ", n);
return i32;
}
MACROLIKE PUREFUNC Int32_t Int32$from_int(Int_t i, bool truncate) {
int64_t i64 = Int64$from_int(i, truncate);
int32_t i32 = (int32_t)i64;
if (!truncate && unlikely((int64_t)i32 != i64))
- fail("Integer is too big to fit in a 32-bit integer: %k", (Text_t[1]){Int$value_as_text(i)});
+ fail("Integer is too big to fit in a 32-bit integer: ", i);
return i32;
}
MACROLIKE PUREFUNC Int32_t Int32$from_int64(Int64_t i64, bool truncate) {
int32_t i32 = (int32_t)i64;
if (!truncate && unlikely((int64_t)i32 != i64))
- fail("Integer is too big to fit in a 32-bit integer: %ld", i64);
+ fail("Integer is too big to fit in a 32-bit integer: ", i64);
return i32;
}
MACROLIKE CONSTFUNC Int32_t Int32$from_int16(Int16_t i) { return (Int32_t)i; }
@@ -357,13 +357,13 @@ MACROLIKE CONSTFUNC Int32_t Int32$from_int8(Int8_t i) { return (Int32_t)i; }
MACROLIKE PUREFUNC Int16_t Int16$from_num(Num_t n, bool truncate) {
int16_t i16 = (int16_t)n;
if (!truncate && unlikely((Num_t)i16 != n))
- fail("Could not convert Num to Int16 without truncation: %g\n", n);
+ fail("Could not convert Num to Int16 without truncation: ", n);
return i16;
}
MACROLIKE PUREFUNC Int16_t Int16$from_num32(Num32_t n, bool truncate) {
int16_t i16 = (int16_t)n;
if (!truncate && unlikely((Num32_t)i16 != n))
- fail("Could not convert Num32 to Int16 without truncation: %g\n", (double)n);
+ fail("Could not convert Num32 to Int16 without truncation: ", (double)n);
return i16;
}
MACROLIKE PUREFUNC Int16_t Int16$from_int(Int_t i, bool truncate) {
@@ -376,13 +376,13 @@ MACROLIKE PUREFUNC Int16_t Int16$from_int(Int_t i, bool truncate) {
MACROLIKE PUREFUNC Int16_t Int16$from_int64(Int64_t i64, bool truncate) {
int16_t i16 = (int16_t)i64;
if (!truncate && unlikely((int64_t)i16 != i64))
- fail("Integer is too big to fit in a 16-bit integer: %ld", i64);
+ fail("Integer is too big to fit in a 16-bit integer: ", i64);
return i16;
}
MACROLIKE PUREFUNC Int16_t Int16$from_int32(Int32_t i32, bool truncate) {
int16_t i16 = (int16_t)i32;
if (!truncate && unlikely((int32_t)i16 != i32))
- fail("Integer is too big to fit in a 16-bit integer: %ld", i32);
+ fail("Integer is too big to fit in a 16-bit integer: ", i32);
return i16;
}
MACROLIKE CONSTFUNC Int16_t Int16$from_int8(Int8_t i) { return (Int16_t)i; }
@@ -391,13 +391,13 @@ MACROLIKE CONSTFUNC Int16_t Int16$from_int8(Int8_t i) { return (Int16_t)i; }
MACROLIKE PUREFUNC Int8_t Int8$from_num(Num_t n, bool truncate) {
int8_t i8 = (int8_t)n;
if (!truncate && unlikely((Num_t)i8 != n))
- fail("Could not convert Num to Int8 without truncation: %g\n", n);
+ fail("Could not convert Num to Int8 without truncation: ", n);
return i8;
}
MACROLIKE PUREFUNC Int8_t Int8$from_num32(Num32_t n, bool truncate) {
int8_t i8 = (int8_t)n;
if (!truncate && unlikely((Num32_t)i8 != n))
- fail("Could not convert Num32 to Int8 without truncation: %g\n", (double)n);
+ fail("Could not convert Num32 to Int8 without truncation: ", n);
return i8;
}
MACROLIKE PUREFUNC Int8_t Int8$from_int(Int_t i, bool truncate) {
@@ -410,19 +410,19 @@ MACROLIKE PUREFUNC Int8_t Int8$from_int(Int_t i, bool truncate) {
MACROLIKE PUREFUNC Int8_t Int8$from_int64(Int64_t i64, bool truncate) {
int8_t i8 = (int8_t)i64;
if (!truncate && unlikely((int64_t)i8 != i64))
- fail("Integer is too big to fit in a 8-bit integer: %ld", i64);
+ fail("Integer is too big to fit in a 8-bit integer: ", i64);
return i8;
}
MACROLIKE PUREFUNC Int8_t Int8$from_int32(Int32_t i32, bool truncate) {
int8_t i8 = (int8_t)i32;
if (!truncate && unlikely((int32_t)i8 != i32))
- fail("Integer is too big to fit in a 8-bit integer: %ld", i32);
+ fail("Integer is too big to fit in a 8-bit integer: ", i32);
return i8;
}
MACROLIKE PUREFUNC Int8_t Int8$from_int16(Int16_t i16, bool truncate) {
int8_t i8 = (int8_t)i16;
if (!truncate && unlikely((int16_t)i8 != i16))
- fail("Integer is too big to fit in a 8-bit integer: %ld", i16);
+ fail("Integer is too big to fit in a 8-bit integer: ", i16);
return i8;
}
#pragma GCC diagnostic pop
diff --git a/src/stdlib/metamethods.c b/src/stdlib/metamethods.c
index c0e11cfc..a7622e0b 100644
--- a/src/stdlib/metamethods.c
+++ b/src/stdlib/metamethods.c
@@ -111,14 +111,14 @@ __attribute__((noreturn))
public void cannot_serialize(const void*, FILE*, Table_t*, const TypeInfo_t *type)
{
Text_t typestr = generic_as_text(NULL, false, type);
- fail("Values of type %k cannot be serialized or deserialized!", &typestr);
+ fail("Values of type ", typestr, " cannot be serialized or deserialized!");
}
__attribute__((noreturn))
public void cannot_deserialize(FILE*, void*, Array_t*, const TypeInfo_t *type)
{
Text_t typestr = generic_as_text(NULL, false, type);
- fail("Values of type %k cannot be serialized or deserialized!", &typestr);
+ fail("Values of type ", typestr, " cannot be serialized or deserialized!");
}
// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/moments.c b/src/stdlib/moments.c
index bb3d70a9..a48e40b5 100644
--- a/src/stdlib/moments.c
+++ b/src/stdlib/moments.c
@@ -222,7 +222,7 @@ public OptionalMoment_t Moment$parse(Text_t text, Text_t format)
const char *str = Text$as_c_string(text);
const char *fmt = Text$as_c_string(format);
if (strstr(fmt, "%Z"))
- fail("The %%Z specifier is not supported for time parsing!");
+ fail("The %Z specifier is not supported for time parsing!");
char *invalid = strptime(str, fmt, &info);
if (!invalid || invalid[0] != '\0')
diff --git a/src/stdlib/mutexeddata.c b/src/stdlib/mutexeddata.c
index f47adfc1..ead154e7 100644
--- a/src/stdlib/mutexeddata.c
+++ b/src/stdlib/mutexeddata.c
@@ -20,7 +20,8 @@ static Text_t MutexedData$as_text(const void *m, bool colorize, const TypeInfo_t
if (!m) {
return Texts(colorize ? Text("\x1b[34;1mmutexed\x1b[m(") : Text("mutexed("), typename, Text(")"));
}
- return Text$format(colorize ? "\x1b[34;1mmutexed %k<%p>\x1b[m" : "mutexed %k<%p>", &typename, *((MutexedData_t*)m));
+ return Texts(colorize ? Text("\x1b[34;1mmutexed ") : Text("mutexed "), typename,
+ Text$format(colorize ? "<%p>\x1b[m" : "<%p>", *((MutexedData_t*)m)));
}
static bool MutexedData$is_none(const void *m, const TypeInfo_t *)
diff --git a/src/stdlib/nums.h b/src/stdlib/nums.h
index be270f51..f355fb6f 100644
--- a/src/stdlib/nums.h
+++ b/src/stdlib/nums.h
@@ -42,7 +42,7 @@ MACROLIKE CONSTFUNC double Num$from_int(Int_t i, bool truncate) {
if likely (i.small & 0x1) {
double ret = (double)(i.small >> 2);
if unlikely (!truncate && (int64_t)ret != (i.small >> 2))
- fail("Could not convert integer to 64-bit floating point without losing precision: %ld", i.small >> 2);
+ fail("Could not convert integer to 64-bit floating point without losing precision: ", i.small >> 2);
return ret;
} else {
double ret = mpz_get_d(*i.big);
@@ -50,7 +50,7 @@ MACROLIKE CONSTFUNC double Num$from_int(Int_t i, bool truncate) {
mpz_t roundtrip;
mpz_init_set_d(roundtrip, ret);
if unlikely (mpz_cmp(*i.big, roundtrip) != 0)
- fail("Could not convert integer to 64-bit floating point without losing precision: %k", (Text_t[1]){Int$value_as_text(i)});
+ fail("Could not convert integer to 64-bit floating point without losing precision: ", i);
}
return ret;
}
@@ -59,7 +59,7 @@ MACROLIKE CONSTFUNC double Num$from_int(Int_t i, bool truncate) {
MACROLIKE CONSTFUNC double Num$from_int64(Int64_t i, bool truncate) {
double n = (double)i;
if unlikely (!truncate && (Int64_t)n != i)
- fail("Could not convert integer to 64-bit floating point without losing precision: %ld", i);
+ fail("Could not convert integer to 64-bit floating point without losing precision: ", i);
return n;
}
MACROLIKE CONSTFUNC double Num$from_int32(Int32_t i) { return (double)i; }
@@ -94,7 +94,7 @@ MACROLIKE CONSTFUNC float Num32$from_int(Int_t i, bool truncate) {
if likely (i.small & 0x1) {
float ret = (float)(i.small >> 2);
if unlikely (!truncate && (int64_t)ret != (i.small >> 2))
- fail("Could not convert integer to 32-bit floating point without losing precision: %ld", i.small >> 2);
+ fail("Could not convert integer to 32-bit floating point without losing precision: ", i.small >> 2);
return ret;
} else {
float ret = (float)mpz_get_d(*i.big);
@@ -102,7 +102,7 @@ MACROLIKE CONSTFUNC float Num32$from_int(Int_t i, bool truncate) {
mpz_t roundtrip;
mpz_init_set_d(roundtrip, ret);
if unlikely (mpz_cmp(*i.big, roundtrip) != 0)
- fail("Could not convert integer to 32-bit floating point without losing precision: %k", (Text_t[1]){Int$value_as_text(i)});
+ fail("Could not convert integer to 32-bit floating point without losing precision: ", i);
}
return ret;
}
@@ -111,13 +111,13 @@ MACROLIKE CONSTFUNC float Num32$from_int(Int_t i, bool truncate) {
MACROLIKE CONSTFUNC float Num32$from_int64(Int64_t i, bool truncate) {
float n = (float)i;
if unlikely (!truncate && (Int64_t)n != i)
- fail("Could not convert integer to 32-bit floating point without losing precision: %ld", i);
+ fail("Could not convert integer to 32-bit floating point without losing precision: ", i);
return n;
}
MACROLIKE CONSTFUNC float Num32$from_int32(Int32_t i, bool truncate) {
float n = (float)i;
if unlikely (!truncate && (Int32_t)n != i)
- fail("Could not convert integer to 32-bit floating point without losing precision: %d", i);
+ fail("Could not convert integer to 32-bit floating point without losing precision: ", i);
return n;
}
MACROLIKE CONSTFUNC float Num32$from_int16(Int16_t i) { return (float)i; }
diff --git a/src/stdlib/optionals.h b/src/stdlib/optionals.h
index ccf1b963..94e4d900 100644
--- a/src/stdlib/optionals.h
+++ b/src/stdlib/optionals.h
@@ -10,12 +10,6 @@
#include "types.h"
#include "util.h"
-#define OptionalBool_t uint8_t
-#define OptionalArray_t Array_t
-#define OptionalTable_t Table_t
-#define OptionalText_t Text_t
-#define OptionalClosure_t Closure_t
-
#define NONE_ARRAY ((Array_t){.length=-1})
#define NONE_BOOL ((OptionalBool_t)2)
#define NONE_INT ((OptionalInt_t){.small=0})
diff --git a/src/stdlib/paths.c b/src/stdlib/paths.c
index fae75e98..83e480e1 100644
--- a/src/stdlib/paths.c
+++ b/src/stdlib/paths.c
@@ -17,6 +17,7 @@
#include <unistd.h>
#include <unistr.h>
+#include "print.h"
#include "arrays.h"
#include "enums.h"
#include "files.h"
@@ -122,8 +123,7 @@ public Path_t Path$_concat(int n, Path_t items[n])
ARRAY_INCREF(result.components);
for (int i = 1; i < n; i++) {
if (items[i].type.$tag != PATH_RELATIVE)
- fail("Cannot concatenate an absolute or home-based path onto another path: (%s)\n",
- Path$as_c_string(items[i]));
+ fail("Cannot concatenate an absolute or home-based path onto another path: (", items[i], ")");
Array$insert_all(&result.components, items[i].components, I(0), sizeof(Text_t));
}
clean_components(&result.components);
@@ -146,8 +146,7 @@ public Path_t Path$resolved(Path_t path, Path_t relative_to)
public Path_t Path$relative_to(Path_t path, Path_t relative_to)
{
if (path.type.$tag != relative_to.type.$tag)
- fail("Cannot create a path relative to a different path with a mismatching type: (%k) relative to (%k)",
- (Text_t[1]){Path$as_text(&path, false, &Path$info)}, (Text_t[1]){Path$as_text(&relative_to, false, &Path$info)});
+ fail("Cannot create a path relative to a different path with a mismatching type: (", path, ") relative to (", relative_to, ")");
Path_t result = {.type.$tag=PATH_RELATIVE};
int64_t shared = 0;
@@ -274,13 +273,13 @@ static void _write(Path_t path, Array_t bytes, int mode, int permissions)
const char *path_str = Path$as_c_string(path);
int fd = open(path_str, mode, permissions);
if (fd == -1)
- fail("Could not write to file: %s\n%s", path_str, strerror(errno));
+ fail("Could not write to file: ", path_str, "\n", strerror(errno));
if (bytes.stride != 1)
Array$compact(&bytes, 1);
ssize_t written = write(fd, bytes.data, (size_t)bytes.length);
if (written != (ssize_t)bytes.length)
- fail("Could not write to file: %s\n%s", path_str, strerror(errno));
+ fail("Could not write to file: ", path_str, "\n", strerror(errno));
close(fd);
}
@@ -328,7 +327,7 @@ public OptionalArray_t Path$read_bytes(Path_t path, OptionalInt_t count)
content[sb.st_size] = '\0';
close(fd);
if (count.small && (int64_t)sb.st_size < target_count)
- fail("Could not read %ld bytes from %k (only got %zu)", target_count, &path, sb.st_size);
+ fail("Could not read ", target_count, " bytes from ", path, " (only got ", sb.st_size, ")");
int64_t len = count.small ? target_count : (int64_t)sb.st_size;
return (Array_t){.data=content, .atomic=1, .stride=1, .length=len};
} else {
@@ -358,7 +357,7 @@ public OptionalArray_t Path$read_bytes(Path_t path, OptionalInt_t count)
}
close(fd);
if (count.small != 0 && (int64_t)len < target_count)
- fail("Could not read %ld bytes from %k (only got %zu)", target_count, &path, len);
+ fail("Could not read ", target_count, " bytes from ", path, " (only got ", len, ")");
return (Array_t){.data=content, .atomic=1, .stride=1, .length=len};
}
}
@@ -393,14 +392,14 @@ public void Path$set_owner(Path_t path, OptionalText_t owner, OptionalText_t gro
uid_t owner_id = (uid_t)-1;
if (owner.length >= 0) {
struct passwd *pwd = getpwnam(Text$as_c_string(owner));
- if (pwd == NULL) fail("Not a valid user: %k", &owner);
+ if (pwd == NULL) fail("Not a valid user: ", owner);
owner_id = pwd->pw_uid;
}
gid_t group_id = (gid_t)-1;
if (group.length >= 0) {
struct group *grp = getgrnam(Text$as_c_string(group));
- if (grp == NULL) fail("Not a valid group: %k", &group);
+ if (grp == NULL) fail("Not a valid group: ", group);
group_id = grp->gr_gid;
}
const char *path_str = Path$as_c_string(path);
@@ -415,17 +414,16 @@ static int _remove_files(const char *path, const struct stat *sbuf, int type, st
switch (type) {
case FTW_F: case FTW_SL: case FTW_SLN:
if (remove(path) < 0) {
- fail("Could not remove file: %s (%s)", path, strerror(errno));
+ fail("Could not remove file: ", path, " (", strerror(errno), ")");
return -1;
}
return 0;
case FTW_DP:
if (rmdir(path) != 0)
- fail("Could not remove directory: %s (%s)", path, strerror(errno));
+ fail("Could not remove directory: ", path, " (", strerror(errno), ")");
return 0;
default:
- printf("Type: %d\n", type);
- fail("Could not remove path: %s (not a file or directory)", path, strerror(errno));
+ fail("Could not remove path: ", path, " (not a file or directory)");
return -1;
}
}
@@ -437,19 +435,19 @@ public void Path$remove(Path_t path, bool ignore_missing)
struct stat sb;
if (lstat(path_str, &sb) != 0) {
if (!ignore_missing)
- fail("Could not remove file: %s (%s)", path_str, strerror(errno));
+ fail("Could not remove file: ", path_str, " (", strerror(errno), ")");
return;
}
if ((sb.st_mode & S_IFMT) == S_IFREG || (sb.st_mode & S_IFMT) == S_IFLNK) {
if (unlink(path_str) != 0 && !ignore_missing)
- fail("Could not remove file: %s (%s)", path_str, strerror(errno));
+ fail("Could not remove file: ", path_str, " (", strerror(errno), ")");
} else if ((sb.st_mode & S_IFMT) == S_IFDIR) {
const int num_open_fd = 10;
if (nftw(path_str, _remove_files, num_open_fd, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) < 0)
fail("Could not remove directory: %s (%s)", path_str, strerror(errno));
} else {
- fail("Could not remove path: %s (not a file or directory)", path_str, strerror(errno));
+ fail("Could not remove path: ", path_str, " (not a file or directory)");
}
}
@@ -459,7 +457,7 @@ public void Path$create_directory(Path_t path, int permissions)
const char *c_path = Path$as_c_string(path);
int status = mkdir(c_path, (mode_t)permissions);
if (status != 0 && errno != EEXIST)
- fail("Could not create directory: %s (%s)", c_path, strerror(errno));
+ fail("Could not create directory: ", c_path, " (", strerror(errno), ")");
}
static Array_t _filtered_children(Path_t path, bool include_hidden, mode_t filter)
@@ -471,7 +469,7 @@ static Array_t _filtered_children(Path_t path, bool include_hidden, mode_t filte
size_t path_len = strlen(path_str);
DIR *d = opendir(path_str);
if (!d)
- fail("Could not open directory: %k (%s)", &path, strerror(errno));
+ fail("Could not open directory: ", path, " (", strerror(errno), ")");
if (path_str[path_len-1] == '/')
--path_len;
@@ -516,13 +514,13 @@ public Path_t Path$unique_directory(Path_t path)
path = Path$expand_home(path);
const char *path_str = Path$as_c_string(path);
size_t len = strlen(path_str);
- if (len >= PATH_MAX) fail("Path is too long: %s", path_str);
+ if (len >= PATH_MAX) fail("Path is too long: ", path_str);
char buf[PATH_MAX] = {};
strcpy(buf, path_str);
if (buf[len-1] == '/')
buf[--len] = '\0';
char *created = mkdtemp(buf);
- if (!created) fail("Failed to create temporary directory: %s (%s)", path_str, strerror(errno));
+ if (!created) fail("Failed to create temporary directory: ", path_str, " (", strerror(errno), ")");
return Path$from_str(created);
}
@@ -531,7 +529,7 @@ public Path_t Path$write_unique_bytes(Path_t path, Array_t bytes)
path = Path$expand_home(path);
const char *path_str = Path$as_c_string(path);
size_t len = strlen(path_str);
- if (len >= PATH_MAX) fail("Path is too long: %s", path_str);
+ if (len >= PATH_MAX) fail("Path is too long: ", path_str);
char buf[PATH_MAX] = {};
strcpy(buf, path_str);
@@ -543,14 +541,14 @@ public Path_t Path$write_unique_bytes(Path_t path, Array_t bytes)
int fd = mkstemps(buf, suffixlen);
if (fd == -1)
- fail("Could not write to unique file: %s\n%s", buf, strerror(errno));
+ fail("Could not write to unique file: ", buf, "\n", strerror(errno));
if (bytes.stride != 1)
Array$compact(&bytes, 1);
ssize_t written = write(fd, bytes.data, (size_t)bytes.length);
if (written != (ssize_t)bytes.length)
- fail("Could not write to file: %s\n%s", buf, strerror(errno));
+ fail("Could not write to file: ", buf, "\n", strerror(errno));
close(fd);
return Path$from_str(buf);
}
@@ -736,42 +734,36 @@ public PUREFUNC bool Path$equal_values(Path_t a, Path_t b)
return Array$equal(&a.components, &b.components, Array$info(&Text$info));
}
-public const char *Path$as_c_string(Path_t path)
+public int Path$print(FILE *f, Path_t path)
{
if (path.components.length == 0) {
- if (path.type.$tag == PATH_ABSOLUTE) return "/";
- else if (path.type.$tag == PATH_RELATIVE) return ".";
- else if (path.type.$tag == PATH_HOME) return "~";
+ if (path.type.$tag == PATH_ABSOLUTE) return fputs("/", f);
+ else if (path.type.$tag == PATH_RELATIVE) return fputs(".", f);
+ else if (path.type.$tag == PATH_HOME) return fputs("~", f);
}
- size_t len = 0, capacity = 16;
- char *buf = GC_MALLOC_ATOMIC(capacity);
+ int n = 0;
if (path.type.$tag == PATH_ABSOLUTE) {
- buf[len++] = '/';
+ n += fputc('/', f);
} else if (path.type.$tag == PATH_HOME) {
- buf[len++] = '~';
- buf[len++] = '/';
+ n += fputs("~/", f);
} else if (path.type.$tag == PATH_RELATIVE) {
- if (!Text$equal_values(*(Text_t*)path.components.data, Text(".."))) {
- buf[len++] = '.';
- buf[len++] = '/';
- }
+ if (!Text$equal_values(*(Text_t*)path.components.data, Text("..")))
+ n += fputs("./", f);
}
for (int64_t i = 0; i < path.components.length; i++) {
Text_t *comp = (Text_t*)(path.components.data + i*path.components.stride);
- const char *comp_str = Text$as_c_string(*comp);
- size_t comp_len = strlen(comp_str);
- if (len + comp_len + 1 > capacity) {
- buf = GC_REALLOC(buf, (capacity += MIN(comp_len + 2, 16)));
- }
- memcpy(&buf[len], comp_str, comp_len);
- len += comp_len;
+ n += Text$print(f, *comp);
if (i + 1 < path.components.length)
- buf[len++] = '/';
+ n += fputc('/', f);
}
- buf[len++] = '\0';
- return buf;
+ return n;
+}
+
+public const char *Path$as_c_string(Path_t path)
+{
+ return String(path);
}
public Text_t Path$as_text(const void *obj, bool color, const TypeInfo_t *type)
diff --git a/src/stdlib/paths.h b/src/stdlib/paths.h
index 6c6cebd3..8bdbb2f3 100644
--- a/src/stdlib/paths.h
+++ b/src/stdlib/paths.h
@@ -11,6 +11,7 @@
Path_t Path$from_str(const char *str);
Path_t Path$from_text(Text_t text);
+// int Path$print(FILE *f, Path_t path);
const char *Path$as_c_string(Path_t path);
#define Path(str) Path$from_str(str)
Path_t Path$_concat(int n, Path_t items[n]);
diff --git a/src/stdlib/patterns.c b/src/stdlib/patterns.c
index 7f7d711b..500d29d2 100644
--- a/src/stdlib/patterns.c
+++ b/src/stdlib/patterns.c
@@ -518,7 +518,7 @@ static pat_t parse_next_pat(TextIter_t *state, int64_t *index)
int32_t close = open;
uc_mirror_char((ucs4_t)open, (ucs4_t*)&close);
if (!match_grapheme(state, index, close))
- fail("Pattern's closing quote is missing: %k", &state->stack[0].text);
+ fail("Pattern's closing quote is missing: ", state->stack[0].text);
return (pat_t){
.tag=PAT_QUOTE,
@@ -533,7 +533,7 @@ static pat_t parse_next_pat(TextIter_t *state, int64_t *index)
int32_t close = open;
uc_mirror_char((ucs4_t)open, (ucs4_t*)&close);
if (!match_grapheme(state, index, close))
- fail("Pattern's closing brace is missing: %k", &state->stack[0].text);
+ fail("Pattern's closing brace is missing: ", state->stack[0].text);
return (pat_t){
.tag=PAT_PAIR,
@@ -553,7 +553,7 @@ static pat_t parse_next_pat(TextIter_t *state, int64_t *index)
} else {
max = min;
}
- if (min > max) fail("Minimum repetitions (%ld) is less than the maximum (%ld)", min, max);
+ if (min > max) fail("Minimum repetitions (", min, ") is less than the maximum (", max, ")");
} else {
min = -1, max = -1;
}
@@ -573,19 +573,19 @@ static pat_t parse_next_pat(TextIter_t *state, int64_t *index)
skip_whitespace(state, index);
int32_t grapheme = Text$get_grapheme_fast(state, (*index)++);
if (!match_grapheme(state, index, '}'))
- fail("Missing closing '}' in pattern: %k", &state->stack[0].text);
+ fail("Missing closing '}' in pattern: ", state->stack[0].text);
return PAT(PAT_GRAPHEME, .grapheme=grapheme);
} else if (strlen(prop_name) == 1) {
// Single letter names: {1+ A}
skip_whitespace(state, index);
if (!match_grapheme(state, index, '}'))
- fail("Missing closing '}' in pattern: %k", &state->stack[0].text);
+ fail("Missing closing '}' in pattern: ", state->stack[0].text);
return PAT(PAT_GRAPHEME, .grapheme=prop_name[0]);
}
skip_whitespace(state, index);
if (!match_grapheme(state, index, '}'))
- fail("Missing closing '}' in pattern: %k", &state->stack[0].text);
+ fail("Missing closing '}' in pattern: ", state->stack[0].text);
switch (tolower(prop_name[0])) {
case '.':
@@ -673,7 +673,7 @@ static pat_t parse_next_pat(TextIter_t *state, int64_t *index)
ucs4_t grapheme = unicode_name_character(prop_name);
if (grapheme == UNINAME_INVALID)
- fail("Not a valid property or character name: %s", prop_name);
+ fail("Not a valid property or character name: ", prop_name);
return PAT(PAT_GRAPHEME, .grapheme=(int32_t)grapheme);
#undef PAT
} else {
@@ -942,14 +942,14 @@ static Text_t apply_backrefs(Text_t text, Array_t recursive_replacements, Text_t
pos += 1;
continue;
}
- if (backref < 0 || backref > 9) fail("Invalid backref index: %ld (only 0-%d are allowed)", backref, MAX_BACKREFS-1);
+ if (backref < 0 || backref > 9) fail("Invalid backref index: ", backref, " (only 0-", MAX_BACKREFS-1, " are allowed)");
backref_len = (after_backref - pos);
if (Text$get_grapheme_fast(&replacement_state, pos + backref_len) == ';')
backref_len += 1; // skip optional semicolon
if (!captures[backref].occupied)
- fail("There is no capture number %ld!", backref);
+ fail("There is no capture number ", backref, "!");
Text_t backref_text = Text$slice(text, I(captures[backref].index+1), I(captures[backref].index + captures[backref].length));
diff --git a/src/stdlib/patterns.h b/src/stdlib/patterns.h
index 53db0978..2b77e490 100644
--- a/src/stdlib/patterns.h
+++ b/src/stdlib/patterns.h
@@ -3,7 +3,6 @@
// The type representing text patterns for pattern matching.
#include <stdbool.h>
-#include <printf.h>
#include <stdint.h>
#include "datatypes.h"
diff --git a/src/stdlib/print.c b/src/stdlib/print.c
new file mode 100644
index 00000000..023af986
--- /dev/null
+++ b/src/stdlib/print.c
@@ -0,0 +1,76 @@
+// This file defines some of the helper functions used for printing values
+#include "print.h"
+
+#include <stdio.h>
+
+int _print_char(FILE *f, char c)
+{
+#if PRINT_COLOR
+#define ESC(e) "\033[35m'\033[34;1m\\" e "\033[0;35m'\033[m"
+#else
+#define ESC(e) "'\\" e "'"
+#endif
+ const char *named[256] = {['\n']=ESC("n"), ['\t']=ESC("t"), ['\r']=ESC("r"),
+ ['\033']=ESC("e"), ['\v']=ESC("v"), ['\a']=ESC("a"), ['\b']=ESC("b")};
+ const char *name = named[(uint8_t)c];
+ if (name != NULL)
+ return fputs(name, f);
+ else if (isprint(c))
+#if PRINT_COLOR
+ return fprintf(f, "\033[35m'%c'\033[m"), c);
+#else
+ return fprintf(f, "'%c'", c);
+#endif
+ else
+ return fprintf(f, ESC("x%02X"), (uint8_t)c);
+#undef ESC
+}
+
+int _print_quoted(FILE *f, quoted_t quoted)
+{
+#if PRINT_COLOR
+#define ESC(e) "\033[34;1m\\" e "\033[0;35m"
+#else
+#define ESC(e) "\\" e
+#endif
+ const char *named[256] = {['\n']=ESC("n"), ['\t']=ESC("t"), ['\r']=ESC("r"),
+ ['\033']=ESC("e"), ['\v']=ESC("v"), ['\a']=ESC("a"), ['\b']=ESC("b")};
+ int printed = fputs("\033[35m\"", f);
+ for (const char *p = quoted.str; *p; p++) {
+ const char *name = named[(uint8_t)*p];
+ if (name != NULL) {
+ printed += fputs(name, f);
+ } else if (isprint(*p) || (uint8_t)*p > 0x7F) {
+ printed += fputc(*p, f);
+ } else {
+ printed += fprintf(f, ESC("x%02X"), (uint8_t)*p);
+ }
+ }
+ printed += fputs("\"\033[m", f);
+#undef ESC
+ return printed;
+}
+
+static ssize_t _gc_stream_write(void *cookie, const char *buf, size_t size) {
+ gc_stream_t *stream = (gc_stream_t *)cookie;
+ if (stream->position + size + 1 > *stream->size)
+ *stream->buffer = GC_REALLOC(*stream->buffer, (*stream->size += MAX(MAX(16, *stream->size/2), size + 1)));
+ memcpy(&(*stream->buffer)[stream->position], buf, size);
+ stream->position += size;
+ (*stream->buffer)[stream->position] = '\0';
+ return (ssize_t)size;
+}
+
+FILE *gc_memory_stream(char **buf, size_t *size) {
+ gc_stream_t *stream = GC_MALLOC(sizeof(gc_stream_t));
+ stream->size = size;
+ stream->buffer = buf;
+ *stream->size = 16;
+ *stream->buffer = GC_MALLOC_ATOMIC(*stream->size);
+ (*stream->buffer)[0] = '\0';
+ stream->position = 0;
+ cookie_io_functions_t functions = {.write = _gc_stream_write};
+ return fopencookie(stream, "w", functions);
+}
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/print.h b/src/stdlib/print.h
new file mode 100644
index 00000000..16400e7d
--- /dev/null
+++ b/src/stdlib/print.h
@@ -0,0 +1,166 @@
+#pragma once
+
+// This file defines some functions to make it easy to do formatted text
+// without using printf style specifiers:
+//
+// print(...) - print text
+// fprint(file, ...) - print text to file
+// print_err(...) - print an error message and exit with EXIT_FAILURE
+// String(...) - return an allocated string
+//
+// If you put `#define PRINT_COLOR 1` before the import, text will be printed
+// with terminal colors.
+
+#include <assert.h>
+#include <ctype.h>
+#include <gc.h>
+#include <gc/cord.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+#include "datatypes.h"
+
+#ifndef PRINT_COLOR
+#define PRINT_COLOR 0
+#endif
+
+#define EVAL0(...) __VA_ARGS__
+#define EVAL1(...) EVAL0(EVAL0(EVAL0(__VA_ARGS__)))
+#define EVAL2(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
+#define EVAL3(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
+#define EVAL4(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
+#define EVAL(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
+
+#define MAP_END(...)
+#define MAP_OUT
+#define MAP_COMMA ,
+
+#define MAP_GET_END2() 0, MAP_END
+#define MAP_GET_END1(...) MAP_GET_END2
+#define MAP_GET_END(...) MAP_GET_END1
+#define MAP_NEXT0(test, next, ...) next MAP_OUT
+
+#define MAP_LIST_NEXT1(test, next) MAP_NEXT0(test, MAP_COMMA next, 0)
+#define MAP_LIST_NEXT(test, next) MAP_LIST_NEXT1(MAP_GET_END test, next)
+
+#define MAP_LIST0(f, x, peek, ...) f(x) MAP_LIST_NEXT(peek, MAP_LIST1)(f, peek, __VA_ARGS__)
+#define MAP_LIST1(f, x, peek, ...) f(x) MAP_LIST_NEXT(peek, MAP_LIST0)(f, peek, __VA_ARGS__)
+
+#define MAP_LIST(f, ...) EVAL(MAP_LIST1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
+
+// GCC lets you define macro-like functions which are always inlined and never
+// compiled using this combination of flags. See: https://gcc.gnu.org/onlinedocs/gcc/Inline.html
+#ifndef PRINT_FN
+#define PRINT_FN extern inline __attribute__((gnu_inline, always_inline)) int
+#endif
+
+typedef struct {
+ uint64_t n;
+ bool no_prefix;
+ bool uppercase;
+ int digits;
+} hex_format_t;
+#define hex(x, ...) ((hex_format_t){.n=x, __VA_ARGS__})
+
+typedef struct {
+ uint64_t n;
+ bool no_prefix;
+ bool uppercase;
+ int digits;
+} oct_format_t;
+#define oct(x, ...) ((oct_format_t){.n=x, __VA_ARGS__})
+
+typedef struct {
+ double n;
+ int precision;
+} num_format_t;
+#define num_fmt(x, ...) ((num_format_t){.n=x, __VA_ARGS__})
+
+typedef struct {
+ const char *str;
+} quoted_t;
+#define quoted(s) ((quoted_t){s})
+
+#if PRINT_COLOR
+#define hl(s) "\033[35m" s "\033[m"
+#else
+#define hl(s) s
+#endif
+PRINT_FN _print_int(FILE *f, int64_t x) { return fprintf(f, hl("%ld"), x); }
+PRINT_FN _print_uint(FILE *f, uint64_t x) { return fprintf(f, hl("%lu"), x); }
+PRINT_FN _print_float(FILE *f, float x) { return fprintf(f, hl("%g"), (double)x); }
+PRINT_FN _print_double(FILE *f, double x) { return fprintf(f, hl("%g"), x); }
+PRINT_FN _print_pointer(FILE *f, void *p) { return fprintf(f, hl("%p"), p); }
+PRINT_FN _print_bool(FILE *f, bool b) { return fputs(b ? hl("yes") : hl("no"), f); }
+PRINT_FN _print_str(FILE *f, const char *s) { return fputs(s, f); }
+int _print_char(FILE *f, char c);
+int _print_quoted(FILE *f, quoted_t quoted);
+PRINT_FN _print_hex(FILE *f, hex_format_t hex) {
+ return fprintf(f, hex.no_prefix ? (hex.uppercase ? hl("%0*lX") : hl("%0*lx")) : (hex.uppercase ? hl("0x%0*lX") : hl("%#0*lx")), hex.digits, hex.n);
+}
+PRINT_FN _print_oct(FILE *f, oct_format_t oct) {
+ return fprintf(f, oct.no_prefix ? (oct.uppercase ? hl("%0*lO") : hl("%0*lo")) : (oct.uppercase ? hl("%#0*lO") : hl("%#0*lo")), oct.digits, oct.n);
+}
+PRINT_FN _print_num_format(FILE *f, num_format_t num) {
+ return fprintf(f, hl("%.*lf"), num.precision, num.n);
+}
+#undef hl
+
+extern int Text$print(FILE *stream, Text_t text);
+extern int Path$print(FILE *stream, Path_t path);
+#ifndef _fprint1
+#define _fprint1(f, x) _Generic((x), \
+ char*: _print_str, \
+ const char*: _print_str, \
+ char: _print_char, \
+ bool: _print_bool, \
+ int64_t: _print_int, \
+ int32_t: _print_int, \
+ int16_t: _print_int, \
+ int8_t: _print_int, \
+ uint64_t: _print_uint, \
+ uint32_t: _print_uint, \
+ uint16_t: _print_uint, \
+ uint8_t: _print_uint, \
+ float: _print_float, \
+ double: _print_double, \
+ hex_format_t: _print_hex, \
+ oct_format_t: _print_oct, \
+ num_format_t: _print_num_format, \
+ quoted_t: _print_quoted, \
+ Text_t: Text$print, \
+ Path_t: Path$print, \
+ Int_t: Int$print, \
+ void*: _print_pointer)(f, x)
+#endif
+
+typedef struct {
+ char **buffer;
+ size_t *size;
+ size_t position;
+} gc_stream_t;
+
+FILE *gc_memory_stream(char **buf, size_t *size);
+
+#define _print(x) _n += _fprint1(_printing, x)
+#define _fprint(f, ...) ({ FILE *_printing = f; int _n = 0; MAP_LIST(_print, __VA_ARGS__); _n; })
+#define fprint(f, ...) _fprint(f, __VA_ARGS__, "\n")
+#define print(...) fprint(stdout, __VA_ARGS__)
+#define fprint_inline(f, ...) _fprint(f, __VA_ARGS__)
+#define print_inline(...) fprint_inline(stdout, __VA_ARGS__)
+#define String(...) ({ \
+ char *_buf = NULL; \
+ size_t _size = 0; \
+ FILE *_stream = gc_memory_stream(&_buf, &_size); \
+ assert(_stream); \
+ _fprint(_stream, __VA_ARGS__); \
+ fflush(_stream); \
+ _buf; })
+#define print_err(...) ({ fprint(stderr, __VA_ARGS__); exit(EXIT_FAILURE); })
+
+// vim: ts=4 sw=0 et cino=L2,l1,(0,W4,m1,\:0
diff --git a/src/stdlib/rng.c b/src/stdlib/rng.c
index 07b2f36c..82dd65d2 100644
--- a/src/stdlib/rng.c
+++ b/src/stdlib/rng.c
@@ -109,11 +109,8 @@ public Int_t RNG$int(RNG_t rng, Int_t min, Int_t max)
}
int32_t cmp = Int$compare_value(min, max);
- if (cmp > 0) {
- Text_t min_text = Int$as_text(&min, false, &Int$info), max_text = Int$as_text(&max, false, &Int$info);
- fail("Random minimum value (%k) is larger than the maximum value (%k)",
- &min_text, &max_text);
- }
+ if (cmp > 0)
+ fail("Random minimum value (", min, ") is larger than the maximum value (", max, ")");
if (cmp == 0) return min;
mpz_t range_size;
@@ -140,7 +137,7 @@ public Int_t RNG$int(RNG_t rng, Int_t min, Int_t max)
public Int64_t RNG$int64(RNG_t rng, Int64_t min, Int64_t max)
{
- if (min > max) fail("Random minimum value (%ld) is larger than the maximum value (%ld)", min, max);
+ if (min > max) fail("Random minimum value (", min, ") is larger than the maximum value (", max, ")");
if (min == max) return min;
if (min == INT64_MIN && max == INT64_MAX) {
int64_t r;
@@ -159,7 +156,7 @@ public Int64_t RNG$int64(RNG_t rng, Int64_t min, Int64_t max)
public Int32_t RNG$int32(RNG_t rng, Int32_t min, Int32_t max)
{
- if (min > max) fail("Random minimum value (%d) is larger than the maximum value (%d)", min, max);
+ if (min > max) fail("Random minimum value (", min, ") is larger than the maximum value (", max, ")");
if (min == max) return min;
if (min == INT32_MIN && max == INT32_MAX) {
int32_t r;
@@ -178,7 +175,7 @@ public Int32_t RNG$int32(RNG_t rng, Int32_t min, Int32_t max)
public Int16_t RNG$int16(RNG_t rng, Int16_t min, Int16_t max)
{
- if (min > max) fail("Random minimum value (%d) is larger than the maximum value (%d)", min, max);
+ if (min > max) fail("Random minimum value (", min, ") is larger than the maximum value (", max, ")");
if (min == max) return min;
if (min == INT16_MIN && max == INT16_MAX) {
int16_t r;
@@ -197,7 +194,7 @@ public Int16_t RNG$int16(RNG_t rng, Int16_t min, Int16_t max)
public Int8_t RNG$int8(RNG_t rng, Int8_t min, Int8_t max)
{
- if (min > max) fail("Random minimum value (%d) is larger than the maximum value (%d)", min, max);
+ if (min > max) fail("Random minimum value (", min, ") is larger than the maximum value (", max, ")");
if (min == max) return min;
if (min == INT8_MIN && max == INT8_MAX) {
int8_t r;
@@ -216,7 +213,7 @@ public Int8_t RNG$int8(RNG_t rng, Int8_t min, Int8_t max)
public Num_t RNG$num(RNG_t rng, Num_t min, Num_t max)
{
- if (min > max) fail("Random minimum value (%g) is larger than the maximum value (%g)", min, max);
+ if (min > max) fail("Random minimum value (", min, ") is larger than the maximum value (", max, ")");
if (min == max) return min;
union {
diff --git a/src/stdlib/stdlib.c b/src/stdlib/stdlib.c
index d2800dcd..d2819c17 100644
--- a/src/stdlib/stdlib.c
+++ b/src/stdlib/stdlib.c
@@ -12,6 +12,7 @@
#include <sys/random.h>
#include <time.h>
+#include "print.h"
#include "bools.h"
#include "files.h"
#include "functiontype.h"
@@ -57,9 +58,6 @@ public void tomo_init(void)
Array_t rng_seed = {.length=sizeof(random_bytes), .data=random_bytes, .stride=1, .atomic=1};
RNG$set_seed(default_rng, rng_seed);
- if (register_printf_specifier('k', printf_text, printf_text_size))
- errx(1, "Couldn't set printf specifier");
-
struct sigaction sigact;
sigact.sa_sigaction = signal_handler;
sigemptyset(&sigact.sa_mask);
@@ -136,7 +134,7 @@ static bool parse_single_arg(const TypeInfo_t *info, char *arg, void *dest)
// Single-argument tag:
if (arg[len] != ':')
- errx(1, "Invalid value for %k.%s: %s", &t, named.name, arg);
+ print_err("Invalid value for ", t, ".", named.name, ": ", arg);
size_t offset = sizeof(int32_t);
if (named.type->align > 0 && offset % (size_t)named.type->align > 0)
offset += (size_t)named.type->align - (offset % (size_t)named.type->align);
@@ -145,7 +143,7 @@ static bool parse_single_arg(const TypeInfo_t *info, char *arg, void *dest)
return true;
}
}
- errx(1, "Invalid value for %s: %s", info->EnumInfo.name, arg);
+ print_err("Invalid value for ", info->EnumInfo.name, ": ", arg);
} else if (info->tag == StructInfo) {
if (info->StructInfo.num_fields == 0)
return true;
@@ -153,14 +151,14 @@ static bool parse_single_arg(const TypeInfo_t *info, char *arg, void *dest)
return parse_single_arg(info->StructInfo.fields[0].type, arg, dest);
Text_t t = generic_as_text(NULL, false, info);
- errx(1, "Unsupported multi-argument struct type for argument parsing: %k", &t);
+ print_err("Unsupported multi-argument struct type for argument parsing: ", t);
} else if (info->tag == ArrayInfo) {
- errx(1, "Array arguments must be specified as `--flag ...` not `--flag=...`");
+ print_err("Array arguments must be specified as `--flag ...` not `--flag=...`");
} else if (info->tag == TableInfo) {
- errx(1, "Table arguments must be specified as `--flag ...` not `--flag=...`");
+ print_err("Table arguments must be specified as `--flag ...` not `--flag=...`");
} else {
Text_t t = generic_as_text(NULL, false, info);
- errx(1, "Unsupported type for argument parsing: %k", &t);
+ print_err("Unsupported type for argument parsing: ", t);
}
}
@@ -178,7 +176,7 @@ static Array_t parse_array(const TypeInfo_t *item_info, int n, char *args[])
for (int i = 0; i < n; i++) {
bool success = parse_single_arg(item_info, args[i], items.data + items.stride*i);
if (!success)
- errx(1, "Couldn't parse argument: %s", args[i]);
+ print_err("Couldn't parse argument: ", args[i]);
}
return items;
}
@@ -209,11 +207,11 @@ static Table_t parse_table(const TypeInfo_t *table, int n, char *args[])
bool success = parse_single_arg(key, key_arg, entries.data + entries.stride*i);
if (!success)
- errx(1, "Couldn't parse table key: %s", key_arg);
+ print_err("Couldn't parse table key: ", key_arg);
success = parse_single_arg(value, value_arg, entries.data + entries.stride*i + value_offset);
if (!success)
- errx(1, "Couldn't parse table value: %s", value_arg);
+ print_err("Couldn't parse table value: ", value_arg);
*equals = '=';
}
@@ -281,18 +279,18 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
*(OptionalBool_t*)spec[s].dest = true;
} else {
if (i + 1 >= argc)
- errx(1, "Missing argument: %s\n%k", argv[i], &usage);
+ print_err("Missing argument: ", argv[i], "\n", usage);
used_args[i+1] = true;
populated_args[s] = parse_single_arg(spec[s].type, argv[i+1], spec[s].dest);
if (!populated_args[s])
- errx(1, "Couldn't parse argument: %s %s\n%k", argv[i], argv[i+1], &usage);
+ print_err("Couldn't parse argument: ", argv[i], " ", argv[i+1], "\n", usage);
}
goto next_arg;
} else if (after_name == '=') { // --foo=val
used_args[i] = true;
populated_args[s] = parse_single_arg(spec[s].type, 2 + argv[i] + strlen(spec[s].name) + 1, spec[s].dest);
if (!populated_args[s])
- errx(1, "Couldn't parse argument: %s\n%k", argv[i], &usage);
+ print_err("Couldn't parse argument: ", argv[i], "\n", usage);
goto next_arg;
} else {
continue;
@@ -303,10 +301,11 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
say(help, true);
exit(0);
}
- errx(1, "Unrecognized argument: %s\n%k", argv[i], &usage);
+ print_err("Unrecognized argument: ", argv[i], "\n", usage);
} else if (argv[i][0] == '-' && argv[i][1] && argv[i][1] != '-') { // Single flag args
used_args[i] = true;
for (char *f = argv[i] + 1; *f; f++) {
+ char flag[] = {'-', *f, 0};
for (int s = 0; s < spec_len; s++) {
if (spec[s].name[0] != *f || strlen(spec[s].name) > 1)
continue;
@@ -316,7 +315,7 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
non_opt_type = non_opt_type->OptionalInfo.type;
if (non_opt_type->tag == ArrayInfo) {
- if (f[1]) errx(1, "No value provided for -%c\n%k", *f, &usage);
+ if (f[1]) print_err("No value provided for ", flag, "\n", usage);
int num_args = 0;
while (i + 1 + num_args < argc) {
if (argv[i+1+num_args][0] == '-')
@@ -340,11 +339,11 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
populated_args[s] = true;
*(OptionalBool_t*)spec[s].dest = true;
} else {
- if (f[1] || i+1 >= argc) errx(1, "No value provided for -%c\n%k", *f, &usage);
+ if (f[1] || i+1 >= argc) print_err("No value provided for ", flag, "\n", usage);
used_args[i+1] = true;
populated_args[s] = parse_single_arg(spec[s].type, argv[i+1], spec[s].dest);
if (!populated_args[s])
- errx(1, "Couldn't parse argument: %s %s\n%k", argv[i], argv[i+1], &usage);
+ print_err("Couldn't parse argument: ", argv[i], " ", argv[i+1], "\n", usage);
}
goto next_flag;
}
@@ -353,7 +352,7 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
say(help, true);
exit(0);
}
- errx(1, "Unrecognized flag: -%c\n%k", *f, &usage);
+ print_err("Unrecognized flag: ", flag, "\n", usage);
next_flag:;
}
} else {
@@ -380,7 +379,7 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
next_non_bool_flag:
++s;
if (s >= spec_len)
- errx(1, "Extra argument: %s\n%k", argv[i], &usage);
+ print_err("Extra argument: ", argv[i], "\n", usage);
}
const TypeInfo_t *non_opt_type = spec[s].type;
@@ -416,7 +415,7 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
}
if (!populated_args[s])
- errx(1, "Invalid value for %s: %s\n%k", spec[s].name, argv[i], &usage);
+ print_err("Invalid value for ", spec[s].name, ": ", argv[i], "\n", usage);
}
for (int s = 0; s < spec_len; s++) {
@@ -426,7 +425,7 @@ public void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help,
else if (spec[s].type->tag == TableInfo)
*(OptionalTable_t*)spec[s].dest = (Table_t){};
else
- errx(1, "The required argument '%s' was not provided\n%k", spec[s].name, &usage);
+ print_err("The required argument '", spec[s].name, "' was not provided\n", usage);
}
}
}
@@ -438,14 +437,17 @@ static void print_stack_line(FILE *out, OptionalText_t fn_name, const char *file
// do a linear scan through the whole file. However, performance shouldn't
// really matter if we only print stack lines when there's a crash.
if (filename) {
- fprintf(out, "\033[34mFile\033[m \033[35;1m%s\033[m", filename);
+ fprint_inline(out, "\033[34mFile\033[m \033[35;1m", filename, "\033[m");
if (line_num >= 1)
- fprintf(out, "\033[34m line\033[m \033[35;1m%ld\033[m", line_num);
+ fprint_inline(out, "\033[34m line\033[m \033[35;1m", line_num, "\033[m");
}
if (fn_name.length > 0) {
- fprintf(out, filename ? "\033[34m, in \033[m \033[36;1m%k\033[m" : "\033[36;1m%k\033[m", &fn_name);
+ if (filename)
+ fprint_inline(out, "\033[34m, in \033[m \033[36;1m", fn_name, "\033[m");
+ else
+ fprint_inline(out, "\033[36;1m", fn_name, "\033[m");
}
- fprintf(out, "\n");
+ fprint_inline(out, "\n");
FILE *f = fopen(filename, "r");
if (!f) return;
@@ -458,7 +460,7 @@ static void print_stack_line(FILE *out, OptionalText_t fn_name, const char *file
line[strlen(line)-1] = '\0';
if (cur_line >= line_num)
- fprintf(out, "\033[33;1m%s\033[m\n", line);
+ fprint(out, "\033[33;1m", line, "\033[m");
cur_line += 1;
if (cur_line > line_num)
@@ -468,7 +470,7 @@ static void print_stack_line(FILE *out, OptionalText_t fn_name, const char *file
fclose(f);
}
-void print_stack_trace(FILE *out, int start, int stop)
+public void print_stack_trace(FILE *out, int start, int stop)
{
// Print stack trace:
void *stack[1024];
@@ -498,52 +500,9 @@ void print_stack_trace(FILE *out, int start, int stop)
}
}
-__attribute__((format(printf, 1, 2)))
-public _Noreturn void fail(const char *fmt, ...)
-{
- fflush(stdout);
- if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \n\n\x1b[0;1m", stderr);
- else fputs("==================== ERROR ====================\n\n", stderr);
- va_list args;
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- if (USE_COLOR) fputs("\x1b[m", stderr);
- fputs("\n\n", stderr);
- va_end(args);
- print_stack_trace(stderr, 2, 4);
- fflush(stderr);
- raise(SIGABRT);
- _exit(1);
-}
-
public _Noreturn void fail_text(Text_t message)
{
- fail("%k", &message);
-}
-
-__attribute__((format(printf, 4, 5)))
-public _Noreturn void fail_source(const char *filename, int64_t start, int64_t end, const char *fmt, ...)
-{
- if (USE_COLOR) fputs("\n\x1b[31;7m ==================== ERROR ==================== \n\n\x1b[0;1m", stderr);
- else fputs("\n==================== ERROR ====================\n\n", stderr);
-
- va_list args;
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- va_end(args);
-
- file_t *file = filename ? load_file(filename) : NULL;
- if (filename && file) {
- fputs("\n", stderr);
- highlight_error(file, file->text+start, file->text+end, "\x1b[31;1m", 2, USE_COLOR);
- fputs("\n", stderr);
- }
- if (USE_COLOR) fputs("\x1b[m", stderr);
-
- print_stack_trace(stderr, 2, 4);
- fflush(stderr);
- raise(SIGABRT);
- _exit(1);
+ fail(message);
}
public Text_t builtin_last_err()
@@ -595,9 +554,8 @@ public void end_inspect(const void *expr, const TypeInfo_t *type)
if (type->metamethods.as_text) {
Text_t expr_text = generic_as_text(expr, USE_COLOR, type);
Text_t type_name = generic_as_text(NULL, false, type);
-
for (int i = 0; i < 3*_inspect_depth; i++) fputc(' ', stdout);
- fprintf(stdout, USE_COLOR ? "\x1b[33;1m=\x1b[0m %k \x1b[2m: \x1b[36m%k\x1b[m\n" : "= %k : %k\n", &expr_text, &type_name);
+ fprint(stdout, USE_COLOR ? "\x1b[33;1m=\x1b[0m " : " =", expr_text, USE_COLOR ? " \x1b[2m: \x1b[36m" : " : ", type_name);
}
}
@@ -610,11 +568,17 @@ public void test_value(const void *expr, const void *expected, const TypeInfo_t
bool success = Text$equal_values(expr_text, expected_text);
if (!success) {
print_stack_trace(stderr, 2, 4);
- fprintf(stderr,
- USE_COLOR
- ? "\n\x1b[31;7m ==================== TEST FAILED ==================== \x1b[0;1m\n\nYou expected: \x1b[m%k\x1b[0m\n\x1b[1m But I got:\x1b[m %k\n\n"
- : "\n==================== TEST FAILED ====================\n\nYou expected: %k\n But I got: %k\n\n",
- &expected_text, &expr_text);
+ if (USE_COLOR) {
+ fprint(stderr,
+ "\n\x1b[31;7m ==================== TEST FAILED ==================== \x1b[0;1m\n\n"
+ "You expected: \x1b[m", expected_text, "\x1b[0m\n"
+ "\x1b[1m But I got:\x1b[m ", expr_text, "\n");
+ } else {
+ fprint(stderr,
+ "\n==================== TEST FAILED ====================\n\n"
+ "You expected: ", expected_text, "\n"
+ " But I got: ", expr_text, "\n");
+ }
fflush(stderr);
raise(SIGABRT);
diff --git a/src/stdlib/stdlib.h b/src/stdlib/stdlib.h
index 49ec43fb..d8b26eb4 100644
--- a/src/stdlib/stdlib.h
+++ b/src/stdlib/stdlib.h
@@ -7,6 +7,8 @@
#include <stdio.h>
#include "datatypes.h"
+#include "files.h"
+#include "print.h"
#include "types.h"
#include "util.h"
@@ -23,11 +25,42 @@ void tomo_init(void);
void _tomo_parse_args(int argc, char *argv[], Text_t usage, Text_t help, int spec_len, cli_arg_t spec[spec_len]);
#define tomo_parse_args(argc, argv, usage, help, ...) \
_tomo_parse_args(argc, argv, usage, help, sizeof((cli_arg_t[]){__VA_ARGS__})/sizeof(cli_arg_t), (cli_arg_t[]){__VA_ARGS__})
-__attribute__((format(printf, 1, 2)))
-_Noreturn void fail(const char *fmt, ...);
+
+#define fail(...) ({ \
+ fflush(stdout); \
+ if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \n\n\x1b[0;1m", stderr); \
+ else fputs("==================== ERROR ====================\n\n", stderr); \
+ fprint_inline(stderr, __VA_ARGS__); \
+ if (USE_COLOR) fputs("\x1b[m", stderr); \
+ fputs("\n\n", stderr); \
+ print_stack_trace(stderr, 2, 4); \
+ fflush(stderr); \
+ raise(SIGABRT); \
+ _exit(1); \
+})
+
+#define fail_source(filename, start, end, ...) ({ \
+ fflush(stdout); \
+ if (USE_COLOR) fputs("\x1b[31;7m ==================== ERROR ==================== \n\n\x1b[0;1m", stderr); \
+ else fputs("==================== ERROR ====================\n\n", stderr); \
+ fprint_inline(stderr, __VA_ARGS__); \
+ if (USE_COLOR) fputs("\x1b[m", stderr); \
+ file_t *_file = (filename) ? load_file(filename) : NULL; \
+ if ((filename) && _file) { \
+ fputs("\n", stderr); \
+ highlight_error(_file, _file->text+(start), _file->text+(end), "\x1b[31;1m", 2, USE_COLOR); \
+ fputs("\n", stderr); \
+ } \
+ if (USE_COLOR) fputs("\x1b[m", stderr); \
+ print_stack_trace(stderr, 2, 4); \
+ fputs("\n\n", stderr); \
+ print_stack_trace(stderr, 2, 4); \
+ fflush(stderr); \
+ raise(SIGABRT); \
+ _exit(1); \
+})
+
_Noreturn void fail_text(Text_t message);
-__attribute__((format(printf, 4, 5)))
-_Noreturn void fail_source(const char *filename, int64_t start, int64_t end, const char *fmt, ...);
Text_t builtin_last_err();
__attribute__((nonnull))
void start_inspect(const char *filename, int64_t start, int64_t end);
diff --git a/src/stdlib/text.c b/src/stdlib/text.c
index c2ee4613..73941717 100644
--- a/src/stdlib/text.c
+++ b/src/stdlib/text.c
@@ -55,7 +55,6 @@
#include <assert.h>
#include <ctype.h>
#include <gc.h>
-#include <printf.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
@@ -681,8 +680,7 @@ public PUREFUNC Text_t Text$cluster(Text_t text, Int_t index_int)
if (index < 0) index = text.length + index + 1;
if (index > text.length || index < 1)
- fail("Invalid index: %ld is beyond the length of the text (length = %ld)",
- Int64$from_int(index_int, false), text.length);
+ fail("Invalid index: ", index_int, " is beyond the length of the text (length = ", (int64_t)text.length, ")");
while (text.tag == TEXT_CONCAT) {
if (index <= text.left->length)
@@ -1104,24 +1102,6 @@ public Text_t Text$title(Text_t text, Text_t language)
return ret;
}
-public int printf_text_size(const struct printf_info *info, size_t n, int argtypes[n], int sizes[n])
-{
- if (n < 1) return -1;
- (void)info;
- argtypes[0] = PA_POINTER;
- sizes[0] = sizeof(Text_t);
- return 1;
-}
-
-public int printf_text(FILE *stream, const struct printf_info *info, const void *const args[])
-{
- Text_t *t = *(Text_t**)args[0];
- if (info->alt)
- return text_visualize(stream, *t, 0);
- else
- return Text$print(stream, *t);
-}
-
static INLINE Text_t _quoted(Text_t text, bool colorize, char quote_char)
{
Text_t ret = colorize ? Text("\x1b[35m") : EMPTY_TEXT;
@@ -1273,13 +1253,14 @@ public Text_t Text$format(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
+ int len = vsnprintf(NULL, 0, fmt, args);
+ va_end(args);
- char buf[9];
- int len = vsnprintf(buf, sizeof(buf), fmt, args);
char *str = GC_MALLOC_ATOMIC((size_t)(len+1));
+ va_start(args, fmt);
vsnprintf(str, (size_t)(len+1), fmt, args);
- Text_t ret = Text$from_str(str);
va_end(args);
+ Text_t ret = Text$from_strn(str, (size_t)len);
return ret;
}
diff --git a/src/stdlib/text.h b/src/stdlib/text.h
index 0a44f4e4..e5c6a14f 100644
--- a/src/stdlib/text.h
+++ b/src/stdlib/text.h
@@ -4,7 +4,6 @@
// Raku's string representation and libunistr
#include <stdbool.h>
-#include <printf.h>
#include <stdint.h>
#include "datatypes.h"
@@ -25,12 +24,9 @@ typedef struct {
#define NEW_TEXT_ITER_STATE(t) (TextIter_t){.stack={{t, 0}}, .stack_index=0}
-int printf_text(FILE *stream, const struct printf_info *info, const void *const args[]);
-int printf_text_size(const struct printf_info *info, size_t n, int argtypes[n], int sizes[n]);
-
#define Text(str) ((Text_t){.length=sizeof(str)-1, .tag=TEXT_ASCII, .ascii="" str})
-int Text$print(FILE *stream, Text_t t);
+//int Text$print(FILE *stream, Text_t t);
Text_t Text$_concat(int n, Text_t items[n]);
#define Text$concat(...) Text$_concat(sizeof((Text_t[]){__VA_ARGS__})/sizeof(Text_t), (Text_t[]){__VA_ARGS__})
#define Texts(...) Text$concat(__VA_ARGS__)