From be8d3974ff7ccf3864d134722ff5b9ba611c1ed4 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Fri, 19 Nov 2021 10:23:32 +0000 Subject: [PATCH] Generalise strbuf_catf() into put_fmt(). marshal.h now provides a macro put_fmt() which allows you to write arbitrary printf-formatted data to an arbitrary BinarySink. We already had this facility for strbufs in particular, in the form of strbuf_catf(). That was able to take advantage of knowing the inner structure of a strbuf to minimise memory allocation (it would snprintf directly into the strbuf's existing buffer if possible). For a general black-box BinarySink we can't do that, so instead we dupvprintf into a temporary buffer. For consistency, I've removed strbuf_catf, and converted all uses of it into the new put_fmt - and I've also added an extra vtable method in the BinarySink API, so that put_fmt can still use strbuf_catf's more efficient memory management when talking to a strbuf, and fall back to the simpler strategy when that's not available. --- crypto/ecc-ssh.c | 4 +- crypto/hmac.c | 12 ++--- crypto/rsa.c | 6 +-- keygen/pockle.c | 24 ++++----- marshal.h | 11 ++++ misc.h | 2 - otherbackends/supdup.c | 26 ++++----- proxy/proxy.c | 4 +- ssh/scpserver.c | 10 ++-- sshpubk.c | 44 +++++++-------- testcrypt.c | 46 ++++++++-------- unix/dialog.c | 14 ++--- unix/network.c | 8 +-- unix/procnet.c | 4 +- unix/storage.c | 2 +- unix/unifont.c | 12 ++--- utils/antispoof.c | 2 +- utils/buildinfo.c | 95 ++++++++++++++++----------------- utils/marshal.c | 20 +++++++ utils/strbuf.c | 26 ++++----- windows/pageant.c | 8 +-- windows/storage.c | 2 +- windows/utils/split_into_argv.c | 2 +- windows/window.c | 26 ++++----- 24 files changed, 217 insertions(+), 193 deletions(-) diff --git a/crypto/ecc-ssh.c b/crypto/ecc-ssh.c index d985866d..893a5877 100644 --- a/crypto/ecc-ssh.c +++ b/crypto/ecc-ssh.c @@ -684,11 +684,11 @@ static char *ecc_cache_str_shared( strbuf *sb = strbuf_new(); if (curve_name) - strbuf_catf(sb, "%s,", curve_name); + put_fmt(sb, "%s,", curve_name); char *hx = mp_get_hex(x); char *hy = mp_get_hex(y); - strbuf_catf(sb, "0x%s,0x%s", hx, hy); + put_fmt(sb, "0x%s,0x%s", hx, hy); sfree(hx); sfree(hy); diff --git a/crypto/hmac.c b/crypto/hmac.c index 8f18eb28..f04d74b5 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -42,20 +42,20 @@ static ssh2_mac *hmac_new(const ssh2_macalg *alg, ssh_cipher *cipher) ctx->digest = snewn(ctx->hashalg->hlen, uint8_t); ctx->text_name = strbuf_new(); - strbuf_catf(ctx->text_name, "HMAC-%s%s", - ctx->hashalg->text_basename, extra->suffix); + put_fmt(ctx->text_name, "HMAC-%s%s", + ctx->hashalg->text_basename, extra->suffix); if (extra->annotation || ctx->hashalg->annotation) { - strbuf_catf(ctx->text_name, " ("); + put_fmt(ctx->text_name, " ("); const char *sep = ""; if (extra->annotation) { - strbuf_catf(ctx->text_name, "%s%s", sep, extra->annotation); + put_fmt(ctx->text_name, "%s%s", sep, extra->annotation); sep = ", "; } if (ctx->hashalg->annotation) { - strbuf_catf(ctx->text_name, "%s%s", sep, ctx->hashalg->annotation); + put_fmt(ctx->text_name, "%s%s", sep, ctx->hashalg->annotation); sep = ", "; } - strbuf_catf(ctx->text_name, ")"); + put_fmt(ctx->text_name, ")"); } ctx->mac.vt = alg; diff --git a/crypto/rsa.c b/crypto/rsa.c index e3dcbdda..ef832868 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -311,11 +311,11 @@ char *rsa_ssh1_fingerprint(RSAKey *key) ssh_hash_final(hash, digest); out = strbuf_new(); - strbuf_catf(out, "%"SIZEu" ", mp_get_nbits(key->modulus)); + put_fmt(out, "%"SIZEu" ", mp_get_nbits(key->modulus)); for (i = 0; i < 16; i++) - strbuf_catf(out, "%s%02x", i ? ":" : "", digest[i]); + put_fmt(out, "%s%02x", i ? ":" : "", digest[i]); if (key->comment) - strbuf_catf(out, " %s", key->comment); + put_fmt(out, " %s", key->comment); return strbuf_to_str(out); } diff --git a/keygen/pockle.c b/keygen/pockle.c index 60017e33..2a072f18 100644 --- a/keygen/pockle.c +++ b/keygen/pockle.c @@ -410,10 +410,10 @@ strbuf *pockle_mpu(Pockle *pockle, mp_int *p) memset(needed, 0, pockle->nlist * sizeof(bool)); needed[pr->index] = true; - strbuf_catf(sb, "[MPU - Primality Certificate]\nVersion 1.0\nBase 10\n\n" - "Proof for:\nN "); + put_fmt(sb, "[MPU - Primality Certificate]\nVersion 1.0\nBase 10\n\n" + "Proof for:\nN "); mp_write_decimal(sb, p); - strbuf_catf(sb, "\n"); + put_fmt(sb, "\n"); for (size_t index = pockle->nlist; index-- > 0 ;) { if (!needed[index]) @@ -421,27 +421,27 @@ strbuf *pockle_mpu(Pockle *pockle, mp_int *p) pr = pockle->list[index]; if (mp_get_nbits(pr->prime) <= 64) { - strbuf_catf(sb, "\nType Small\nN "); + put_fmt(sb, "\nType Small\nN "); mp_write_decimal(sb, pr->prime); - strbuf_catf(sb, "\n"); + put_fmt(sb, "\n"); } else { assert(pr->witness); - strbuf_catf(sb, "\nType BLS5\nN "); + put_fmt(sb, "\nType BLS5\nN "); mp_write_decimal(sb, pr->prime); - strbuf_catf(sb, "\n"); + put_fmt(sb, "\n"); for (size_t i = 0; i < pr->nfactors; i++) { - strbuf_catf(sb, "Q[%"SIZEu"] ", i+1); + put_fmt(sb, "Q[%"SIZEu"] ", i+1); mp_write_decimal(sb, pr->factors[i]->prime); assert(pr->factors[i]->index < index); needed[pr->factors[i]->index] = true; - strbuf_catf(sb, "\n"); + put_fmt(sb, "\n"); } for (size_t i = 0; i < pr->nfactors + 1; i++) { - strbuf_catf(sb, "A[%"SIZEu"] ", i); + put_fmt(sb, "A[%"SIZEu"] ", i); mp_write_decimal(sb, pr->witness); - strbuf_catf(sb, "\n"); + put_fmt(sb, "\n"); } - strbuf_catf(sb, "----\n"); + put_fmt(sb, "----\n"); } } sfree(needed); diff --git a/marshal.h b/marshal.h index 108d8aeb..bcd2b38d 100644 --- a/marshal.h +++ b/marshal.h @@ -4,6 +4,7 @@ #include "defs.h" #include +#include /* * A sort of 'abstract base class' or 'interface' or 'trait' which is @@ -12,6 +13,7 @@ */ struct BinarySink { void (*write)(BinarySink *sink, const void *data, size_t len); + void (*writefmtv)(BinarySink *sink, const char *fmt, va_list ap); BinarySink *binarysink_; }; @@ -25,6 +27,7 @@ struct BinarySink { #define BinarySink_IMPLEMENTATION BinarySink binarysink_[1] #define BinarySink_INIT(obj, writefn) \ ((obj)->binarysink_->write = (writefn), \ + (obj)->binarysink_->writefmtv = NULL, \ (obj)->binarysink_->binarysink_ = (obj)->binarysink_) /* @@ -139,6 +142,12 @@ struct BinarySink { #define put_datapl(bs, pl) \ BinarySink_put_datapl(BinarySink_UPCAST(bs), pl) +/* Emit printf-formatted data, with no terminator. */ +#define put_fmt(bs, ...) \ + BinarySink_put_fmt(BinarySink_UPCAST(bs), __VA_ARGS__) +#define put_fmtv(bs, fmt, ap) \ + BinarySink_put_fmtv(BinarySink_UPCAST(bs), fmt, ap) + /* * The underlying real C functions that implement most of those * macros. Generally you won't want to call these directly, because @@ -166,6 +175,8 @@ void BinarySink_put_asciz(BinarySink *, const char *str); bool BinarySink_put_pstring(BinarySink *, const char *str); void BinarySink_put_mp_ssh1(BinarySink *bs, mp_int *x); void BinarySink_put_mp_ssh2(BinarySink *bs, mp_int *x); +void BinarySink_put_fmt(BinarySink *, const char *fmt, ...) PRINTF_LIKE(2, 3); +void BinarySink_put_fmtv(BinarySink *, const char *fmt, va_list ap); /* ---------------------------------------------------------------------- */ diff --git a/misc.h b/misc.h index 84643936..0cb55b65 100644 --- a/misc.h +++ b/misc.h @@ -56,8 +56,6 @@ void *strbuf_append(strbuf *buf, size_t len); void strbuf_shrink_to(strbuf *buf, size_t new_len); void strbuf_shrink_by(strbuf *buf, size_t amount_to_remove); char *strbuf_to_str(strbuf *buf); /* does free buf, but you must free result */ -void strbuf_catf(strbuf *buf, const char *fmt, ...) PRINTF_LIKE(2, 3); -void strbuf_catfv(strbuf *buf, const char *fmt, va_list ap); static inline void strbuf_clear(strbuf *buf) { strbuf_shrink_to(buf, 0); } bool strbuf_chomp(strbuf *buf, char char_to_remove); diff --git a/otherbackends/supdup.c b/otherbackends/supdup.c index 5c9494d5..a272b256 100644 --- a/otherbackends/supdup.c +++ b/otherbackends/supdup.c @@ -289,7 +289,7 @@ static void do_argsdone(Supdup *supdup, strbuf *outbuf, int c) */ // We only care about the new position. - strbuf_catf(outbuf, "\033[%d;%dH", supdup->td_args[2]+1, supdup->td_args[3]+1); + put_fmt(outbuf, "\033[%d;%dH", supdup->td_args[2]+1, supdup->td_args[3]+1); break; case TDMV0: @@ -298,7 +298,7 @@ static void do_argsdone(Supdup *supdup, strbuf *outbuf, int c) General cursor position code. Followed by two bytes; the new vertical and horizontal positions. */ - strbuf_catf(outbuf, "\033[%d;%dH", supdup->td_args[0]+1, supdup->td_args[1]+1); + put_fmt(outbuf, "\033[%d;%dH", supdup->td_args[0]+1, supdup->td_args[1]+1); break; case TDEOF: @@ -312,7 +312,7 @@ static void do_argsdone(Supdup *supdup, strbuf *outbuf, int c) lines lower on the screen than the cursor. The cursor does not move. */ - strbuf_catf(outbuf, "\033[J"); + put_fmt(outbuf, "\033[J"); break; case TDEOL: @@ -321,7 +321,7 @@ static void do_argsdone(Supdup *supdup, strbuf *outbuf, int c) position the cursor is at and all positions to the right on the same line. The cursor does not move. */ - strbuf_catf(outbuf, "\033[K"); + put_fmt(outbuf, "\033[K"); break; case TDDLF: @@ -329,7 +329,7 @@ static void do_argsdone(Supdup *supdup, strbuf *outbuf, int c) Clear the character position the cursor is on. The cursor does not move. */ - strbuf_catf(outbuf, "\033[X"); + put_fmt(outbuf, "\033[X"); break; case TDCRL: @@ -339,7 +339,7 @@ static void do_argsdone(Supdup *supdup, strbuf *outbuf, int c) that line. If the cursor is at the bottom line, scroll up. */ - strbuf_catf(outbuf, "\015\012"); + put_fmt(outbuf, "\015\012"); break; case TDNOP: @@ -383,7 +383,7 @@ static void do_argsdone(Supdup *supdup, strbuf *outbuf, int c) line. */ - strbuf_catf(outbuf, "\033[C"); + put_fmt(outbuf, "\033[C"); break; case TDCLR: @@ -391,7 +391,7 @@ static void do_argsdone(Supdup *supdup, strbuf *outbuf, int c) Erase the screen. Home the cursor to the top left hand corner of the screen. */ - strbuf_catf(outbuf, "\033[2J\033[H"); + put_fmt(outbuf, "\033[2J\033[H"); break; case TDBEL: @@ -399,7 +399,7 @@ static void do_argsdone(Supdup *supdup, strbuf *outbuf, int c) Generate an audio tone, bell, whatever. */ - strbuf_catf(outbuf, "\007"); + put_fmt(outbuf, "\007"); break; case TDILP: @@ -410,7 +410,7 @@ static void do_argsdone(Supdup *supdup, strbuf *outbuf, int c) on and all lines below it move down; lines moved off the bottom of the screen are lost. */ - strbuf_catf(outbuf, "\033[%dL", supdup->td_args[0]); + put_fmt(outbuf, "\033[%dL", supdup->td_args[0]); break; case TDDLP: @@ -421,7 +421,7 @@ static void do_argsdone(Supdup *supdup, strbuf *outbuf, int c) Newly- created lines at the bottom of the screen are blank. */ - strbuf_catf(outbuf, "\033[%dM", supdup->td_args[0]); + put_fmt(outbuf, "\033[%dM", supdup->td_args[0]); break; case TDICP: @@ -432,7 +432,7 @@ static void do_argsdone(Supdup *supdup, strbuf *outbuf, int c) current line move to the right; characters moved off the end of the line are lost. */ - strbuf_catf(outbuf, "\033[%d@", supdup->td_args[0]); + put_fmt(outbuf, "\033[%d@", supdup->td_args[0]); break; case TDDCP: @@ -442,7 +442,7 @@ static void do_argsdone(Supdup *supdup, strbuf *outbuf, int c) the one the cursor is on. Newly-created characters at the end of the line are blank. */ - strbuf_catf(outbuf, "\033[%dP", supdup->td_args[0]); + put_fmt(outbuf, "\033[%dP", supdup->td_args[0]); break; case TDBOW: diff --git a/proxy/proxy.c b/proxy/proxy.c index d6041754..c3a882e6 100644 --- a/proxy/proxy.c +++ b/proxy/proxy.c @@ -1369,7 +1369,7 @@ char *format_telnet_command(SockAddr *addr, int port, Conf *conf) eo += 4; } else if (strnicmp(fmt + eo, "port", 4) == 0) { - strbuf_catf(buf, "%d", port); + put_fmt(buf, "%d", port); eo += 4; } else if (strnicmp(fmt + eo, "user", 4) == 0) { @@ -1389,7 +1389,7 @@ char *format_telnet_command(SockAddr *addr, int port, Conf *conf) } else if (strnicmp(fmt + eo, "proxyport", 9) == 0) { int port = conf_get_int(conf, CONF_proxy_port); - strbuf_catf(buf, "%d", port); + put_fmt(buf, "%d", port); eo += 9; } else { diff --git a/ssh/scpserver.c b/ssh/scpserver.c index 97b20814..15633ecb 100644 --- a/ssh/scpserver.c +++ b/ssh/scpserver.c @@ -536,7 +536,7 @@ static void scp_source_send_E(ScpSource *scp) assert(scp->n_pending_commands == 0); scp->pending_commands[scp->n_pending_commands++] = cmd = strbuf_new(); - strbuf_catf(cmd, "E\012"); + put_fmt(cmd, "E\012"); } static void scp_source_send_CD( @@ -550,7 +550,7 @@ static void scp_source_send_CD( if (scp->send_file_times && (attrs.flags & SSH_FILEXFER_ATTR_ACMODTIME)) { scp->pending_commands[scp->n_pending_commands++] = cmd = strbuf_new(); /* Our SFTP-based filesystem API doesn't support microsecond times */ - strbuf_catf(cmd, "T%lu 0 %lu 0\012", attrs.mtime, attrs.atime); + put_fmt(cmd, "T%lu 0 %lu 0\012", attrs.mtime, attrs.atime); } const char *slash; @@ -559,9 +559,9 @@ static void scp_source_send_CD( slash+1, name.len - (slash+1 - (const char *)name.ptr)); scp->pending_commands[scp->n_pending_commands++] = cmd = strbuf_new(); - strbuf_catf(cmd, "%c%04o %"PRIu64" %.*s\012", cmdchar, - (unsigned)(attrs.permissions & 07777), - size, PTRLEN_PRINTF(name)); + put_fmt(cmd, "%c%04o %"PRIu64" %.*s\012", cmdchar, + (unsigned)(attrs.permissions & 07777), + size, PTRLEN_PRINTF(name)); if (cmdchar == 'C') { /* We'll also wait for an ack before sending the file data, diff --git a/sshpubk.c b/sshpubk.c index e7197de3..003213ca 100644 --- a/sshpubk.c +++ b/sshpubk.c @@ -1550,33 +1550,33 @@ strbuf *ppk_save_sb(ssh2_userkey *key, const char *passphrase, } strbuf *out = strbuf_new_nm(); - strbuf_catf(out, "PuTTY-User-Key-File-%u: %s\n", - params.fmt_version, ssh_key_ssh_id(key->key)); - strbuf_catf(out, "Encryption: %s\n", cipherstr); - strbuf_catf(out, "Comment: %s\n", key->comment); - strbuf_catf(out, "Public-Lines: %d\n", base64_lines(pub_blob->len)); + put_fmt(out, "PuTTY-User-Key-File-%u: %s\n", + params.fmt_version, ssh_key_ssh_id(key->key)); + put_fmt(out, "Encryption: %s\n", cipherstr); + put_fmt(out, "Comment: %s\n", key->comment); + put_fmt(out, "Public-Lines: %d\n", base64_lines(pub_blob->len)); base64_encode_s(BinarySink_UPCAST(out), pub_blob->u, pub_blob->len, 64); if (params.fmt_version == 3 && ciphertype->keylen != 0) { - strbuf_catf(out, "Key-Derivation: %s\n", - params.argon2_flavour == Argon2d ? "Argon2d" : - params.argon2_flavour == Argon2i ? "Argon2i" : "Argon2id"); - strbuf_catf(out, "Argon2-Memory: %"PRIu32"\n", params.argon2_mem); + put_fmt(out, "Key-Derivation: %s\n", + params.argon2_flavour == Argon2d ? "Argon2d" : + params.argon2_flavour == Argon2i ? "Argon2i" : "Argon2id"); + put_fmt(out, "Argon2-Memory: %"PRIu32"\n", params.argon2_mem); assert(!params.argon2_passes_auto); - strbuf_catf(out, "Argon2-Passes: %"PRIu32"\n", params.argon2_passes); - strbuf_catf(out, "Argon2-Parallelism: %"PRIu32"\n", - params.argon2_parallelism); - strbuf_catf(out, "Argon2-Salt: "); + put_fmt(out, "Argon2-Passes: %"PRIu32"\n", params.argon2_passes); + put_fmt(out, "Argon2-Parallelism: %"PRIu32"\n", + params.argon2_parallelism); + put_fmt(out, "Argon2-Salt: "); for (size_t i = 0; i < passphrase_salt->len; i++) - strbuf_catf(out, "%02x", passphrase_salt->u[i]); - strbuf_catf(out, "\n"); + put_fmt(out, "%02x", passphrase_salt->u[i]); + put_fmt(out, "\n"); } - strbuf_catf(out, "Private-Lines: %d\n", base64_lines(priv_encrypted_len)); + put_fmt(out, "Private-Lines: %d\n", base64_lines(priv_encrypted_len)); base64_encode_s(BinarySink_UPCAST(out), priv_blob_encrypted, priv_encrypted_len, 64); - strbuf_catf(out, "Private-MAC: "); + put_fmt(out, "Private-MAC: "); for (i = 0; i < macalg->len; i++) - strbuf_catf(out, "%02x", priv_mac[i]); - strbuf_catf(out, "\n"); + put_fmt(out, "%02x", priv_mac[i]); + put_fmt(out, "\n"); strbuf_free(cipher_mac_keys_blob); strbuf_free(passphrase_salt); @@ -1740,7 +1740,7 @@ static void ssh2_fingerprint_blob_md5(ptrlen blob, strbuf *sb) hash_simple(&ssh_md5, blob, digest); for (unsigned i = 0; i < 16; i++) - strbuf_catf(sb, "%02x%s", digest[i], i==15 ? "" : ":"); + put_fmt(sb, "%02x%s", digest[i], i==15 ? "" : ":"); } static void ssh2_fingerprint_blob_sha256(ptrlen blob, strbuf *sb) @@ -1778,9 +1778,9 @@ char *ssh2_fingerprint_blob(ptrlen blob, FingerprintType fptype) const ssh_keyalg *alg = find_pubkey_alg_len(algname); if (alg) { int bits = ssh_key_public_bits(alg, blob); - strbuf_catf(sb, "%.*s %d ", PTRLEN_PRINTF(algname), bits); + put_fmt(sb, "%.*s %d ", PTRLEN_PRINTF(algname), bits); } else { - strbuf_catf(sb, "%.*s ", PTRLEN_PRINTF(algname)); + put_fmt(sb, "%.*s ", PTRLEN_PRINTF(algname)); } } diff --git a/testcrypt.c b/testcrypt.c index 1b875c2b..2376fa04 100644 --- a/testcrypt.c +++ b/testcrypt.c @@ -592,7 +592,7 @@ static struct mpint_list get_mpint_list(BinarySource *in) static void finaliser_return_uint(strbuf *out, void *ctx) { unsigned *uval = (unsigned *)ctx; - strbuf_catf(out, "%u\n", *uval); + put_fmt(out, "%u\n", *uval); sfree(uval); } @@ -620,7 +620,7 @@ static void finaliser_return_opt_string_asciz(strbuf *out, void *ctx) char *val = *valp; sfree(valp); if (!val) - strbuf_catf(out, "NULL\n"); + put_fmt(out, "NULL\n"); else return_val_string_asciz(out, val); } @@ -639,7 +639,7 @@ static void finaliser_return_opt_string_asciz_const(strbuf *out, void *ctx) const char *val = *valp; sfree(valp); if (!val) - strbuf_catf(out, "NULL\n"); + put_fmt(out, "NULL\n"); else return_val_string_asciz_const(out, val); } @@ -676,29 +676,29 @@ GET_CONSUMED_FN(pcs) static void return_int(strbuf *out, intmax_t u) { - strbuf_catf(out, "%"PRIdMAX"\n", u); + put_fmt(out, "%"PRIdMAX"\n", u); } static void return_uint(strbuf *out, uintmax_t u) { - strbuf_catf(out, "0x%"PRIXMAX"\n", u); + put_fmt(out, "0x%"PRIXMAX"\n", u); } static void return_boolean(strbuf *out, bool b) { - strbuf_catf(out, "%s\n", b ? "true" : "false"); + put_fmt(out, "%s\n", b ? "true" : "false"); } static void return_pocklestatus(strbuf *out, PockleStatus status) { switch (status) { default: - strbuf_catf(out, "POCKLE_BAD_STATUS_VALUE\n"); + put_fmt(out, "POCKLE_BAD_STATUS_VALUE\n"); break; #define STATUS_CASE(id) \ case id: \ - strbuf_catf(out, "%s\n", #id); \ + put_fmt(out, "%s\n", #id); \ break; POCKLE_STATUSES(STATUS_CASE); @@ -711,11 +711,11 @@ static void return_pocklestatus(strbuf *out, PockleStatus status) static void return_mr_result(strbuf *out, struct mr_result result) { if (!result.passed) - strbuf_catf(out, "failed\n"); + put_fmt(out, "failed\n"); else if (!result.potential_primitive_root) - strbuf_catf(out, "passed\n"); + put_fmt(out, "passed\n"); else - strbuf_catf(out, "passed+ppr\n"); + put_fmt(out, "passed+ppr\n"); } static void return_val_string_asciz_const(strbuf *out, const char *s) @@ -735,7 +735,7 @@ static void return_val_string_asciz(strbuf *out, char *s) static void return_opt_##type_name(strbuf *out, c_type ptr) \ { \ if (!ptr) \ - strbuf_catf(out, "NULL\n"); \ + put_fmt(out, "NULL\n"); \ else \ return_##type_name(out, ptr); \ } @@ -750,7 +750,7 @@ NULLABLE_RETURN_WRAPPER(val_mpint, mp_int *) static void handle_hello(BinarySource *in, strbuf *out) { - strbuf_catf(out, "hello, world\n"); + put_fmt(out, "hello, world\n"); } static void rsa_free(RSAKey *rsa) @@ -803,7 +803,7 @@ static void handle_getstring(BinarySource *in, strbuf *out) if (c > ' ' && c < 0x7F && c != '%') { put_byte(out, c); } else { - strbuf_catf(out, "%%%02X", 0xFFU & (unsigned)c); + put_fmt(out, "%%%02X", 0xFFU & (unsigned)c); } } put_byte(out, '\n'); @@ -822,7 +822,7 @@ static void handle_mp_dump(BinarySource *in, strbuf *out) { mp_int *mp = get_val_mpint(in); for (size_t i = mp_max_bytes(mp); i-- > 0 ;) - strbuf_catf(out, "%02X", mp_get_byte(mp, i)); + put_fmt(out, "%02X", mp_get_byte(mp, i)); put_byte(out, '\n'); } @@ -1320,26 +1320,26 @@ strbuf *get_implementations_commasep(ptrlen alg) put_datapl(out, alg); if (ptrlen_startswith(alg, PTRLEN_LITERAL("aes"), NULL)) { - strbuf_catf(out, ",%.*s_sw", PTRLEN_PRINTF(alg)); + put_fmt(out, ",%.*s_sw", PTRLEN_PRINTF(alg)); #if HAVE_AES_NI - strbuf_catf(out, ",%.*s_ni", PTRLEN_PRINTF(alg)); + put_fmt(out, ",%.*s_ni", PTRLEN_PRINTF(alg)); #endif #if HAVE_NEON_CRYPTO - strbuf_catf(out, ",%.*s_neon", PTRLEN_PRINTF(alg)); + put_fmt(out, ",%.*s_neon", PTRLEN_PRINTF(alg)); #endif } else if (ptrlen_startswith(alg, PTRLEN_LITERAL("sha256"), NULL) || ptrlen_startswith(alg, PTRLEN_LITERAL("sha1"), NULL)) { - strbuf_catf(out, ",%.*s_sw", PTRLEN_PRINTF(alg)); + put_fmt(out, ",%.*s_sw", PTRLEN_PRINTF(alg)); #if HAVE_SHA_NI - strbuf_catf(out, ",%.*s_ni", PTRLEN_PRINTF(alg)); + put_fmt(out, ",%.*s_ni", PTRLEN_PRINTF(alg)); #endif #if HAVE_NEON_CRYPTO - strbuf_catf(out, ",%.*s_neon", PTRLEN_PRINTF(alg)); + put_fmt(out, ",%.*s_neon", PTRLEN_PRINTF(alg)); #endif } else if (ptrlen_startswith(alg, PTRLEN_LITERAL("sha512"), NULL)) { - strbuf_catf(out, ",%.*s_sw", PTRLEN_PRINTF(alg)); + put_fmt(out, ",%.*s_sw", PTRLEN_PRINTF(alg)); #if HAVE_NEON_SHA512 - strbuf_catf(out, ",%.*s_neon", PTRLEN_PRINTF(alg)); + put_fmt(out, ",%.*s_neon", PTRLEN_PRINTF(alg)); #endif } diff --git a/unix/dialog.c b/unix/dialog.c index 743be31d..9ba1e164 100644 --- a/unix/dialog.c +++ b/unix/dialog.c @@ -3615,12 +3615,12 @@ int gtk_seat_confirm_ssh_host_key( strbuf *sb = strbuf_new(); if (fingerprints[SSH_FPTYPE_SHA256]) - strbuf_catf(sb, "SHA256 fingerprint: %s\n", - fingerprints[SSH_FPTYPE_SHA256]); + put_fmt(sb, "SHA256 fingerprint: %s\n", + fingerprints[SSH_FPTYPE_SHA256]); if (fingerprints[SSH_FPTYPE_MD5]) - strbuf_catf(sb, "MD5 fingerprint: %s\n", - fingerprints[SSH_FPTYPE_MD5]); - strbuf_catf(sb, "Full text of host's public key:"); + put_fmt(sb, "MD5 fingerprint: %s\n", + fingerprints[SSH_FPTYPE_MD5]); + put_fmt(sb, "Full text of host's public key:"); /* We have to manually wrap the public key, or else the GtkLabel * will resize itself to accommodate the longest word, which will * lead to a hilariously wide message box. */ @@ -3943,12 +3943,12 @@ static void eventlog_list_handler(union control *ctrl, dlgparam *dp, strbuf_clear(es->seldata); for (i = 0; i < es->ninitial; i++) { if (dlg_listbox_issel(ctrl, dp, i)) - strbuf_catf(es->seldata, "%s\n", es->events_initial[i]); + put_fmt(es->seldata, "%s\n", es->events_initial[i]); } for (i = 0; i < es->ncircular; i++) { if (dlg_listbox_issel(ctrl, dp, es->ninitial + i)) { int j = (es->circular_first + i) % LOGEVENT_CIRCULAR_MAX; - strbuf_catf(es->seldata, "%s\n", es->events_circular[j]); + put_fmt(es->seldata, "%s\n", es->events_circular[j]); } } diff --git a/unix/network.c b/unix/network.c index b8f923e9..fe0bc70b 100644 --- a/unix/network.c +++ b/unix/network.c @@ -232,9 +232,9 @@ SockAddr *sk_namelookup(const char *host, char **canonicalname, int address_fami ret->superfamily = IP; if (ret->ais->ai_canonname != NULL) - strbuf_catf(realhost, "%s", ret->ais->ai_canonname); + put_fmt(realhost, "%s", ret->ais->ai_canonname); else - strbuf_catf(realhost, "%s", host); + put_fmt(realhost, "%s", host); #else if ((a = inet_addr(host)) == (unsigned long)(in_addr_t)(-1)) { /* @@ -258,7 +258,7 @@ SockAddr *sk_namelookup(const char *host, char **canonicalname, int address_fami } /* This way we are always sure the h->h_name is valid :) */ strbuf_clear(realhost); - strbuf_catf(realhost, "%s", h->h_name); + put_fmt(realhost, "%s", h->h_name); for (n = 0; h->h_addr_list[n]; n++); ret->addresses = snewn(n, unsigned long); ret->naddresses = n; @@ -273,7 +273,7 @@ SockAddr *sk_namelookup(const char *host, char **canonicalname, int address_fami */ ret->superfamily = IP; strbuf_clear(realhost); - strbuf_catf(realhost, "%s", host); + put_fmt(realhost, "%s", host); ret->addresses = snew(unsigned long); ret->naddresses = 1; ret->addresses[0] = ntohl(a); diff --git a/unix/procnet.c b/unix/procnet.c index 43b1f055..09373956 100644 --- a/unix/procnet.c +++ b/unix/procnet.c @@ -170,8 +170,8 @@ static char *format_sockaddr(const void *addr, int family) const uint32_t *addrwords = (const uint32_t *)a->sin6_addr.s6_addr; for (int i = 0; i < 4; i++) - strbuf_catf(sb, "%08X", addrwords[i]); - strbuf_catf(sb, ":%04X", ntohs(a->sin6_port)); + put_fmt(sb, "%08X", addrwords[i]); + put_fmt(sb, ":%04X", ntohs(a->sin6_port)); return strbuf_to_str(sb); } else { diff --git a/unix/storage.c b/unix/storage.c index 16bb63e0..7a9585f9 100644 --- a/unix/storage.c +++ b/unix/storage.c @@ -173,7 +173,7 @@ static char *make_filename(int index, const char *subname) if (index == INDEX_SESSION) { strbuf *sb = strbuf_new(); tmp = make_filename(INDEX_SESSIONDIR, NULL); - strbuf_catf(sb, "%s/", tmp); + put_fmt(sb, "%s/", tmp); sfree(tmp); make_session_filename(subname, sb); return strbuf_to_str(sb); diff --git a/unix/unifont.c b/unix/unifont.c index d50a7810..62445db2 100644 --- a/unix/unifont.c +++ b/unix/unifont.c @@ -1904,19 +1904,19 @@ static void pangofont_enum_fonts(GtkWidget *widget, fontsel_add_entry callback, /* Weight: normal, then lighter, then bolder */ if (weight <= PANGO_WEIGHT_NORMAL) weight = PANGO_WEIGHT_NORMAL - weight; - strbuf_catf(buf, "%4d", weight); + put_fmt(buf, "%4d", weight); - strbuf_catf(buf, " %2d", - pango_font_description_get_style(desc)); + put_fmt(buf, " %2d", + pango_font_description_get_style(desc)); int stretch = pango_font_description_get_stretch(desc); /* Stretch: closer to normal sorts earlier */ stretch = 2 * abs(PANGO_STRETCH_NORMAL - stretch) + (stretch < PANGO_STRETCH_NORMAL); - strbuf_catf(buf, " %2d", stretch); + put_fmt(buf, " %2d", stretch); - strbuf_catf(buf, " %2d", - pango_font_description_get_variant(desc)); + put_fmt(buf, " %2d", + pango_font_description_get_variant(desc)); stylekey = strbuf_to_str(buf); } diff --git a/utils/antispoof.c b/utils/antispoof.c index 60769af4..b3a04ef3 100644 --- a/utils/antispoof.c +++ b/utils/antispoof.c @@ -18,7 +18,7 @@ void seat_antispoof_msg(InteractionReadySeat iseat, const char *msg) * wouldn't be able to mimic it within our line-length * constraint. */ - strbuf_catf(sb, "-- %s ", msg); + put_fmt(sb, "-- %s ", msg); while (sb->len < 78) put_byte(sb, '-'); } diff --git a/utils/buildinfo.c b/utils/buildinfo.c index 2c40d6c2..3e42dec9 100644 --- a/utils/buildinfo.c +++ b/utils/buildinfo.c @@ -10,26 +10,25 @@ char *buildinfo(const char *newline) { strbuf *buf = strbuf_new(); - strbuf_catf(buf, "Build platform: %d-bit %s", - (int)(CHAR_BIT * sizeof(void *)), - BUILDINFO_PLATFORM); + put_fmt(buf, "Build platform: %d-bit %s", + (int)(CHAR_BIT * sizeof(void *)), BUILDINFO_PLATFORM); #ifdef __clang_version__ #define FOUND_COMPILER - strbuf_catf(buf, "%sCompiler: clang %s", newline, __clang_version__); + put_fmt(buf, "%sCompiler: clang %s", newline, __clang_version__); #elif defined __GNUC__ && defined __VERSION__ #define FOUND_COMPILER - strbuf_catf(buf, "%sCompiler: gcc %s", newline, __VERSION__); + put_fmt(buf, "%sCompiler: gcc %s", newline, __VERSION__); #endif #if defined _MSC_VER #ifndef FOUND_COMPILER #define FOUND_COMPILER - strbuf_catf(buf, "%sCompiler: ", newline); + put_fmt(buf, "%sCompiler: ", newline); #else - strbuf_catf(buf, ", emulating "); + put_fmt(buf, ", emulating "); #endif - strbuf_catf(buf, "Visual Studio"); + put_fmt(buf, "Visual Studio"); #if 0 /* @@ -51,69 +50,69 @@ char *buildinfo(const char *newline) * 19.28.29500.* and going up. Hence, 19 28 29500 is what we * compare _MSC_FULL_VER against above. */ - strbuf_catf(buf, " 2019 (16.9)"); + put_fmt(buf, " 2019 (16.9)"); #elif _MSC_VER == 1928 - strbuf_catf(buf, " 2019 (16.8)"); + put_fmt(buf, " 2019 (16.8)"); #elif _MSC_VER == 1927 - strbuf_catf(buf, " 2019 (16.7)"); + put_fmt(buf, " 2019 (16.7)"); #elif _MSC_VER == 1926 - strbuf_catf(buf, " 2019 (16.6)"); + put_fmt(buf, " 2019 (16.6)"); #elif _MSC_VER == 1925 - strbuf_catf(buf, " 2019 (16.5)"); + put_fmt(buf, " 2019 (16.5)"); #elif _MSC_VER == 1924 - strbuf_catf(buf, " 2019 (16.4)"); + put_fmt(buf, " 2019 (16.4)"); #elif _MSC_VER == 1923 - strbuf_catf(buf, " 2019 (16.3)"); + put_fmt(buf, " 2019 (16.3)"); #elif _MSC_VER == 1922 - strbuf_catf(buf, " 2019 (16.2)"); + put_fmt(buf, " 2019 (16.2)"); #elif _MSC_VER == 1921 - strbuf_catf(buf, " 2019 (16.1)"); + put_fmt(buf, " 2019 (16.1)"); #elif _MSC_VER == 1920 - strbuf_catf(buf, " 2019 (16.0)"); + put_fmt(buf, " 2019 (16.0)"); #elif _MSC_VER == 1916 - strbuf_catf(buf, " 2017 version 15.9"); + put_fmt(buf, " 2017 version 15.9"); #elif _MSC_VER == 1915 - strbuf_catf(buf, " 2017 version 15.8"); + put_fmt(buf, " 2017 version 15.8"); #elif _MSC_VER == 1914 - strbuf_catf(buf, " 2017 version 15.7"); + put_fmt(buf, " 2017 version 15.7"); #elif _MSC_VER == 1913 - strbuf_catf(buf, " 2017 version 15.6"); + put_fmt(buf, " 2017 version 15.6"); #elif _MSC_VER == 1912 - strbuf_catf(buf, " 2017 version 15.5"); + put_fmt(buf, " 2017 version 15.5"); #elif _MSC_VER == 1911 - strbuf_catf(buf, " 2017 version 15.3"); + put_fmt(buf, " 2017 version 15.3"); #elif _MSC_VER == 1910 - strbuf_catf(buf, " 2017 RTW (15.0)"); + put_fmt(buf, " 2017 RTW (15.0)"); #elif _MSC_VER == 1900 - strbuf_catf(buf, " 2015 (14.0)"); + put_fmt(buf, " 2015 (14.0)"); #elif _MSC_VER == 1800 - strbuf_catf(buf, " 2013 (12.0)"); + put_fmt(buf, " 2013 (12.0)"); #elif _MSC_VER == 1700 - strbuf_catf(buf, " 2012 (11.0)"); + put_fmt(buf, " 2012 (11.0)"); #elif _MSC_VER == 1600 - strbuf_catf(buf, " 2010 (10.0)"); + put_fmt(buf, " 2010 (10.0)"); #elif _MSC_VER == 1500 - strbuf_catf(buf, " 2008 (9.0)"); + put_fmt(buf, " 2008 (9.0)"); #elif _MSC_VER == 1400 - strbuf_catf(buf, " 2005 (8.0)"); + put_fmt(buf, " 2005 (8.0)"); #elif _MSC_VER == 1310 - strbuf_catf(buf, " .NET 2003 (7.1)"); + put_fmt(buf, " .NET 2003 (7.1)"); #elif _MSC_VER == 1300 - strbuf_catf(buf, " .NET 2002 (7.0)"); + put_fmt(buf, " .NET 2002 (7.0)"); #elif _MSC_VER == 1200 - strbuf_catf(buf, " 6.0"); + put_fmt(buf, " 6.0"); #else - strbuf_catf(buf, ", unrecognised version"); + put_fmt(buf, ", unrecognised version"); #endif - strbuf_catf(buf, ", _MSC_VER=%d", (int)_MSC_VER); + put_fmt(buf, ", _MSC_VER=%d", (int)_MSC_VER); #endif #ifdef BUILDINFO_GTK { char *gtk_buildinfo = buildinfo_gtk_version(); if (gtk_buildinfo) { - strbuf_catf(buf, "%sCompiled against GTK version %s", - newline, gtk_buildinfo); + put_fmt(buf, "%sCompiled against GTK version %s", + newline, gtk_buildinfo); sfree(gtk_buildinfo); } } @@ -122,34 +121,34 @@ char *buildinfo(const char *newline) { int echm = has_embedded_chm(); if (echm >= 0) - strbuf_catf(buf, "%sEmbedded HTML Help file: %s", newline, - echm ? "yes" : "no"); + put_fmt(buf, "%sEmbedded HTML Help file: %s", newline, + echm ? "yes" : "no"); } #endif #if defined _WINDOWS && defined MINEFIELD - strbuf_catf(buf, "%sBuild option: MINEFIELD", newline); + put_fmt(buf, "%sBuild option: MINEFIELD", newline); #endif #ifdef NO_IPV6 - strbuf_catf(buf, "%sBuild option: NO_IPV6", newline); + put_fmt(buf, "%sBuild option: NO_IPV6", newline); #endif #ifdef NO_GSSAPI - strbuf_catf(buf, "%sBuild option: NO_GSSAPI", newline); + put_fmt(buf, "%sBuild option: NO_GSSAPI", newline); #endif #ifdef STATIC_GSSAPI - strbuf_catf(buf, "%sBuild option: STATIC_GSSAPI", newline); + put_fmt(buf, "%sBuild option: STATIC_GSSAPI", newline); #endif #ifdef UNPROTECT - strbuf_catf(buf, "%sBuild option: UNPROTECT", newline); + put_fmt(buf, "%sBuild option: UNPROTECT", newline); #endif #ifdef FUZZING - strbuf_catf(buf, "%sBuild option: FUZZING", newline); + put_fmt(buf, "%sBuild option: FUZZING", newline); #endif #ifdef DEBUG - strbuf_catf(buf, "%sBuild option: DEBUG", newline); + put_fmt(buf, "%sBuild option: DEBUG", newline); #endif - strbuf_catf(buf, "%sSource commit: %s", newline, commitid); + put_fmt(buf, "%sSource commit: %s", newline, commitid); return strbuf_to_str(buf); } diff --git a/utils/marshal.c b/utils/marshal.c index ff9bb851..84d1391f 100644 --- a/utils/marshal.c +++ b/utils/marshal.c @@ -1,4 +1,5 @@ #include +#include #include #include @@ -99,6 +100,25 @@ bool BinarySink_put_pstring(BinarySink *bs, const char *str) return true; } +void BinarySink_put_fmtv(BinarySink *bs, const char *fmt, va_list ap) +{ + if (bs->writefmtv) { + bs->writefmtv(bs, fmt, ap); + } else { + char *str = dupvprintf(fmt, ap); + bs->write(bs, str, strlen(str)); + burnstr(str); + } +} + +void BinarySink_put_fmt(BinarySink *bs, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + BinarySink_put_fmtv(bs, fmt, ap); + va_end(ap); +} + /* ---------------------------------------------------------------------- */ static bool BinarySource_data_avail(BinarySource *src, size_t wanted) diff --git a/utils/strbuf.c b/utils/strbuf.c index 8358a413..636467a4 100644 --- a/utils/strbuf.c +++ b/utils/strbuf.c @@ -60,10 +60,21 @@ static void strbuf_BinarySink_write( memcpy(strbuf_append(buf_o, len), data, len); } +static void strbuf_BinarySink_writefmtv( + BinarySink *bs, const char *fmt, va_list ap) +{ + strbuf *buf_o = BinarySink_DOWNCAST(bs, strbuf); + struct strbuf_impl *buf = container_of(buf_o, struct strbuf_impl, visible); + STRBUF_SET_PTR(buf, dupvprintf_inner(buf->visible.s, buf->visible.len, + &buf->size, fmt, ap)); + buf->visible.len += strlen(buf->visible.s + buf->visible.len); +} + static strbuf *strbuf_new_general(bool nm) { struct strbuf_impl *buf = snew(struct strbuf_impl); BinarySink_INIT(&buf->visible, strbuf_BinarySink_write); + buf->visible.binarysink_->writefmtv = strbuf_BinarySink_writefmtv; buf->visible.len = 0; buf->size = 512; buf->nm = nm; @@ -89,21 +100,6 @@ char *strbuf_to_str(strbuf *buf_o) sfree(buf); return ret; } -void strbuf_catfv(strbuf *buf_o, const char *fmt, va_list ap) -{ - struct strbuf_impl *buf = container_of(buf_o, struct strbuf_impl, visible); - STRBUF_SET_PTR(buf, dupvprintf_inner(buf->visible.s, buf->visible.len, - &buf->size, fmt, ap)); - buf->visible.len += strlen(buf->visible.s + buf->visible.len); -} -void strbuf_catf(strbuf *buf_o, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - strbuf_catfv(buf_o, fmt, ap); - va_end(ap); -} - strbuf *strbuf_new_for_agent_query(void) { strbuf *buf = strbuf_new(); diff --git a/windows/pageant.c b/windows/pageant.c index 0e25cc5d..6fbbf883 100644 --- a/windows/pageant.c +++ b/windows/pageant.c @@ -335,7 +335,7 @@ static void keylist_update_callback( switch (key->ssh_version) { case 1: { - strbuf_catf(listentry, "ssh1\t%s\t%s", fingerprint, comment); + put_fmt(listentry, "ssh1\t%s\t%s", fingerprint, comment); /* * Replace the space in the fingerprint (between bit count and @@ -390,15 +390,15 @@ static void keylist_update_callback( put_byte(listentry, c); } - strbuf_catf(listentry, "\t%s", comment); + put_fmt(listentry, "\t%s", comment); break; } } if (ext_flags & LIST_EXTENDED_FLAG_HAS_NO_CLEARTEXT_KEY) { - strbuf_catf(listentry, "\t(encrypted)"); + put_fmt(listentry, "\t(encrypted)"); } else if (ext_flags & LIST_EXTENDED_FLAG_HAS_ENCRYPTED_KEY_FILE) { - strbuf_catf(listentry, "\t(re-encryptable)"); + put_fmt(listentry, "\t(re-encryptable)"); /* At least one key can be re-encrypted */ ctx->enable_reencrypt_controls = true; diff --git a/windows/storage.c b/windows/storage.c index 2bb08953..6f05cdc7 100644 --- a/windows/storage.c +++ b/windows/storage.c @@ -318,7 +318,7 @@ void enum_settings_finish(settings_e *e) static void hostkey_regname(strbuf *sb, const char *hostname, int port, const char *keytype) { - strbuf_catf(sb, "%s@%d:", keytype, port); + put_fmt(sb, "%s@%d:", keytype, port); escape_registry_key(hostname, sb); } diff --git a/windows/utils/split_into_argv.c b/windows/utils/split_into_argv.c index c9f9e184..c42c7a0b 100644 --- a/windows/utils/split_into_argv.c +++ b/windows/utils/split_into_argv.c @@ -514,7 +514,7 @@ int main(int argc, char **argv) strbuf *cmdline = strbuf_new(); char *p; - strbuf_catf(cmdline, "%s -splat ", argv[0]); + put_fmt(cmdline, "%s -splat ", argv[0]); printf(" {\""); size_t args_start = cmdline->len; for (p = argv[2]; *p; p++) { diff --git a/windows/window.c b/windows/window.c index 8ab371bb..851dafb5 100644 --- a/windows/window.c +++ b/windows/window.c @@ -4946,7 +4946,7 @@ static void wintw_clip_write( get_unitab(CP_ACP, unitab, 0); - strbuf_catf( + put_fmt( rtf, "{\\rtf1\\ansi\\deff0{\\fonttbl\\f0\\fmodern %s;}\\f0\\fs%d", font->name, font->height*2); @@ -5034,16 +5034,16 @@ static void wintw_clip_write( for (i = 0; i < OSC4_NCOLOURS; i++) { if (palette[i] != 0) { const PALETTEENTRY *pe = &logpal->palPalEntry[i]; - strbuf_catf(rtf, "\\red%d\\green%d\\blue%d;", - pe->peRed, pe->peGreen, pe->peBlue); + put_fmt(rtf, "\\red%d\\green%d\\blue%d;", + pe->peRed, pe->peGreen, pe->peBlue); } } if (rgbtree) { rgbindex *rgbp; for (i = 0; (rgbp = index234(rgbtree, i)) != NULL; i++) - strbuf_catf(rtf, "\\red%d\\green%d\\blue%d;", - GetRValue(rgbp->ref), GetGValue(rgbp->ref), - GetBValue(rgbp->ref)); + put_fmt(rtf, "\\red%d\\green%d\\blue%d;", + GetRValue(rgbp->ref), GetGValue(rgbp->ref), + GetBValue(rgbp->ref)); } put_datapl(rtf, PTRLEN_LITERAL("}")); } @@ -5162,13 +5162,13 @@ static void wintw_clip_write( lastfgcolour = fgcolour; lastfg = fg; if (fg == -1) { - strbuf_catf(rtf, "\\cf%d ", - (fgcolour >= 0) ? palette[fgcolour] : 0); + put_fmt(rtf, "\\cf%d ", + (fgcolour >= 0) ? palette[fgcolour] : 0); } else { rgbindex rgb, *rgbp; rgb.ref = fg; if ((rgbp = find234(rgbtree, &rgb, NULL)) != NULL) - strbuf_catf(rtf, "\\cf%d ", rgbp->index); + put_fmt(rtf, "\\cf%d ", rgbp->index); } } @@ -5176,13 +5176,13 @@ static void wintw_clip_write( lastbgcolour = bgcolour; lastbg = bg; if (bg == -1) - strbuf_catf(rtf, "\\highlight%d ", - (bgcolour >= 0) ? palette[bgcolour] : 0); + put_fmt(rtf, "\\highlight%d ", + (bgcolour >= 0) ? palette[bgcolour] : 0); else { rgbindex rgb, *rgbp; rgb.ref = bg; if ((rgbp = find234(rgbtree, &rgb, NULL)) != NULL) - strbuf_catf(rtf, "\\highlight%d ", rgbp->index); + put_fmt(rtf, "\\highlight%d ", rgbp->index); } } @@ -5243,7 +5243,7 @@ static void wintw_clip_write( } else if (tdata[tindex+i] == 0x0D || tdata[tindex+i] == 0x0A) { put_datapl(rtf, PTRLEN_LITERAL("\\par\r\n")); } else if (tdata[tindex+i] > 0x7E || tdata[tindex+i] < 0x20) { - strbuf_catf(rtf, "\\'%02x", tdata[tindex+i]); + put_fmt(rtf, "\\'%02x", tdata[tindex+i]); } else { put_byte(rtf, tdata[tindex+i]); }