drgn/libdrgn/string_builder.c
Omar Sandoval 761da83ddd libdrgn: add {min,max}_iconst() and rewrite min() and max()
min() and max() from the Linux kernel go through the trouble of
resulting in a constant expression if the arguments are constant
expressions, but they can't be used outside of a function due to their
use of ({ }). This means that they can't be used for, e.g., enumerators
or global arrays. Let's simplify min() and max() and instead add
explicit min_iconst() and max_iconst() macros that can be used
everywhere that an integer constant expression is required. We can then
use it in hash_table.h. While we're here, let's split these into their
own header file and document them better.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2020-10-10 23:48:03 -07:00

96 lines
1.9 KiB
C

// Copyright (c) Facebook, Inc. and its affiliates.
// SPDX-License-Identifier: GPL-3.0+
#include <stdlib.h>
#include <stdio.h>
#include "bitops.h"
#include "string_builder.h"
bool string_builder_finalize(struct string_builder *sb, char **ret)
{
if (!string_builder_reserve(sb, sb->len + 1))
return false;
sb->str[sb->len] = '\0';
*ret = sb->str;
return true;
}
bool string_builder_reserve(struct string_builder *sb, size_t capacity)
{
char *tmp;
if (capacity <= sb->capacity)
return true;
capacity = next_power_of_two(capacity);
tmp = realloc(sb->str, capacity);
if (!tmp)
return false;
sb->str = tmp;
sb->capacity = capacity;
return true;
}
bool string_builder_appendc(struct string_builder *sb, char c)
{
if (!string_builder_reserve(sb, sb->len + 1))
return false;
sb->str[sb->len++] = c;
return true;
}
bool string_builder_appendn(struct string_builder *sb, const char *str,
size_t len)
{
if (!string_builder_reserve(sb, sb->len + len))
return false;
memcpy(&sb->str[sb->len], str, len);
sb->len += len;
return true;
}
bool string_builder_vappendf(struct string_builder *sb, const char *format,
va_list ap)
{
va_list aq;
int len;
again:
va_copy(aq, ap);
len = vsnprintf(&sb->str[sb->len], sb->capacity - sb->len, format, aq);
va_end(aq);
if (len < 0)
return false;
if (sb->len + len < sb->capacity) {
sb->len += len;
return true;
}
/*
* vsnprintf() always null-terminates the string, so we have to allocate
* an extra character.
*/
if (!string_builder_reserve(sb, sb->len + len + 1))
return false;
goto again;
}
bool string_builder_appendf(struct string_builder *sb, const char *format, ...)
{
va_list ap;
bool ret;
va_start(ap, format);
ret = string_builder_vappendf(sb, format, ap);
va_end(ap);
return ret;
}
bool string_builder_line_break(struct string_builder *sb)
{
if (!sb->len || sb->str[sb->len - 1] == '\n')
return true;
return string_builder_appendc(sb, '\n');
}