Commit | Line | Data |
---|---|---|
adec5584 | 1 | .\" -*-nroff-*- |
c4ccbbf9 MW |
2 | .\" |
3 | .\" Manual for generalized output formatting | |
4 | .\" | |
5 | .\" (c) 2024 Straylight/Edgeware | |
6 | .\" | |
7 | . | |
8 | .\"----- Licensing notice --------------------------------------------------- | |
9 | .\" | |
10 | .\" This file is part of the mLib utilities library. | |
11 | .\" | |
12 | .\" mLib is free software: you can redistribute it and/or modify it under | |
13 | .\" the terms of the GNU Library General Public License as published by | |
14 | .\" the Free Software Foundation; either version 2 of the License, or (at | |
15 | .\" your option) any later version. | |
16 | .\" | |
17 | .\" mLib is distributed in the hope that it will be useful, but WITHOUT | |
18 | .\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
19 | .\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | |
20 | .\" License for more details. | |
21 | .\" | |
22 | .\" You should have received a copy of the GNU Library General Public | |
23 | .\" License along with mLib. If not, write to the Free Software | |
24 | .\" Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |
25 | .\" USA. | |
26 | . | |
27 | .\"-------------------------------------------------------------------------- | |
28 | .so ../defs.man \" @@@PRE@@@ | |
adec5584 | 29 | . |
c4ccbbf9 MW |
30 | .\"-------------------------------------------------------------------------- |
31 | .TH gprintf 3mLib "9 March 2024" "Straylight/Edgeware" "mLib utilities library" | |
32 | .\" @gprintf | |
33 | .\" @vgprintf | |
34 | .\" @gprintf_memputf | |
adec5584 | 35 | . |
c4ccbbf9 MW |
36 | .\" @file_printops |
37 | . | |
38 | .\"-------------------------------------------------------------------------- | |
adec5584 MW |
39 | .SH NAME |
40 | gprintf \- generalized output formatting | |
41 | . | |
c4ccbbf9 | 42 | .\"-------------------------------------------------------------------------- |
adec5584 | 43 | .SH SYNOPSIS |
c4ccbbf9 | 44 | . |
adec5584 MW |
45 | .nf |
46 | .B "#include <mLib/gprintf.h>" | |
d056fbdf | 47 | .PP |
adec5584 MW |
48 | .ta 2n |
49 | .B "struct gprintf_ops {" | |
50 | .BI " int (*putch)(void *" out ", int " ch ");" | |
51 | .BI " int (*putm)(void *" out ", const char *" p ", size_t " sz ");" | |
52 | .BI " int (*nputf)(void *" out ", size_t " maxsz ", const char *" p ", ...);" | |
53 | .B "};" | |
d056fbdf | 54 | .PP |
adec5584 MW |
55 | .BI "int gprintf(const struct gprintf_ops *" ops ", void *" out "," |
56 | .ta \w'\fBint gprintf('u | |
57 | .BI " const char *" p ", ...);" | |
58 | .BI "int vgprintf(const struct gprintf_ops *" ops ", void *" out "," | |
59 | .ta \w'\fBint vgprintf('u | |
60 | .BI " const char *" p ", va_list *" ap ");" | |
d056fbdf | 61 | .PP |
adec5584 MW |
62 | .BI "int gprintf_memputf(char **" buf_inout ", size_t *" sz_inout "," |
63 | .ta \w'\fBint gprintf_memputf('u | |
64 | .BI " size_t " maxsz ", const char *" p ", va_list " ap ");" | |
d056fbdf | 65 | .PP |
adec5584 MW |
66 | .B "const struct gprintf_ops file_printops;" |
67 | .fi | |
68 | . | |
c4ccbbf9 | 69 | .\"-------------------------------------------------------------------------- |
adec5584 | 70 | .SH DESCRIPTION |
c4ccbbf9 | 71 | . |
adec5584 MW |
72 | The |
73 | .B "<mLib/gprintf.h>" | |
74 | header file declares facilities for generalized output formatting | |
75 | \(en i.e., | |
76 | .BR printf (3)-like | |
77 | formatting to arbitrary output sinks. | |
78 | This is the mechanism underlying the | |
79 | .BR dstr_putf (3) | |
80 | and | |
81 | .BR buf_putstrf...(3) | |
82 | functions. | |
83 | .PP | |
c4ccbbf9 MW |
84 | The formatting is intended to be convenient and safe |
85 | rather than efficient, | |
86 | so don't expect blistering performance. | |
87 | Similarly, there may be differences | |
88 | between the formatting done by | |
89 | .B gprintf | |
90 | and the C ilbrary's | |
91 | .BR sprintf (3) | |
92 | because the former has to do most of its work itself. | |
93 | In particular, | |
94 | .B gprintf | |
95 | understands the POSIX | |
96 | .RB ` n$ ' | |
97 | positional parameter notation accepted by many Unix C libraries, | |
98 | even if the underlying C library does not. | |
99 | .PP | |
adec5584 MW |
100 | To use it, you must define a |
101 | .B "struct gprintf_ops" | |
102 | structure, | |
103 | providing functions to write the formatted output to your chosen sink. | |
104 | Each function receives a void pointer argument named | |
105 | .IR out , | |
106 | which is simply the | |
107 | .I out | |
108 | argument passed to | |
109 | .RB ( v ) gprintf , | |
110 | and should return the number of characters that it wrote | |
111 | \(en or at least some nonnegative value \(en | |
112 | on success, | |
113 | or \-1 if it encountered an error. | |
114 | .PP | |
115 | The three functions are: | |
116 | .hP \*o | |
117 | .BR putch : | |
118 | write out the single character | |
119 | .IR ch , | |
120 | which is an integer holding an | |
121 | .B "unsigned char" | |
122 | value, as used by | |
123 | .BR fputc (3). | |
124 | .hP \*o | |
125 | .BR putm : | |
126 | write out | |
127 | .I sz | |
128 | characters from the buffer starting at | |
129 | .IR p . | |
130 | .hP \*o | |
131 | .BR nputf : | |
132 | process the format string | |
133 | .I p | |
134 | and arguments | |
135 | .IR ap , | |
136 | writing out the formatted output; | |
137 | the output will not be longer than | |
138 | .I maxsz | |
139 | characters. | |
140 | .PP | |
141 | It may seem paradoxical for | |
142 | .B gprintf | |
143 | to require the backend to do string formatting, | |
144 | since its entire purpose is to do string formatting for you; | |
145 | but implementing the | |
146 | .B nputf | |
147 | function can typically be done straightforwardly enough by calling | |
148 | .BR snprintf (3) | |
149 | or similar. | |
150 | Difficult cases can be dealt with using | |
151 | .BR gprintf_memputf , | |
152 | described below. | |
153 | .PP | |
154 | The | |
155 | .B gprintf | |
156 | function formats a string | |
157 | .I p | |
158 | together with its variable argument list, | |
159 | using the provided output operations | |
160 | .IR ops , | |
161 | and passing them the pointer | |
162 | .I out | |
163 | when it calls on them. | |
164 | The | |
165 | .B vgprintf | |
166 | function is similar, | |
167 | except that it receives the format arguments as | |
168 | .I "a pointer to" | |
169 | a captured | |
170 | .B va_list | |
171 | argument tail. | |
172 | The argument tail is updated in place, | |
173 | and (on successful completion) | |
174 | is left referring to the first unused argument. | |
175 | .PP | |
176 | The | |
177 | .B gprintf_memputf | |
178 | function is a utility for implementing | |
179 | .B nputf | |
180 | operations. | |
181 | On entry, | |
c752173d MW |
182 | .I a |
183 | should be a pointer to an arena, | |
184 | typically | |
185 | .BR arena_global (3); | |
adec5584 MW |
186 | .BI * buf_inout |
187 | should be a pointer to a buffer of | |
188 | .BI * sz_inout | |
c752173d MW |
189 | bytes, allocated from the arena |
190 | .IR a ; | |
adec5584 MW |
191 | instead, |
192 | .BI * buf_inout | |
193 | may be null | |
194 | if | |
195 | .BI * sz_inout | |
196 | is zero. | |
197 | The | |
198 | .I maxsz | |
199 | and | |
200 | .I p | |
201 | arguments are the maximum output size and format string passed to the | |
202 | .B nputf | |
203 | function, | |
204 | and | |
205 | .I ap | |
206 | is the format-argument list, captured using | |
207 | .BR va_start (3). | |
208 | The function will adjust the buffer pointer and size as necessary, | |
209 | write the formatted result to the buffer, null-terminated, | |
210 | and return the actual output length. | |
211 | The function is designed to be efficient when called multiple times, | |
212 | retaining the same buffer across calls, | |
213 | resizing it as necessary in a geometric progression. | |
adec5584 MW |
214 | .PP |
215 | A typical | |
216 | .B nputf | |
217 | function using | |
218 | .B gprintf_memputf | |
219 | might look something like this. | |
220 | .VS | |
221 | .ta 2n | |
222 | struct my_output { | |
223 | /* output state */ | |
224 | char *buf; | |
225 | size_t sz; | |
226 | /* ...\& other members ...\& */ | |
227 | }; | |
d056fbdf | 228 | .VP |
adec5584 | 229 | /* ...\& define putch and putm ...\& */ |
d056fbdf | 230 | .VP |
adec5584 MW |
231 | static int nputf(void *out, size_t maxsz, const char *p, ...) |
232 | { | |
233 | struct my_output *myout = out; | |
234 | va_list ap; | |
235 | int n; | |
d056fbdf | 236 | .VP |
adec5584 MW |
237 | va_start(ap, p); |
238 | n = gprintf_memputf(&myout->buf, &myout->sz, maxsz, p, ap); | |
239 | va_end(ap); | |
240 | if (n > 0) n = putm(myout, myout->buf, n); | |
241 | return (n); | |
242 | } | |
d056fbdf | 243 | .VP |
adec5584 | 244 | const struct gprintf_ops my_output_ops = { putch, putm, nputf }; |
d056fbdf | 245 | .VP |
adec5584 | 246 | /* ...\& */ |
d056fbdf | 247 | .VP |
adec5584 | 248 | struct my_output myout; |
d056fbdf | 249 | .VP |
adec5584 MW |
250 | myout.buf = 0; myout.sz = 0; |
251 | /* ...\& other initialization ...\& */ | |
252 | gprintf(&my_output_ops, &myout, "Hello, %s!", "world"); | |
253 | xfree(myout.buf); myout.buf = 0; myout.sz = 0; | |
254 | /* ...\& other cleanup ...\& */ | |
255 | .VE | |
256 | . | |
c4ccbbf9 | 257 | .\"-------------------------------------------------------------------------- |
adec5584 | 258 | .SH "SEE ALSO" |
c4ccbbf9 | 259 | . |
adec5584 MW |
260 | .BR buf (3), |
261 | .BR dstr (3), | |
262 | .BR mLib (3). | |
263 | . | |
c4ccbbf9 | 264 | .\"-------------------------------------------------------------------------- |
adec5584 | 265 | .SH AUTHOR |
c4ccbbf9 MW |
266 | . |
267 | .\"-------------------------------------------------------------------------- | |
adec5584 | 268 | Mark Wooding, <mdw@distorted.org.uk> |
c4ccbbf9 MW |
269 | . |
270 | .\"----- That's all, folks -------------------------------------------------- |