subsurface/membuffer.c
Linus Torvalds 989c8f0110 Fix totally broken put_vformat() implementation
I'm ashamed.  put_vbuffer() worked perfectly fine for the normal case
when everything fit in our simple buffer on-stack, but the fallback case
was broken in so many ways that I'm just going to go sit in a corner and
cry myself to sleep.

And dammit, I _knew_ how to do it right.  I knew you had to do a
"va_copy()" and couldn't just keep re-using 'args'.  I've done this
before.  But I half-arsed it, and nobody ever noticed, because you
wouldn't do C style format strings for big strings.

"128 bytes is enough for everybody".

And as penance for this idiocy, I just spent too much time trying to
figure out what was wrong in my git loading code when my debug printouts
caused SIGSEGV's.

Sigh.

Anyway, now it should hopefully be correct, and the code is smarter
about things too, not having that extra buffer since we already *have* a
buffer in the "struct membuffer" we are working with.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2014-03-08 16:32:31 -08:00

166 lines
3.1 KiB
C

#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "dive.h"
#include "membuffer.h"
void free_buffer(struct membuffer *b)
{
free(b->buffer);
b->buffer = NULL;
b->len = 0;
b->alloc = 0;
}
void flush_buffer(struct membuffer *b, FILE *f)
{
if (b->len) {
fwrite(b->buffer, 1, b->len, f);
free_buffer(b);
}
}
void strip_mb(struct membuffer *b)
{
while (b->len && isspace(b->buffer[b->len - 1]))
b->len--;
}
/*
* Running out of memory isn't really an issue these days.
* So rather than do insane error handling and making the
* interface very complex, we'll just die. It won't happen
* unless you're running on a potato.
*/
static void oom(void)
{
fprintf(stderr, "Out of memory\n");
exit(1);
}
static void make_room(struct membuffer *b, unsigned int size)
{
unsigned int needed = b->len + size;
if (needed > b->alloc) {
char *n;
/* round it up to not reallocate all the time.. */
needed = needed * 9 / 8 + 1024;
n = realloc(b->buffer, needed);
if (!n)
oom();
b->buffer = n;
b->alloc = needed;
}
}
const char *mb_cstring(struct membuffer *b)
{
make_room(b, 1);
b->buffer[b->len] = 0;
return b->buffer;
}
void put_bytes(struct membuffer *b, const char *str, int len)
{
make_room(b, len);
memcpy(b->buffer + b->len, str, len);
b->len += len;
}
void put_string(struct membuffer *b, const char *str)
{
put_bytes(b, str, strlen(str));
}
void put_vformat(struct membuffer *b, const char *fmt, va_list args)
{
int room = 128;
for (;;) {
int len;
va_list copy;
char *target;
make_room(b, room);
room = b->alloc - b->len;
target = b->buffer + b->len;
va_copy(copy, args);
len = vsnprintf(target, room, fmt, copy);
va_end(copy);
if (len < room) {
b->len += len;
return;
}
room = len+1;
}
}
void put_format(struct membuffer *b, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
put_vformat(b, fmt, args);
va_end(args);
}
void put_milli(struct membuffer *b, const char *pre, int value, const char *post)
{
int i;
char buf[4];
const char *sign = "";
unsigned v;
v = value;
if (value < 0) {
sign = "-";
v = -value;
}
for (i = 2; i >= 0; i--) {
buf[i] = (v % 10) + '0';
v /= 10;
}
buf[3] = 0;
if (buf[2] == '0') {
buf[2] = 0;
if (buf[1] == '0')
buf[1] = 0;
}
put_format(b, "%s%s%u.%s%s", pre, sign, v, buf, post);
}
void put_temperature(struct membuffer *b, temperature_t temp, const char *pre, const char *post)
{
if (temp.mkelvin)
put_milli(b, pre, temp.mkelvin - ZERO_C_IN_MKELVIN, post);
}
void put_depth(struct membuffer *b, depth_t depth, const char *pre, const char *post)
{
if (depth.mm)
put_milli(b, pre, depth.mm, post);
}
void put_duration(struct membuffer *b, duration_t duration, const char *pre, const char *post)
{
if (duration.seconds)
put_format(b, "%s%u:%02u%s", pre, FRACTION(duration.seconds, 60), post);
}
void put_pressure(struct membuffer *b, pressure_t pressure, const char *pre, const char *post)
{
if (pressure.mbar)
put_milli(b, pre, pressure.mbar, post);
}
void put_salinity(struct membuffer *b, int salinity, const char *pre, const char *post)
{
if (salinity)
put_format(b, "%s%d%s", pre, salinity / 10, post);
}