Commit | Line | Data |
---|---|---|
adec5584 MW |
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 | .. | |
d056fbdf MW |
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 | \} | |
adec5584 MW |
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>" | |
d056fbdf | 41 | .PP |
adec5584 MW |
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 "};" | |
d056fbdf | 48 | .PP |
adec5584 MW |
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 ");" | |
d056fbdf | 55 | .PP |
adec5584 MW |
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 ");" | |
d056fbdf | 59 | .PP |
adec5584 MW |
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 | }; | |
d056fbdf | 202 | .VP |
adec5584 | 203 | /* ...\& define putch and putm ...\& */ |
d056fbdf | 204 | .VP |
adec5584 MW |
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; | |
d056fbdf | 210 | .VP |
adec5584 MW |
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 | } | |
d056fbdf | 217 | .VP |
adec5584 | 218 | const struct gprintf_ops my_output_ops = { putch, putm, nputf }; |
d056fbdf | 219 | .VP |
adec5584 | 220 | /* ...\& */ |
d056fbdf | 221 | .VP |
adec5584 | 222 | struct my_output myout; |
d056fbdf | 223 | .VP |
adec5584 MW |
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> |