return p;
}
+int strextendf(char **x, const char *format, ...) {
+ size_t m, a;
+ va_list ap;
+ int l;
+
+ /* Appends a formatted string to the specified string. Don't use this in inner loops, since then
+ * we'll spend a tonload of time in determining the length of the string passed in, over and over
+ * again. */
+
+ assert(x);
+ assert(format);
+
+ /* Let's try to use the allocated buffer, if there's room at the end still. Otherwise let's extend by 64 chars. */
+ if (*x) {
+ m = strlen(*x);
+ a = malloc_usable_size(*x);
+ assert(a >= m + 1);
+ } else
+ m = a = 0;
+
+ if (a - m < 17) { /* if there's less than 16 chars space, then enlarge the buffer first */
+ char *n;
+
+ if (_unlikely_(m > SIZE_MAX - 64)) /* overflow check */
+ return -ENOMEM;
+
+ n = realloc(*x, m + 64);
+ if (!n)
+ return -ENOMEM;
+
+ *x = n;
+ a = malloc_usable_size(*x);
+ }
+
+ /* Now, let's try to format the string into it */
+ va_start(ap, format);
+ l = vsnprintf(*x + m, a - m, format, ap);
+ va_end(ap);
+
+ assert(l >= 0);
+
+ if ((size_t) l < a - m) {
+ char *n;
+
+ /* Nice! This worked. We are done. But first, let's return the extra space we don't
+ * need. This should be a cheap operation, since we only lower the allocation size here,
+ * never increase. */
+ n = realloc(*x, m + (size_t) l + 1);
+ if (n)
+ *x = n;
+ } else {
+ char *n;
+
+ /* Wasn't enough. Then let's allocate exactly what we need. */
+
+ if (_unlikely_((size_t) l > SIZE_MAX - 1)) /* overflow check #1 */
+ goto oom;
+ if (_unlikely_(m > SIZE_MAX - ((size_t) l + 1))) /* overflow check #2 */
+ goto oom;
+
+ a = m + (size_t) l + 1;
+ n = realloc(*x, a);
+ if (!n)
+ goto oom;
+ *x = n;
+
+ va_start(ap, format);
+ l = vsnprintf(*x + m, a - m, format, ap);
+ va_end(ap);
+
+ assert((size_t) l < a - m);
+ }
+
+ return 0;
+
+oom:
+ /* truncate the bytes added after the first vsnprintf() attempt again */
+ (*x)[m] = 0;
+ return -ENOMEM;
+}
+
char *strrep(const char *s, unsigned n) {
char *r, *p;
size_t l;
#define strextend_with_separator(x, separator, ...) strextend_with_separator_internal(x, separator, __VA_ARGS__, NULL)
#define strextend(x, ...) strextend_with_separator_internal(x, NULL, __VA_ARGS__, NULL)
+int strextendf(char **x, const char *format, ...) _printf_(2,3);
+
char *strrep(const char *s, unsigned n);
int split_pair(const char *s, const char *sep, char **l, char **r);
if (!arg_machine) {
if (arg_directory && path_equal(arg_directory, "/"))
arg_machine = gethostname_malloc();
- else {
- if (arg_image) {
- char *e;
+ else if (arg_image) {
+ char *e;
- arg_machine = strdup(basename(arg_image));
+ arg_machine = strdup(basename(arg_image));
- /* Truncate suffix if there is one */
- e = endswith(arg_machine, ".raw");
- if (e)
- *e = 0;
- } else
- arg_machine = strdup(basename(arg_directory));
- }
+ /* Truncate suffix if there is one */
+ e = endswith(arg_machine, ".raw");
+ if (e)
+ *e = 0;
+ } else
+ arg_machine = strdup(basename(arg_directory));
if (!arg_machine)
return log_oom();
if (!hostname_is_valid(arg_machine, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine machine name automatically, please use -M.");
- if (arg_ephemeral) {
- char *b;
-
- /* Add a random suffix when this is an
- * ephemeral machine, so that we can run many
- * instances at once without manually having
- * to specify -M each time. */
-
- if (asprintf(&b, "%s-%016" PRIx64, arg_machine, random_u64()) < 0)
+ /* Add a random suffix when this is an ephemeral machine, so that we can run many
+ * instances at once without manually having to specify -M each time. */
+ if (arg_ephemeral)
+ if (strextendf(&arg_machine, "-%016" PRIx64, random_u64()) < 0)
return log_oom();
-
- free(arg_machine);
- arg_machine = b;
- }
}
return 0;
assert_se(strverscmp_improved("123_aa2-67.89", "123aa+2-67.89") == 0);
}
+static void test_strextendf(void) {
+ _cleanup_free_ char *p = NULL;
+
+ assert_se(strextendf(&p, "<%i>", 77) >= 0);
+ assert_se(streq(p, "<77>"));
+
+ assert_se(strextendf(&p, "<%i>", 99) >= 0);
+ assert_se(streq(p, "<77><99>"));
+
+ assert_se(strextendf(&p, "<%80i>", 88) >= 0);
+ assert_se(streq(p, "<77><99>< 88>"));
+
+ assert_se(strextendf(&p, "<%08x>", 0x1234) >= 0);
+ assert_se(streq(p, "<77><99>< 88><00001234>"));
+}
+
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
test_string_contains_word_strv();
test_string_contains_word();
test_strverscmp_improved();
+ test_strextendf();
return 0;
}