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