1 /*
2 * The authors of this software are Rob Pike and Ken Thompson.
3 * Copyright (c) 2002 by Lucent Technologies.
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose without fee is hereby granted, provided that this entire notice
6 * is included in all copies of any software which is or includes a copy
7 * or modification of this software and in all copies of the supporting
8 * documentation for such software.
9 * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
10 * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
11 * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
12 * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
13 */
14 #include "lib9.h"
15 #include "fmtdef.h"
16
17 /* format the output into f->to and return the number of characters fmted */
18 int
dofmt(Fmt * f,char * fmt)19 dofmt(Fmt *f, char *fmt)
20 {
21 Rune rune, *rt, *rs;
22 int r;
23 char *t, *s;
24 int n, nfmt;
25
26 nfmt = f->nfmt;
27 for(;;){
28 if(f->runes){
29 rt = f->to;
30 rs = f->stop;
31 while((r = *(uchar*)fmt) && r != '%'){
32 if(r < Runeself)
33 fmt++;
34 else{
35 fmt += chartorune(&rune, fmt);
36 r = rune;
37 }
38 FMTRCHAR(f, rt, rs, r);
39 }
40 fmt++;
41 f->nfmt += rt - (Rune *)f->to;
42 f->to = rt;
43 if(!r)
44 return f->nfmt - nfmt;
45 f->stop = rs;
46 }else{
47 t = f->to;
48 s = f->stop;
49 while((r = *(uchar*)fmt) && r != '%'){
50 if(r < Runeself){
51 FMTCHAR(f, t, s, r);
52 fmt++;
53 }else{
54 n = chartorune(&rune, fmt);
55 if(t + n > s){
56 t = _fmtflush(f, t, n);
57 if(t != nil)
58 s = f->stop;
59 else
60 return -1;
61 }
62 while(n--)
63 *t++ = *fmt++;
64 }
65 }
66 fmt++;
67 f->nfmt += t - (char *)f->to;
68 f->to = t;
69 if(!r)
70 return f->nfmt - nfmt;
71 f->stop = s;
72 }
73
74 fmt = _fmtdispatch(f, fmt, 0);
75 if(fmt == nil)
76 return -1;
77 }
78 }
79
80 void *
_fmtflush(Fmt * f,void * t,int len)81 _fmtflush(Fmt *f, void *t, int len)
82 {
83 if(f->runes)
84 f->nfmt += (Rune*)t - (Rune*)f->to;
85 else
86 f->nfmt += (char*)t - (char *)f->to;
87 f->to = t;
88 if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
89 f->stop = f->to;
90 return nil;
91 }
92 return f->to;
93 }
94
95 /*
96 * put a formatted block of memory sz bytes long of n runes into the output buffer,
97 * left/right justified in a field of at least f->width charactes
98 */
99 int
_fmtpad(Fmt * f,int n)100 _fmtpad(Fmt *f, int n)
101 {
102 char *t, *s;
103 int i;
104
105 t = f->to;
106 s = f->stop;
107 for(i = 0; i < n; i++)
108 FMTCHAR(f, t, s, ' ');
109 f->nfmt += t - (char *)f->to;
110 f->to = t;
111 return 0;
112 }
113
114 int
_rfmtpad(Fmt * f,int n)115 _rfmtpad(Fmt *f, int n)
116 {
117 Rune *t, *s;
118 int i;
119
120 t = f->to;
121 s = f->stop;
122 for(i = 0; i < n; i++)
123 FMTRCHAR(f, t, s, ' ');
124 f->nfmt += t - (Rune *)f->to;
125 f->to = t;
126 return 0;
127 }
128
129 int
_fmtcpy(Fmt * f,void * vm,int n,int sz)130 _fmtcpy(Fmt *f, void *vm, int n, int sz)
131 {
132 Rune *rt, *rs, r;
133 char *t, *s, *m, *me;
134 ulong fl;
135 int nc, w;
136
137 m = vm;
138 me = m + sz;
139 w = f->width;
140 fl = f->flags;
141 if((fl & FmtPrec) && n > f->prec)
142 n = f->prec;
143 if(f->runes){
144 if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
145 return -1;
146 rt = f->to;
147 rs = f->stop;
148 for(nc = n; nc > 0; nc--){
149 r = *(uchar*)m;
150 if(r < Runeself)
151 m++;
152 else if((me - m) >= UTFmax || fullrune(m, me-m))
153 m += chartorune(&r, m);
154 else
155 break;
156 FMTRCHAR(f, rt, rs, r);
157 }
158 f->nfmt += rt - (Rune *)f->to;
159 f->to = rt;
160 if(m < me)
161 return -1;
162 if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
163 return -1;
164 }else{
165 if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
166 return -1;
167 t = f->to;
168 s = f->stop;
169 for(nc = n; nc > 0; nc--){
170 r = *(uchar*)m;
171 if(r < Runeself)
172 m++;
173 else if((me - m) >= UTFmax || fullrune(m, me-m))
174 m += chartorune(&r, m);
175 else
176 break;
177 FMTRUNE(f, t, s, r);
178 }
179 f->nfmt += t - (char *)f->to;
180 f->to = t;
181 if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
182 return -1;
183 }
184 return 0;
185 }
186
187 int
_fmtrcpy(Fmt * f,void * vm,int n)188 _fmtrcpy(Fmt *f, void *vm, int n)
189 {
190 Rune r, *m, *me, *rt, *rs;
191 char *t, *s;
192 ulong fl;
193 int w;
194
195 m = vm;
196 w = f->width;
197 fl = f->flags;
198 if((fl & FmtPrec) && n > f->prec)
199 n = f->prec;
200 if(f->runes){
201 if(!(fl & FmtLeft) && _rfmtpad(f, w - n) < 0)
202 return -1;
203 rt = f->to;
204 rs = f->stop;
205 for(me = m + n; m < me; m++)
206 FMTRCHAR(f, rt, rs, *m);
207 f->nfmt += rt - (Rune *)f->to;
208 f->to = rt;
209 if(fl & FmtLeft && _rfmtpad(f, w - n) < 0)
210 return -1;
211 }else{
212 if(!(fl & FmtLeft) && _fmtpad(f, w - n) < 0)
213 return -1;
214 t = f->to;
215 s = f->stop;
216 for(me = m + n; m < me; m++){
217 r = *m;
218 FMTRUNE(f, t, s, r);
219 }
220 f->nfmt += t - (char *)f->to;
221 f->to = t;
222 if(fl & FmtLeft && _fmtpad(f, w - n) < 0)
223 return -1;
224 }
225 return 0;
226 }
227
228 /* fmt out one character */
229 int
_charfmt(Fmt * f)230 _charfmt(Fmt *f)
231 {
232 char x[1];
233
234 x[0] = va_arg(f->args, int);
235 f->prec = 1;
236 return _fmtcpy(f, x, 1, 1);
237 }
238
239 /* fmt out one rune */
240 int
_runefmt(Fmt * f)241 _runefmt(Fmt *f)
242 {
243 Rune x[1];
244
245 x[0] = va_arg(f->args, int);
246 return _fmtrcpy(f, x, 1);
247 }
248
249 /* public helper routine: fmt out a null terminated string already in hand */
250 int
fmtstrcpy(Fmt * f,char * s)251 fmtstrcpy(Fmt *f, char *s)
252 {
253 int p, i;
254 if(!s)
255 return _fmtcpy(f, "<nil>", 5, 5);
256 /* if precision is specified, make sure we don't wander off the end */
257 if(f->flags & FmtPrec){
258 p = f->prec;
259 for(i = 0; i < p; i++)
260 if(s[i] == 0)
261 break;
262 return _fmtcpy(f, s, utfnlen(s, i), i); /* BUG?: won't print a partial rune at end */
263 }
264
265 return _fmtcpy(f, s, utflen(s), strlen(s));
266 }
267
268 /* fmt out a null terminated utf string */
269 int
_strfmt(Fmt * f)270 _strfmt(Fmt *f)
271 {
272 char *s;
273
274 s = va_arg(f->args, char *);
275 return fmtstrcpy(f, s);
276 }
277
278 /* public helper routine: fmt out a null terminated rune string already in hand */
279 int
fmtrunestrcpy(Fmt * f,Rune * s)280 fmtrunestrcpy(Fmt *f, Rune *s)
281 {
282 Rune *e;
283 int n, p;
284
285 if(!s)
286 return _fmtcpy(f, "<nil>", 5, 5);
287 /* if precision is specified, make sure we don't wander off the end */
288 if(f->flags & FmtPrec){
289 p = f->prec;
290 for(n = 0; n < p; n++)
291 if(s[n] == 0)
292 break;
293 }else{
294 for(e = s; *e; e++)
295 ;
296 n = e - s;
297 }
298 return _fmtrcpy(f, s, n);
299 }
300
301 /* fmt out a null terminated rune string */
302 int
_runesfmt(Fmt * f)303 _runesfmt(Fmt *f)
304 {
305 Rune *s;
306
307 s = va_arg(f->args, Rune *);
308 return fmtrunestrcpy(f, s);
309 }
310
311 /* fmt a % */
312 int
_percentfmt(Fmt * f)313 _percentfmt(Fmt *f)
314 {
315 Rune x[1];
316
317 x[0] = f->r;
318 f->prec = 1;
319 return _fmtrcpy(f, x, 1);
320 }
321
322 /* fmt an integer */
323 int
_ifmt(Fmt * f)324 _ifmt(Fmt *f)
325 {
326 char buf[70], *p, *conv;
327 uvlong vu;
328 ulong u;
329 int neg, base, i, n, fl, w, isv;
330
331 neg = 0;
332 fl = f->flags;
333 isv = 0;
334 vu = 0;
335 u = 0;
336 if(f->r == 'p'){
337 u = (ulong)va_arg(f->args, void*);
338 f->r = 'x';
339 fl |= FmtUnsigned;
340 }else if(fl & FmtVLong){
341 isv = 1;
342 if(fl & FmtUnsigned)
343 vu = va_arg(f->args, uvlong);
344 else
345 vu = va_arg(f->args, vlong);
346 }else if(fl & FmtLong){
347 if(fl & FmtUnsigned)
348 u = va_arg(f->args, ulong);
349 else
350 u = va_arg(f->args, long);
351 }else if(fl & FmtByte){
352 if(fl & FmtUnsigned)
353 u = (uchar)va_arg(f->args, int);
354 else
355 u = (char)va_arg(f->args, int);
356 }else if(fl & FmtShort){
357 if(fl & FmtUnsigned)
358 u = (ushort)va_arg(f->args, int);
359 else
360 u = (short)va_arg(f->args, int);
361 }else{
362 if(fl & FmtUnsigned)
363 u = va_arg(f->args, uint);
364 else
365 u = va_arg(f->args, int);
366 }
367 conv = "0123456789abcdef";
368 switch(f->r){
369 case 'd':
370 base = 10;
371 break;
372 case 'x':
373 base = 16;
374 break;
375 case 'X':
376 base = 16;
377 conv = "0123456789ABCDEF";
378 break;
379 case 'b':
380 base = 2;
381 break;
382 case 'o':
383 base = 8;
384 break;
385 default:
386 return -1;
387 }
388 if(!(fl & FmtUnsigned)){
389 if(isv && (vlong)vu < 0){
390 vu = -(vlong)vu;
391 neg = 1;
392 }else if(!isv && (long)u < 0){
393 u = -(long)u;
394 neg = 1;
395 }
396 }
397 p = buf + sizeof buf - 1;
398 n = 0;
399 if(isv){
400 while(vu){
401 i = vu % base;
402 vu /= base;
403 if((fl & FmtComma) && n % 4 == 3){
404 *p-- = ',';
405 n++;
406 }
407 *p-- = conv[i];
408 n++;
409 }
410 }else{
411 while(u){
412 i = u % base;
413 u /= base;
414 if((fl & FmtComma) && n % 4 == 3){
415 *p-- = ',';
416 n++;
417 }
418 *p-- = conv[i];
419 n++;
420 }
421 }
422 if(n == 0){
423 *p-- = '0';
424 n = 1;
425 }
426 for(w = f->prec; n < w && p > buf+3; n++)
427 *p-- = '0';
428 if(neg || (fl & (FmtSign|FmtSpace)))
429 n++;
430 if(fl & FmtSharp){
431 if(base == 16)
432 n += 2;
433 else if(base == 8){
434 if(p[1] == '0')
435 fl &= ~FmtSharp;
436 else
437 n++;
438 }
439 }
440 if((fl & FmtZero) && !(fl & FmtLeft)){
441 for(w = f->width; n < w && p > buf+3; n++)
442 *p-- = '0';
443 f->width = 0;
444 }
445 if(fl & FmtSharp){
446 if(base == 16)
447 *p-- = f->r;
448 if(base == 16 || base == 8)
449 *p-- = '0';
450 }
451 if(neg)
452 *p-- = '-';
453 else if(fl & FmtSign)
454 *p-- = '+';
455 else if(fl & FmtSpace)
456 *p-- = ' ';
457 f->flags &= ~FmtPrec;
458 return _fmtcpy(f, p + 1, n, n);
459 }
460
461 int
_countfmt(Fmt * f)462 _countfmt(Fmt *f)
463 {
464 void *p;
465 ulong fl;
466
467 fl = f->flags;
468 p = va_arg(f->args, void*);
469 if(fl & FmtVLong){
470 *(vlong*)p = f->nfmt;
471 }else if(fl & FmtLong){
472 *(long*)p = f->nfmt;
473 }else if(fl & FmtByte){
474 *(char*)p = f->nfmt;
475 }else if(fl & FmtShort){
476 *(short*)p = f->nfmt;
477 }else{
478 *(int*)p = f->nfmt;
479 }
480 return 0;
481 }
482
483 int
_flagfmt(Fmt * f)484 _flagfmt(Fmt *f)
485 {
486 switch(f->r){
487 case ',':
488 f->flags |= FmtComma;
489 break;
490 case '-':
491 f->flags |= FmtLeft;
492 break;
493 case '+':
494 f->flags |= FmtSign;
495 break;
496 case '#':
497 f->flags |= FmtSharp;
498 break;
499 case ' ':
500 f->flags |= FmtSpace;
501 break;
502 case 'u':
503 f->flags |= FmtUnsigned;
504 break;
505 case 'h':
506 if(f->flags & FmtShort)
507 f->flags |= FmtByte;
508 f->flags |= FmtShort;
509 break;
510 case 'l':
511 if(f->flags & FmtLong)
512 f->flags |= FmtVLong;
513 f->flags |= FmtLong;
514 break;
515 }
516 return 1;
517 }
518
519 /* default error format */
520 int
_badfmt(Fmt * f)521 _badfmt(Fmt *f)
522 {
523 char x[3];
524
525 x[0] = '%';
526 x[1] = f->r;
527 x[2] = '%';
528 f->prec = 3;
529 _fmtcpy(f, x, 3, 3);
530 return 0;
531 }
532