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 | .. | |
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> |