.\" -*-nroff-*- .de VS .sp 1 .RS .nf .ft B .. .de VE .ft R .fi .RE .sp 1 .. .de hP .IP .ft B \h'-\w'\\$1\ 'u'\\$1\ \c .ft P .. .ie t .ds o \(bu .el .ds o o . .TH gprintf 3 "9 March 2024" "Straylight/Edgeware" "mLib utilities library" . .SH NAME gprintf \- generalized output formatting . .SH SYNOPSIS .nf .B "#include " .ta 2n .B "struct gprintf_ops {" .BI " int (*putch)(void *" out ", int " ch ");" .BI " int (*putm)(void *" out ", const char *" p ", size_t " sz ");" .BI " int (*nputf)(void *" out ", size_t " maxsz ", const char *" p ", ...);" .B "};" .BI "int gprintf(const struct gprintf_ops *" ops ", void *" out "," .ta \w'\fBint gprintf('u .BI " const char *" p ", ...);" .BI "int vgprintf(const struct gprintf_ops *" ops ", void *" out "," .ta \w'\fBint vgprintf('u .BI " const char *" p ", va_list *" ap ");" .BI "int gprintf_memputf(char **" buf_inout ", size_t *" sz_inout "," .ta \w'\fBint gprintf_memputf('u .BI " size_t " maxsz ", const char *" p ", va_list " ap ");" .B "const struct gprintf_ops file_printops;" .fi . .SH DESCRIPTION The .B "" header file declares facilities for generalized output formatting \(en i.e., .BR printf (3)-like formatting to arbitrary output sinks. This is the mechanism underlying the .BR dstr_putf (3) and .BR buf_putstrf...(3) functions. .PP To use it, you must define a .B "struct gprintf_ops" structure, providing functions to write the formatted output to your chosen sink. Each function receives a void pointer argument named .IR out , which is simply the .I out argument passed to .RB ( v ) gprintf , and should return the number of characters that it wrote \(en or at least some nonnegative value \(en on success, or \-1 if it encountered an error. .PP The three functions are: .hP \*o .BR putch : write out the single character .IR ch , which is an integer holding an .B "unsigned char" value, as used by .BR fputc (3). .hP \*o .BR putm : write out .I sz characters from the buffer starting at .IR p . .hP \*o .BR nputf : process the format string .I p and arguments .IR ap , writing out the formatted output; the output will not be longer than .I maxsz characters. .PP It may seem paradoxical for .B gprintf to require the backend to do string formatting, since its entire purpose is to do string formatting for you; but implementing the .B nputf function can typically be done straightforwardly enough by calling .BR snprintf (3) or similar. Difficult cases can be dealt with using .BR gprintf_memputf , described below. .PP The .B gprintf function formats a string .I p together with its variable argument list, using the provided output operations .IR ops , and passing them the pointer .I out when it calls on them. The .B vgprintf function is similar, except that it receives the format arguments as .I "a pointer to" a captured .B va_list argument tail. The argument tail is updated in place, and (on successful completion) is left referring to the first unused argument. .PP The .B gprintf_memputf function is a utility for implementing .B nputf operations. On entry, .BI * buf_inout should be a pointer to a buffer of .BI * sz_inout bytes, allocated from .BR arena_global (3); instead, .BI * buf_inout may be null if .BI * sz_inout is zero. The .I maxsz and .I p arguments are the maximum output size and format string passed to the .B nputf function, and .I ap is the format-argument list, captured using .BR va_start (3). The function will adjust the buffer pointer and size as necessary, write the formatted result to the buffer, null-terminated, and return the actual output length. The function is designed to be efficient when called multiple times, retaining the same buffer across calls, resizing it as necessary in a geometric progression. When the buffer is no longer wanted, free it using .BR xfree (3). .PP A typical .B nputf function using .B gprintf_memputf might look something like this. .VS .ta 2n struct my_output { /* output state */ char *buf; size_t sz; /* ...\& other members ...\& */ }; /* ...\& define putch and putm ...\& */ static int nputf(void *out, size_t maxsz, const char *p, ...) { struct my_output *myout = out; va_list ap; int n; va_start(ap, p); n = gprintf_memputf(&myout->buf, &myout->sz, maxsz, p, ap); va_end(ap); if (n > 0) n = putm(myout, myout->buf, n); return (n); } const struct gprintf_ops my_output_ops = { putch, putm, nputf }; /* ...\& */ struct my_output myout; myout.buf = 0; myout.sz = 0; /* ...\& other initialization ...\& */ gprintf(&my_output_ops, &myout, "Hello, %s!", "world"); xfree(myout.buf); myout.buf = 0; myout.sz = 0; /* ...\& other cleanup ...\& */ .VE . .SH "SEE ALSO" .BR buf (3), .BR dstr (3), .BR mLib (3). . .SH AUTHOR Mark Wooding,