From 271cda44d5644185b1de775cca6e62aac4c5bb15 Mon Sep 17 00:00:00 2001 From: June McEnroe Date: Sat, 12 Jun 2021 16:36:13 -0400 Subject: Publish "seprintf" --- www/text.causal.agency/024-seprintf.7 | 137 ++++++++++++++++++++++++++++++++++ www/text.causal.agency/Makefile | 1 + 2 files changed, 138 insertions(+) create mode 100644 www/text.causal.agency/024-seprintf.7 (limited to 'www') diff --git a/www/text.causal.agency/024-seprintf.7 b/www/text.causal.agency/024-seprintf.7 new file mode 100644 index 00000000..d1af2e1a --- /dev/null +++ b/www/text.causal.agency/024-seprintf.7 @@ -0,0 +1,137 @@ +.Dd June 12, 2021 +.Dt SEPRINTF 7 +.Os "Causal Agency" +. +.Sh NAME +.Nm seprintf +.Nd an snprintf alternative +. +.Sh SYNOPSIS +.Ft "char *" +.Fn seprintf "char *ptr" "char *end" "const char *fmt" "..." +. +.Sh DESCRIPTION +While discussing string building in C recently, +mcf pointed out +.Xr seprint 2 +from Plan 9, +and it kind of blew my mind. +I had implemented my own function in +.Xr catgirl 1 +for building up strings using +.Xr snprintf 3 +and a struct containing +pointer, length and capacity, +but it felt out of place. +.Fn seprintf +(I add the +.Dq f , +Plan 9 doesn't) +is a much simpler +and more +.Dq C-like +interface with really nice usage patterns. +. +.Pp +The obvious difference from +.Xr snprintf 3 +is that +.Fn seprintf +takes an +.Fa end +pointer +rather than a size. +This means you need only calculate it +once for each buffer, +rather than subtracting +the running length from the buffer size. +.Fn seprintf Ap s +return value is a pointer +to the terminating null +of the string it wrote, +so you can pass that back in +to continue appending +to the same buffer. +. +.Pp +I'm not sure of the exact behaviour on Plan 9, +but my implementation indicates truncation occurred +by returning the +.Fa end +pointer. +That makes it both easy to check, +and perfectly fine to keep calling +.Fn seprintf +anyway. +It just won't write anything if +.Fa ptr +== +.Fa end . +. +.Pp +In the case of formatting failure +(which should be prevented by +compile-time format string checking, +but should still be considered), +.Fn seprintf +returns +.Dv NULL . +I'm again not sure if this matches Plan 9. +I like this a lot better than +.Xr snprintf 3 +returning -1, +because an unchecked +.Dv NULL +is likely to quickly cause a crash, +while blindly adding +.Xr snprintf 3 Ap s +return value +to your running length +is a non-obvious logic error. +. +.Sh EXAMPLES +Here's an example of what some code using +.Fn seprintf +might look like: +.Bd -literal -offset indent +char buf[4096]; +char *ptr = buf, *end = &buf[sizeof(buf)]; +ptr = seprintf(ptr, end, "argv: "); +for (int i = 1; i < argc; ++i) { + ptr = seprintf( + ptr, end, "%s%s", + (i > 1 ? ", " : ""), argv[i] + ); +} +if (ptr == end) errx(1, "truncation occurred :("); +.Ed +. +.Pp +And here is the very short implementation of it against +.Xr vsnprintf 3 +which I copy into my project header files: +.Bd -literal -offset indent +#include +#include +static inline char * +seprintf(char *ptr, char *end, const char *fmt, ...) + __attribute__((format(printf, 3, 4))); +static inline char * +seprintf(char *ptr, char *end, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + int n = vsnprintf(ptr, end - ptr, fmt, ap); + va_end(ap); + if (n < 0) return NULL; + if (n > end - ptr) return end; + return ptr + n; +} +.Ed +. +.Sh AUTHORS +.An june Aq Mt june@causal.agency +.Pp +Another short one before +.Xr git-subtree 1 . +I just think this function +is really neat. diff --git a/www/text.causal.agency/Makefile b/www/text.causal.agency/Makefile index 78665792..a9330045 100644 --- a/www/text.causal.agency/Makefile +++ b/www/text.causal.agency/Makefile @@ -26,6 +26,7 @@ TXTS += 020-c-style.txt TXTS += 021-time-machine.txt TXTS += 022-swans-are-dead.txt TXTS += 023-sparse-checkout.txt +TXTS += 024-seprintf.txt all: ${TXTS} -- cgit 1.4.1 f='/exman/commit/exman.1?h=2063.9&id=b49a923d2fe7a39034af0a654eef6d38a8669765&follow=1'>Update to FreeBSD 13.1 2062.83June McEnroe 2022-07-27openbsd: Include man pages from baseXX.tgzKeith Whitney A number of OpenBSD man pages are currently missing in exman, since they reside in OpenBSD's baseXX.tgz [1]: - help(1) - man(1) - pkg_add(1) - OpenBSD::BaseState(3p) - packages(7) - adduser(8) - afterboot(8) - user(8) - useradd(8) - userdel(8) - userinfo(8) - usermod(8) This patch adds baseXX.tgz to the OpenBSD distfiles, which begrudgingly adds ~330 MiB to the install. I figure this might acceptable since base.txz is similarly fetched for FreeBSD. Since this isn't ideal, I'll look into whether these man pages are intended to be in baseXX.tgz or not. If not, I'll see about changing this upstream, and this patch can be reverted. [1] Lines 2876-2931: https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/distrib/sets/lists/base/mi?annotate=1.1065 2022-05-08Update to OpenBSD 7.1 2062.73June McEnroe 2021-10-15Update to OpenBSD 7.0 2062.63June McEnroe 2021-08-29Update to Linux man-pages 5.13 2062.53Štěpán Němec 2021-08-26Update to NetBSD 9.2 2062.52June McEnroe 2021-08-26Support DESTDIR in install/uninstallJune McEnroe 2021-08-26Add version number generatorJune McEnroe 2021-08-22Add ISC license headerJune McEnroe 2021-08-22Update to Linux man-pages 5.12Štěpán Němec 2021-06-21Add manuals for macOS 11.3June McEnroe 2021-05-08Update to OpenBSD 6.9June McEnroe 2021-04-26Update to Linux man-pages 5.11June McEnroe 2021-04-26Update to FreeBSD 13.0June McEnroe 2021-01-27Completely rewrite how manuals are fetched and installedJune McEnroe Also add section 6 manuals from NetBSD and OpenBSD! 2020-12-14Update to man-pages-posix 2017-aJune McEnroe 2020-12-14Update to OpenBSD 6.8June McEnroe 2020-12-14Update to NetBSD 9.1June McEnroe 2020-12-14Update to man-pages 5.09June McEnroe 2020-12-14Update to FreeBSD 12.2June McEnroe 2020-06-08Update to OpenBSD 6.7June McEnroe 2020-05-04Add hack for macOS to search extra man sectionsJune McEnroe 2020-05-04Don't clear MANSECTJune McEnroe