116 lines
2.5 KiB
C
116 lines
2.5 KiB
C
#include <assert.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
|
|
#include "apfl.h"
|
|
|
|
#include "format.h"
|
|
|
|
#define TRY FMT_TRY
|
|
|
|
static bool
|
|
write(struct apfl_format_writer w, const char *buf, size_t len)
|
|
{
|
|
return len == 0
|
|
? true
|
|
: w.write(w.opaque, buf, len);
|
|
}
|
|
|
|
static bool
|
|
write_file(void *opaque, const char *buf, size_t len)
|
|
{
|
|
FILE *f = opaque;
|
|
return fwrite(buf, len, 1, f) == 1;
|
|
}
|
|
|
|
static bool
|
|
write_string(void *opaque, const char *buf, size_t len)
|
|
{
|
|
struct apfl_string_builder *sb = opaque;
|
|
return apfl_string_builder_append(sb, (struct apfl_string_view) {.bytes = buf, .len = len});
|
|
}
|
|
|
|
struct apfl_format_writer
|
|
apfl_format_file_writer(FILE *f)
|
|
{
|
|
return (struct apfl_format_writer) {
|
|
.write = write_file,
|
|
.opaque = f,
|
|
};
|
|
}
|
|
|
|
struct apfl_format_writer
|
|
apfl_format_string_writer(struct apfl_string_builder *sb)
|
|
{
|
|
return (struct apfl_format_writer) {
|
|
.write = write_string,
|
|
.opaque = sb,
|
|
};
|
|
}
|
|
|
|
bool
|
|
apfl_format_put_string_view(struct apfl_format_writer w, struct apfl_string_view sv)
|
|
{
|
|
return write(w, sv.bytes, sv.len);
|
|
}
|
|
|
|
#define PUT_INT_BUFSIZE 21 // ceil(log10(2**64)) + 1
|
|
|
|
bool
|
|
apfl_format_put_int(struct apfl_format_writer w, int i)
|
|
{
|
|
char buf[PUT_INT_BUFSIZE];
|
|
size_t len = snprintf(buf, PUT_INT_BUFSIZE, "%d", i);
|
|
assert(len < PUT_INT_BUFSIZE);
|
|
return write(w, buf, len);
|
|
}
|
|
|
|
bool
|
|
apfl_format_put_char(struct apfl_format_writer w, char c)
|
|
{
|
|
return write(w, &c, 1);
|
|
}
|
|
|
|
#define PUT_HEXBYTE_BUFSIZE 3
|
|
|
|
bool
|
|
apfl_format_put_hexbyte(struct apfl_format_writer w, unsigned char c)
|
|
{
|
|
char buf[PUT_HEXBYTE_BUFSIZE];
|
|
size_t len = snprintf(buf, PUT_HEXBYTE_BUFSIZE, "%x", (unsigned) c);
|
|
assert(len < PUT_HEXBYTE_BUFSIZE);
|
|
return write(w, buf, len);
|
|
}
|
|
|
|
bool
|
|
apfl_format_put_pos(struct apfl_format_writer w, struct apfl_position pos)
|
|
{
|
|
TRY(apfl_format_put_int(w, pos.line));
|
|
TRY(apfl_format_put_string(w, ":"));
|
|
TRY(apfl_format_put_int(w, pos.col));
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
apfl_format_put_indent(struct apfl_format_writer w, unsigned indent)
|
|
{
|
|
while (indent--) {
|
|
TRY(apfl_format_put_string(w, " "));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
#define PUT_NUMBER_BUFSIZE 100 // Arbitrarily chosen ¯\_(ツ)_/¯
|
|
|
|
bool
|
|
apfl_format_put_number(struct apfl_format_writer w, apfl_number number)
|
|
{
|
|
char buf[PUT_NUMBER_BUFSIZE];
|
|
size_t len = snprintf(buf, PUT_NUMBER_BUFSIZE, "%.12G", number);
|
|
TRY(write(w, buf, len));
|
|
if (len >= PUT_NUMBER_BUFSIZE) {
|
|
TRY(apfl_format_put_string(w, "[...]"));
|
|
}
|
|
return true;
|
|
}
|