c7f86522aa0831b0c740a715644ce2717cd17e24
[mLib] / utils / gprintf.3
1 .\" -*-nroff-*-
2 .de VS
3 .sp 1
4 .RS
5 .nf
6 .ft B
7 ..
8 .de VE
9 .ft R
10 .fi
11 .RE
12 .sp 1
13 ..
14 .de hP
15 .IP
16 .ft B
17 \h'-\w'\\$1\ 'u'\\$1\ \c
18 .ft P
19 ..
20 .ie t .ds o \(bu
21 .el .ds o o
22 .
23 .TH gprintf 3 "9 March 2024" "Straylight/Edgeware" "mLib utilities library"
24 .
25 .SH NAME
26 gprintf \- generalized output formatting
27 .
28 .SH SYNOPSIS
29 .nf
30 .B "#include <mLib/gprintf.h>"
31
32 .ta 2n
33 .B "struct gprintf_ops {"
34 .BI " int (*putch)(void *" out ", int " ch ");"
35 .BI " int (*putm)(void *" out ", const char *" p ", size_t " sz ");"
36 .BI " int (*nputf)(void *" out ", size_t " maxsz ", const char *" p ", ...);"
37 .B "};"
38
39 .BI "int gprintf(const struct gprintf_ops *" ops ", void *" out ","
40 .ta \w'\fBint gprintf('u
41 .BI " const char *" p ", ...);"
42 .BI "int vgprintf(const struct gprintf_ops *" ops ", void *" out ","
43 .ta \w'\fBint vgprintf('u
44 .BI " const char *" p ", va_list *" ap ");"
45
46 .BI "int gprintf_memputf(char **" buf_inout ", size_t *" sz_inout ","
47 .ta \w'\fBint gprintf_memputf('u
48 .BI " size_t " maxsz ", const char *" p ", va_list " ap ");"
49
50 .B "const struct gprintf_ops file_printops;"
51 .fi
52 .
53 .SH DESCRIPTION
54 The
55 .B "<mLib/gprintf.h>"
56 header file declares facilities for generalized output formatting
57 \(en i.e.,
58 .BR printf (3)-like
59 formatting to arbitrary output sinks.
60 This is the mechanism underlying the
61 .BR dstr_putf (3)
62 and
63 .BR buf_putstrf...(3)
64 functions.
65 .PP
66 To use it, you must define a
67 .B "struct gprintf_ops"
68 structure,
69 providing functions to write the formatted output to your chosen sink.
70 Each function receives a void pointer argument named
71 .IR out ,
72 which is simply the
73 .I out
74 argument passed to
75 .RB ( v ) gprintf ,
76 and should return the number of characters that it wrote
77 \(en or at least some nonnegative value \(en
78 on success,
79 or \-1 if it encountered an error.
80 .PP
81 The three functions are:
82 .hP \*o
83 .BR putch :
84 write out the single character
85 .IR ch ,
86 which is an integer holding an
87 .B "unsigned char"
88 value, as used by
89 .BR fputc (3).
90 .hP \*o
91 .BR putm :
92 write out
93 .I sz
94 characters from the buffer starting at
95 .IR p .
96 .hP \*o
97 .BR nputf :
98 process the format string
99 .I p
100 and arguments
101 .IR ap ,
102 writing out the formatted output;
103 the output will not be longer than
104 .I maxsz
105 characters.
106 .PP
107 It may seem paradoxical for
108 .B gprintf
109 to require the backend to do string formatting,
110 since its entire purpose is to do string formatting for you;
111 but implementing the
112 .B nputf
113 function can typically be done straightforwardly enough by calling
114 .BR snprintf (3)
115 or similar.
116 Difficult cases can be dealt with using
117 .BR gprintf_memputf ,
118 described below.
119 .PP
120 The
121 .B gprintf
122 function formats a string
123 .I p
124 together with its variable argument list,
125 using the provided output operations
126 .IR ops ,
127 and passing them the pointer
128 .I out
129 when it calls on them.
130 The
131 .B vgprintf
132 function is similar,
133 except that it receives the format arguments as
134 .I "a pointer to"
135 a captured
136 .B va_list
137 argument tail.
138 The argument tail is updated in place,
139 and (on successful completion)
140 is left referring to the first unused argument.
141 .PP
142 The
143 .B gprintf_memputf
144 function is a utility for implementing
145 .B nputf
146 operations.
147 On entry,
148 .BI * buf_inout
149 should be a pointer to a buffer of
150 .BI * sz_inout
151 bytes, allocated from
152 .BR arena_global (3);
153 instead,
154 .BI * buf_inout
155 may be null
156 if
157 .BI * sz_inout
158 is zero.
159 The
160 .I maxsz
161 and
162 .I p
163 arguments are the maximum output size and format string passed to the
164 .B nputf
165 function,
166 and
167 .I ap
168 is the format-argument list, captured using
169 .BR va_start (3).
170 The function will adjust the buffer pointer and size as necessary,
171 write the formatted result to the buffer, null-terminated,
172 and return the actual output length.
173 The function is designed to be efficient when called multiple times,
174 retaining the same buffer across calls,
175 resizing it as necessary in a geometric progression.
176 When the buffer is no longer wanted, free it using
177 .BR xfree (3).
178 .PP
179 A typical
180 .B nputf
181 function using
182 .B gprintf_memputf
183 might look something like this.
184 .VS
185 .ta 2n
186 struct my_output {
187 /* output state */
188 char *buf;
189 size_t sz;
190 /* ...\& other members ...\& */
191 };
192
193 /* ...\& define putch and putm ...\& */
194
195 static int nputf(void *out, size_t maxsz, const char *p, ...)
196 {
197 struct my_output *myout = out;
198 va_list ap;
199 int n;
200
201 va_start(ap, p);
202 n = gprintf_memputf(&myout->buf, &myout->sz, maxsz, p, ap);
203 va_end(ap);
204 if (n > 0) n = putm(myout, myout->buf, n);
205 return (n);
206 }
207
208 const struct gprintf_ops my_output_ops = { putch, putm, nputf };
209
210 /* ...\& */
211
212 struct my_output myout;
213
214 myout.buf = 0; myout.sz = 0;
215 /* ...\& other initialization ...\& */
216 gprintf(&my_output_ops, &myout, "Hello, %s!", "world");
217 xfree(myout.buf); myout.buf = 0; myout.sz = 0;
218 /* ...\& other cleanup ...\& */
219 .VE
220 .
221 .SH "SEE ALSO"
222 .BR buf (3),
223 .BR dstr (3),
224 .BR mLib (3).
225 .
226 .SH AUTHOR
227 Mark Wooding, <mdw@distorted.org.uk>