rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 1 | .TH FMTINSTALL 3 |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 2 | .SH NAME |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 3 | fmtinstall, dofmt, dorfmt, fmtprint, fmtvprint, fmtrune, fmtstrcpy, fmtrunestrcpy, fmtfdinit, fmtfdflush, fmtstrinit, fmtstrflush, runefmtstrinit, runefmtstrflush, errfmt \- support for user-defined print formats and output routines |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 4 | .SH SYNOPSIS |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 5 | .B #include <u.h> |
| 6 | .br |
| 7 | .B #include <libc.h> |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 8 | .PP |
| 9 | .ft L |
| 10 | .nf |
| 11 | .ta \w' 'u +\w' 'u +\w' 'u +\w' 'u +\w' 'u |
| 12 | typedef struct Fmt Fmt; |
| 13 | struct Fmt{ |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 14 | uchar runes; /* output buffer is runes or chars? */ |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 15 | void *start; /* of buffer */ |
| 16 | void *to; /* current place in the buffer */ |
| 17 | void *stop; /* end of the buffer; overwritten if flush fails */ |
| 18 | int (*flush)(Fmt*); /* called when to == stop */ |
| 19 | void *farg; /* to make flush a closure */ |
| 20 | int nfmt; /* num chars formatted so far */ |
| 21 | va_list args; /* args passed to dofmt */ |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 22 | int r; /* % format Rune */ |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 23 | int width; |
| 24 | int prec; |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 25 | ulong flags; |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 26 | }; |
| 27 | |
| 28 | enum{ |
| 29 | FmtWidth = 1, |
| 30 | FmtLeft = FmtWidth << 1, |
| 31 | FmtPrec = FmtLeft << 1, |
| 32 | FmtSharp = FmtPrec << 1, |
| 33 | FmtSpace = FmtSharp << 1, |
| 34 | FmtSign = FmtSpace << 1, |
| 35 | FmtZero = FmtSign << 1, |
| 36 | FmtUnsigned = FmtZero << 1, |
| 37 | FmtShort = FmtUnsigned << 1, |
| 38 | FmtLong = FmtShort << 1, |
| 39 | FmtVLong = FmtLong << 1, |
| 40 | FmtComma = FmtVLong << 1, |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 41 | |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 42 | FmtFlag = FmtComma << 1 |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 43 | }; |
| 44 | .fi |
| 45 | .PP |
| 46 | .B |
| 47 | .ta \w'\fLchar* 'u |
| 48 | |
| 49 | .PP |
| 50 | .B |
| 51 | int fmtfdinit(Fmt *f, int fd, char *buf, int nbuf); |
| 52 | .PP |
| 53 | .B |
| 54 | int fmtfdflush(Fmt *f); |
| 55 | .PP |
| 56 | .B |
| 57 | int fmtstrinit(Fmt *f); |
| 58 | .PP |
| 59 | .B |
| 60 | char* fmtstrflush(Fmt *f); |
| 61 | .PP |
| 62 | .B |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 63 | int runefmtstrinit(Fmt *f); |
| 64 | .PP |
| 65 | .B |
| 66 | Rune* runefmtstrflush(Fmt *f); |
| 67 | |
| 68 | .PP |
| 69 | .B |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 70 | int fmtinstall(int c, int (*fn)(Fmt*)); |
| 71 | .PP |
| 72 | .B |
| 73 | int dofmt(Fmt *f, char *fmt); |
| 74 | .PP |
| 75 | .B |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 76 | int dorfmt(Fmt*, Rune *fmt); |
| 77 | .PP |
| 78 | .B |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 79 | int fmtprint(Fmt *f, char *fmt, ...); |
| 80 | .PP |
| 81 | .B |
| 82 | int fmtvprint(Fmt *f, char *fmt, va_list v); |
| 83 | .PP |
| 84 | .B |
| 85 | int fmtrune(Fmt *f, int r); |
| 86 | .PP |
| 87 | .B |
| 88 | int fmtstrcpy(Fmt *f, char *s); |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 89 | .PP |
| 90 | .B |
| 91 | int fmtrunestrcpy(Fmt *f, Rune *s); |
| 92 | .PP |
| 93 | .B |
| 94 | int errfmt(Fmt *f); |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 95 | .SH DESCRIPTION |
| 96 | The interface described here allows the construction of custom |
rsc | bf8a59f | 2004-04-11 03:42:27 +0000 | [diff] [blame] | 97 | .IR print (3) |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 98 | verbs and output routines. |
| 99 | In essence, they provide access to the workings of the formatted print code. |
| 100 | .PP |
| 101 | The |
rsc | bf8a59f | 2004-04-11 03:42:27 +0000 | [diff] [blame] | 102 | .IR print (3) |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 103 | suite maintains its state with a data structure called |
| 104 | .BR Fmt . |
| 105 | A typical call to |
rsc | bf8a59f | 2004-04-11 03:42:27 +0000 | [diff] [blame] | 106 | .IR print (3) |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 107 | or its relatives initializes a |
| 108 | .B Fmt |
| 109 | structure, passes it to subsidiary routines to process the output, |
| 110 | and finishes by emitting any saved state recorded in the |
| 111 | .BR Fmt . |
| 112 | The details of the |
| 113 | .B Fmt |
| 114 | are unimportant to outside users, except insofar as the general |
| 115 | design influences the interface. |
| 116 | The |
| 117 | .B Fmt |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 118 | records whether the output is in runes or bytes, |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 119 | the verb being processed, its precision and width, |
| 120 | and buffering parameters. |
| 121 | Most important, it also records a |
| 122 | .I flush |
| 123 | routine that the library will call if a buffer overflows. |
| 124 | When printing to a file descriptor, the flush routine will |
| 125 | emit saved characters and reset the buffer; when printing |
| 126 | to an allocated string, it will resize the string to receive more output. |
| 127 | The flush routine is nil when printing to fixed-size buffers. |
| 128 | User code need never provide a flush routine; this is done internally |
| 129 | by the library. |
| 130 | .SS Custom output routines |
| 131 | To write a custom output routine, such as an error handler that |
| 132 | formats and prints custom error messages, the output sequence can be run |
| 133 | from outside the library using the routines described here. |
| 134 | There are two main cases: output to an open file descriptor |
| 135 | and output to a string. |
| 136 | .PP |
| 137 | To write to a file descriptor, call |
| 138 | .I fmtfdinit |
| 139 | to initialize the local |
| 140 | .B Fmt |
| 141 | structure |
| 142 | .IR f , |
| 143 | giving the file descriptor |
| 144 | .IR fd , |
| 145 | the buffer |
| 146 | .IR buf , |
| 147 | and its size |
| 148 | .IR nbuf . |
| 149 | Then call |
| 150 | .IR fmtprint |
| 151 | or |
| 152 | .IR fmtvprint |
| 153 | to generate the output. |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 154 | These behave like |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 155 | .B fprint |
| 156 | (see |
rsc | bf8a59f | 2004-04-11 03:42:27 +0000 | [diff] [blame] | 157 | .IR print (3)) |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 158 | or |
| 159 | .B vfprint |
| 160 | except that the characters are buffered until |
| 161 | .I fmtfdflush |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 162 | is called and the return value is either 0 or \-1. |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 163 | A typical example of this sequence appears in the Examples section. |
| 164 | .PP |
| 165 | The same basic sequence applies when outputting to an allocated string: |
| 166 | call |
| 167 | .I fmtstrinit |
| 168 | to initialize the |
| 169 | .BR Fmt , |
| 170 | then call |
| 171 | .I fmtprint |
| 172 | and |
| 173 | .I fmtvprint |
| 174 | to generate the output. |
| 175 | Finally, |
| 176 | .I fmtstrflush |
| 177 | will return the allocated string, which should be freed after use. |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 178 | To output to a rune string, use |
| 179 | .I runefmtstrinit |
| 180 | and |
| 181 | .IR runefmtstrflush . |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 182 | Regardless of the output style or type, |
| 183 | .I fmtprint |
| 184 | or |
| 185 | .I fmtvprint |
| 186 | generates the characters. |
| 187 | .SS Custom format verbs |
| 188 | .I Fmtinstall |
| 189 | is used to install custom verbs and flags labeled by character |
| 190 | .IR c , |
| 191 | which may be any non-zero Unicode character. |
| 192 | .I Fn |
| 193 | should be declared as |
| 194 | .IP |
| 195 | .EX |
| 196 | int fn(Fmt*) |
| 197 | .EE |
| 198 | .PP |
| 199 | .IB Fp ->r |
| 200 | is the flag or verb character to cause |
| 201 | .I fn |
| 202 | to be called. |
| 203 | In |
| 204 | .IR fn , |
| 205 | .IB fp ->width , |
| 206 | .IB fp ->prec |
| 207 | are the width and precision, and |
| 208 | .IB fp ->flags |
| 209 | the decoded flags for the verb (see |
rsc | bf8a59f | 2004-04-11 03:42:27 +0000 | [diff] [blame] | 210 | .IR print (3) |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 211 | for a description of these items). |
| 212 | The standard flag values are: |
| 213 | .B FmtSign |
| 214 | .RB ( + ), |
| 215 | .B FmtLeft |
| 216 | .RB ( - ), |
| 217 | .B FmtSpace |
| 218 | .RB ( '\ ' ), |
| 219 | .B FmtSharp |
| 220 | .RB ( # ), |
| 221 | .B FmtComma |
| 222 | .RB ( , ), |
| 223 | .B FmtLong |
| 224 | .RB ( l ), |
| 225 | .B FmtShort |
| 226 | .RB ( h ), |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 227 | .B FmtUnsigned |
| 228 | .RB ( u ), |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 229 | and |
| 230 | .B FmtVLong |
| 231 | .RB ( ll ). |
| 232 | The flag bits |
| 233 | .B FmtWidth |
| 234 | and |
| 235 | .B FmtPrec |
| 236 | identify whether a width and precision were specified. |
| 237 | .PP |
| 238 | .I Fn |
| 239 | is passed a pointer to the |
| 240 | .B Fmt |
| 241 | structure recording the state of the output. |
| 242 | If |
| 243 | .IB fp ->r |
| 244 | is a verb (rather than a flag), |
| 245 | .I fn |
| 246 | should use |
| 247 | .B Fmt->args |
| 248 | to fetch its argument from the list, |
| 249 | then format it, and return zero. |
| 250 | If |
| 251 | .IB fp ->r |
| 252 | is a flag, |
| 253 | .I fn |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 254 | should return one. |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 255 | All interpretation of |
| 256 | .IB fp ->width\f1, |
| 257 | .IB fp ->prec\f1, |
| 258 | and |
| 259 | .IB fp-> flags |
| 260 | is left up to the conversion routine. |
| 261 | .I Fmtinstall |
| 262 | returns 0 if the installation succeeds, \-1 if it fails. |
| 263 | .PP |
| 264 | .IR Fmtprint |
| 265 | and |
| 266 | .IR fmtvprint |
| 267 | may be called to |
| 268 | help prepare output in custom conversion routines. |
| 269 | However, these functions clear the width, precision, and flags. |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 270 | Both functions return 0 for success and \-1 for failure. |
| 271 | .PP |
| 272 | The functions |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 273 | .I dofmt |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 274 | and |
| 275 | .I dorfmt |
| 276 | are the underlying formatters; they |
| 277 | use the existing contents of |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 278 | .B Fmt |
| 279 | and should be called only by sophisticated conversion routines. |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 280 | These routines return the number of characters (bytes of UTF or runes) |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 281 | produced. |
| 282 | .PP |
| 283 | Some internal functions may be useful to format primitive types. |
| 284 | They honor the width, precision and flags as described in |
rsc | bf8a59f | 2004-04-11 03:42:27 +0000 | [diff] [blame] | 285 | .IR print (3). |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 286 | .I Fmtrune |
| 287 | formats a single character |
| 288 | .BR r . |
| 289 | .I Fmtstrcpy |
| 290 | formats a string |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 291 | .BR s ; |
| 292 | .I fmtrunestrcpy |
| 293 | formats a rune string |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 294 | .BR s . |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 295 | .I Errfmt |
| 296 | formats the system error string. |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 297 | All these routines return zero for successful execution. |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 298 | Conversion routines that call these functions will work properly |
| 299 | regardless of whether the output is bytes or runes. |
rsc | 058b011 | 2005-01-03 06:40:20 +0000 | [diff] [blame] | 300 | .\" .PP |
| 301 | .\" .IR 2c (1) |
| 302 | .\" describes the C directive |
| 303 | .\" .B #pragma |
| 304 | .\" .B varargck |
| 305 | .\" that can be used to provide type-checking for custom print verbs and output routines. |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 306 | .SH EXAMPLES |
| 307 | This function prints an error message with a variable |
| 308 | number of arguments and then quits. |
| 309 | Compared to the corresponding example in |
rsc | bf8a59f | 2004-04-11 03:42:27 +0000 | [diff] [blame] | 310 | .IR print (3), |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 311 | this version uses a smaller buffer, will never truncate |
| 312 | the output message, but might generate multiple |
| 313 | .B write |
| 314 | system calls to produce its output. |
| 315 | .IP |
| 316 | .EX |
| 317 | .ta 6n +6n +6n +6n +6n +6n +6n +6n +6n |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 318 | #pragma varargck argpos error 1 |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 319 | |
| 320 | void fatal(char *fmt, ...) |
| 321 | { |
| 322 | Fmt f; |
| 323 | char buf[64]; |
| 324 | va_list arg; |
| 325 | |
| 326 | fmtfdinit(&f, 1, buf, sizeof buf); |
| 327 | fmtprint(&f, "fatal: "); |
| 328 | va_start(arg, fmt); |
| 329 | fmtvprint(&f, fmt, arg); |
| 330 | va_end(arg); |
| 331 | fmtprint(&f, "\en"); |
| 332 | fmtfdflush(&f); |
| 333 | exits("fatal error"); |
| 334 | } |
| 335 | .EE |
| 336 | .PP |
| 337 | This example adds a verb to print complex numbers. |
| 338 | .IP |
| 339 | .EX |
| 340 | typedef |
| 341 | struct { |
| 342 | double r, i; |
| 343 | } Complex; |
| 344 | |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 345 | #pragma varargck type "X" Complex |
| 346 | |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 347 | int |
| 348 | Xfmt(Fmt *f) |
| 349 | { |
| 350 | Complex c; |
| 351 | |
| 352 | c = va_arg(f->args, Complex); |
| 353 | return fmtprint(f, "(%g,%g)", c.r, c.i); |
| 354 | } |
| 355 | |
| 356 | main(...) |
| 357 | { |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 358 | Complex x = (Complex){ 1.5, -2.3 }; |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 359 | |
| 360 | fmtinstall('X', Xfmt); |
| 361 | print("x = %X\en", x); |
| 362 | } |
| 363 | .EE |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 364 | .SH SOURCE |
rsc | c3674de | 2005-01-11 17:37:33 +0000 | [diff] [blame] | 365 | .B \*9/src/lib9/fmt |
rsc | b2cfc4e | 2003-09-30 17:47:41 +0000 | [diff] [blame] | 366 | .SH SEE ALSO |
rsc | bf8a59f | 2004-04-11 03:42:27 +0000 | [diff] [blame] | 367 | .IR print (3), |
rsc | 058b011 | 2005-01-03 06:40:20 +0000 | [diff] [blame] | 368 | .IR utf (7), |
rsc | bf8a59f | 2004-04-11 03:42:27 +0000 | [diff] [blame] | 369 | .IR errstr (3) |
rsc | cfa37a7 | 2004-04-10 18:53:55 +0000 | [diff] [blame] | 370 | .SH DIAGNOSTICS |
| 371 | These routines return negative numbers or nil for errors and set |
| 372 | .IR errstr . |